Browse Source

Merge branch 'master' of https://github.com/thingsboard/thingsboard into UITests_DeviseProfiles

pull/7897/head
Seraphym-Tuhai 4 years ago
parent
commit
39fa491daf
  1. 2
      application/pom.xml
  2. 2
      application/src/main/data/upgrade/3.4.1/schema_update.sql
  3. 11
      application/src/main/java/org/thingsboard/server/controller/ControllerConstants.java
  4. 19
      application/src/main/java/org/thingsboard/server/controller/TelemetryController.java
  5. 12
      application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/RuleChainsEdgeEventFetcher.java
  6. 3
      application/src/main/java/org/thingsboard/server/service/entitiy/edge/DefaultTbEdgeService.java
  7. 2
      application/src/main/java/org/thingsboard/server/service/session/DefaultDeviceSessionCacheService.java
  8. 14
      application/src/test/java/org/thingsboard/server/controller/BaseEdgeControllerTest.java
  9. 2
      common/actor/pom.xml
  10. 2
      common/cache/pom.xml
  11. 2
      common/cluster-api/pom.xml
  12. 2
      common/coap-server/pom.xml
  13. 2
      common/dao-api/pom.xml
  14. 2
      common/data/pom.xml
  15. 2
      common/edge-api/pom.xml
  16. 2
      common/message/pom.xml
  17. 2
      common/pom.xml
  18. 2
      common/queue/pom.xml
  19. 2
      common/script/pom.xml
  20. 2
      common/script/remote-js-client/pom.xml
  21. 2
      common/script/script-api/pom.xml
  22. 2
      common/stats/pom.xml
  23. 2
      common/transport/coap/pom.xml
  24. 2
      common/transport/http/pom.xml
  25. 2
      common/transport/lwm2m/pom.xml
  26. 2
      common/transport/mqtt/pom.xml
  27. 2
      common/transport/pom.xml
  28. 2
      common/transport/snmp/pom.xml
  29. 2
      common/transport/transport-api/pom.xml
  30. 2
      common/util/pom.xml
  31. 2
      common/version-control/pom.xml
  32. 2
      dao/pom.xml
  33. 9
      dao/src/main/java/org/thingsboard/server/dao/service/ConstraintValidator.java
  34. 2
      msa/black-box-tests/pom.xml
  35. 2
      msa/js-executor/package.json
  36. 2
      msa/js-executor/pom.xml
  37. 2
      msa/pom.xml
  38. 2
      msa/tb-node/pom.xml
  39. 2
      msa/tb/pom.xml
  40. 2
      msa/transport/coap/pom.xml
  41. 2
      msa/transport/http/pom.xml
  42. 2
      msa/transport/lwm2m/pom.xml
  43. 2
      msa/transport/mqtt/pom.xml
  44. 2
      msa/transport/pom.xml
  45. 2
      msa/transport/snmp/pom.xml
  46. 2
      msa/vc-executor-docker/pom.xml
  47. 2
      msa/vc-executor/pom.xml
  48. 2
      msa/web-ui/package.json
  49. 2
      msa/web-ui/pom.xml
  50. 4
      netty-mqtt/pom.xml
  51. 2
      pom.xml
  52. 2
      rest-client/pom.xml
  53. 2
      rule-engine/pom.xml
  54. 2
      rule-engine/rule-engine-api/pom.xml
  55. 2
      rule-engine/rule-engine-components/pom.xml
  56. 2
      tools/pom.xml
  57. 2
      transport/coap/pom.xml
  58. 2
      transport/http/pom.xml
  59. 2
      transport/lwm2m/pom.xml
  60. 2
      transport/mqtt/pom.xml
  61. 2
      transport/pom.xml
  62. 2
      transport/snmp/pom.xml
  63. 2
      ui-ngx/package.json
  64. 2
      ui-ngx/pom.xml
  65. 1
      ui-ngx/src/app/core/api/widget-subscription.ts
  66. 22
      ui-ngx/src/app/core/http/entity.service.ts
  67. 51
      ui-ngx/src/app/core/http/widget.service.ts
  68. 12
      ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.html
  69. 76
      ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.ts
  70. 1
      ui-ngx/src/app/modules/home/components/dashboard-page/layout/manage-dashboard-layouts-dialog.component.ts
  71. 53
      ui-ngx/src/app/modules/home/components/widget/widget-component.service.ts

2
application/pom.xml

@ -20,7 +20,7 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
<groupId>org.thingsboard</groupId> <groupId>org.thingsboard</groupId>
<version>3.4.3-SNAPSHOT</version> <version>3.4.4-SNAPSHOT</version>
<artifactId>thingsboard</artifactId> <artifactId>thingsboard</artifactId>
</parent> </parent>
<artifactId>application</artifactId> <artifactId>application</artifactId>

2
application/src/main/data/upgrade/3.4.1/schema_update.sql

@ -88,7 +88,7 @@ $$
-- in case of running the upgrade script a second time: -- in case of running the upgrade script a second time:
IF NOT (SELECT exists(SELECT FROM pg_tables WHERE tablename = 'old_edge_event')) THEN IF NOT (SELECT exists(SELECT FROM pg_tables WHERE tablename = 'old_edge_event')) THEN
ALTER TABLE edge_event RENAME TO old_edge_event; ALTER TABLE edge_event RENAME TO old_edge_event;
CREATE INDEX IF NOT EXISTS idx_old_blob_entity_created_time_tmp ON old_blob_entity(created_time); CREATE INDEX IF NOT EXISTS idx_old_edge_event_created_time_tmp ON old_edge_event(created_time);
ALTER INDEX IF EXISTS idx_edge_event_tenant_id_and_created_time RENAME TO idx_old_edge_event_tenant_id_and_created_time; ALTER INDEX IF EXISTS idx_edge_event_tenant_id_and_created_time RENAME TO idx_old_edge_event_tenant_id_and_created_time;
FOR table_partition IN SELECT tablename AS name, split_part(tablename, '_', 3) AS partition_ts FOR table_partition IN SELECT tablename AS name, split_part(tablename, '_', 3) AS partition_ts

11
application/src/main/java/org/thingsboard/server/controller/ControllerConstants.java

@ -1433,7 +1433,8 @@ public class ControllerConstants {
protected static final String ATTRIBUTES_SCOPE_DESCRIPTION = "A string value representing the attributes scope. For example, 'SERVER_SCOPE'."; protected static final String ATTRIBUTES_SCOPE_DESCRIPTION = "A string value representing the attributes scope. For example, 'SERVER_SCOPE'.";
protected static final String ATTRIBUTES_KEYS_DESCRIPTION = "A string value representing the comma-separated list of attributes keys. For example, 'active,inactivityAlarmTime'."; protected static final String ATTRIBUTES_KEYS_DESCRIPTION = "A string value representing the comma-separated list of attributes keys. For example, 'active,inactivityAlarmTime'.";
protected static final String ATTRIBUTES_SCOPE_ALLOWED_VALUES = "SERVER_SCOPE, CLIENT_SCOPE, SHARED_SCOPE"; protected static final String ATTRIBUTES_SAVE_SCOPE_ALLOWED_VALUES = "SERVER_SCOPE, SHARED_SCOPE";
protected static final String ATTRIBUTES_SCOPE_ALLOWED_VALUES = ATTRIBUTES_SAVE_SCOPE_ALLOWED_VALUES + ", CLIENT_SCOPE";
protected static final String ATTRIBUTES_JSON_REQUEST_DESCRIPTION = "A string value representing the json object. For example, '{\"key\":\"value\"}'. See API call description for more details."; protected static final String ATTRIBUTES_JSON_REQUEST_DESCRIPTION = "A string value representing the json object. For example, '{\"key\":\"value\"}'. See API call description for more details.";
protected static final String TELEMETRY_KEYS_BASE_DESCRIPTION = "A string value representing the comma-separated list of telemetry keys."; protected static final String TELEMETRY_KEYS_BASE_DESCRIPTION = "A string value representing the comma-separated list of telemetry keys.";
@ -1459,10 +1460,12 @@ public class ControllerConstants {
protected static final String SAVE_ENTITY_TIMESERIES_STATUS_INTERNAL_SERVER_ERROR = "The exception was thrown during processing the request. " + protected 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."; "Platform creates an audit log event about entity timeseries updates with action type 'TIMESERIES_UPDATED' that includes an error stacktrace.";
protected static final String ENTITY_ATTRIBUTE_SCOPES = " List of possible attribute scopes depends on the entity type: " + protected static final String ENTITY_ATTRIBUTE_SCOPES_TEMPLATE = " List of possible attribute scopes depends on the entity type: " +
"\n\n * SERVER_SCOPE - supported for all entity types;" + "\n\n * SERVER_SCOPE - supported for all entity types;" +
"\n * CLIENT_SCOPE - supported for devices;" + "\n * SHARED_SCOPE - supported for devices";
"\n * SHARED_SCOPE - supported for devices. "+ "\n\n"; protected static final String ENTITY_SAVE_ATTRIBUTE_SCOPES = ENTITY_ATTRIBUTE_SCOPES_TEMPLATE + ".\n\n";
protected static final String ENTITY_GET_ATTRIBUTE_SCOPES = ENTITY_ATTRIBUTE_SCOPES_TEMPLATE +
";\n * CLIENT_SCOPE - supported for devices. " + "\n\n";
protected static final String ATTRIBUTE_DATA_EXAMPLE = "[\n" + protected static final String ATTRIBUTE_DATA_EXAMPLE = "[\n" +
" {\"key\": \"stringAttributeKey\", \"value\": \"value\", \"lastUpdateTs\": 1609459200000},\n" + " {\"key\": \"stringAttributeKey\", \"value\": \"value\", \"lastUpdateTs\": 1609459200000},\n" +

19
application/src/main/java/org/thingsboard/server/controller/TelemetryController.java

@ -58,7 +58,6 @@ import org.thingsboard.server.common.data.id.EntityIdFactory;
import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.id.UUIDBased; import org.thingsboard.server.common.data.id.UUIDBased;
import org.thingsboard.server.common.data.kv.Aggregation; import org.thingsboard.server.common.data.kv.Aggregation;
import org.thingsboard.server.common.data.kv.AttributeKey;
import org.thingsboard.server.common.data.kv.AttributeKvEntry; import org.thingsboard.server.common.data.kv.AttributeKvEntry;
import org.thingsboard.server.common.data.kv.BaseAttributeKvEntry; import org.thingsboard.server.common.data.kv.BaseAttributeKvEntry;
import org.thingsboard.server.common.data.kv.BaseDeleteTsKvQuery; import org.thingsboard.server.common.data.kv.BaseDeleteTsKvQuery;
@ -92,11 +91,9 @@ import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy; import javax.annotation.PreDestroy;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashSet;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@ -104,13 +101,15 @@ import java.util.stream.Collectors;
import static org.thingsboard.server.controller.ControllerConstants.ATTRIBUTES_JSON_REQUEST_DESCRIPTION; import static org.thingsboard.server.controller.ControllerConstants.ATTRIBUTES_JSON_REQUEST_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.ATTRIBUTES_KEYS_DESCRIPTION; import static org.thingsboard.server.controller.ControllerConstants.ATTRIBUTES_KEYS_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.ATTRIBUTES_SAVE_SCOPE_ALLOWED_VALUES;
import static org.thingsboard.server.controller.ControllerConstants.ATTRIBUTES_SCOPE_ALLOWED_VALUES; import static org.thingsboard.server.controller.ControllerConstants.ATTRIBUTES_SCOPE_ALLOWED_VALUES;
import static org.thingsboard.server.controller.ControllerConstants.ATTRIBUTES_SCOPE_DESCRIPTION; import static org.thingsboard.server.controller.ControllerConstants.ATTRIBUTES_SCOPE_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.ATTRIBUTE_DATA_EXAMPLE; import static org.thingsboard.server.controller.ControllerConstants.ATTRIBUTE_DATA_EXAMPLE;
import static org.thingsboard.server.controller.ControllerConstants.DEVICE_ID; 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.DEVICE_ID_PARAM_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.ENTITY_ATTRIBUTE_SCOPES; import static org.thingsboard.server.controller.ControllerConstants.ENTITY_GET_ATTRIBUTE_SCOPES;
import static org.thingsboard.server.controller.ControllerConstants.ENTITY_ID_PARAM_DESCRIPTION; import static org.thingsboard.server.controller.ControllerConstants.ENTITY_ID_PARAM_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.ENTITY_SAVE_ATTRIBUTE_SCOPES;
import static org.thingsboard.server.controller.ControllerConstants.ENTITY_TYPE_PARAM_DESCRIPTION; import static org.thingsboard.server.controller.ControllerConstants.ENTITY_TYPE_PARAM_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.INVALID_ENTITY_ID_OR_ENTITY_TYPE_DESCRIPTION; import static org.thingsboard.server.controller.ControllerConstants.INVALID_ENTITY_ID_OR_ENTITY_TYPE_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.INVALID_STRUCTURE_OF_THE_REQUEST; import static org.thingsboard.server.controller.ControllerConstants.INVALID_STRUCTURE_OF_THE_REQUEST;
@ -241,7 +240,7 @@ public class TelemetryController extends BaseController {
@ApiOperation(value = "Get attributes by scope (getAttributesByScope)", @ApiOperation(value = "Get attributes by scope (getAttributesByScope)",
notes = "Returns all attributes of a specified scope that belong to specified entity." + notes = "Returns all attributes of a specified scope that belong to specified entity." +
ENTITY_ATTRIBUTE_SCOPES + ENTITY_GET_ATTRIBUTE_SCOPES +
"Use optional 'keys' parameter to return specific attributes." "Use optional 'keys' parameter to return specific attributes."
+ "\n Example of the result: \n\n" + "\n Example of the result: \n\n"
+ MARKDOWN_CODE_BLOCK_START + MARKDOWN_CODE_BLOCK_START
@ -383,7 +382,7 @@ public class TelemetryController extends BaseController {
@ResponseBody @ResponseBody
public DeferredResult<ResponseEntity> saveDeviceAttributes( public DeferredResult<ResponseEntity> saveDeviceAttributes(
@ApiParam(value = DEVICE_ID_PARAM_DESCRIPTION, required = true) @PathVariable("deviceId") String deviceIdStr, @ApiParam(value = DEVICE_ID_PARAM_DESCRIPTION, required = true) @PathVariable("deviceId") String deviceIdStr,
@ApiParam(value = ATTRIBUTES_SCOPE_DESCRIPTION, allowableValues = ATTRIBUTES_SCOPE_ALLOWED_VALUES, required = true) @PathVariable("scope") String scope, @ApiParam(value = ATTRIBUTES_SCOPE_DESCRIPTION, allowableValues = ATTRIBUTES_SAVE_SCOPE_ALLOWED_VALUES, required = true) @PathVariable("scope") String scope,
@ApiParam(value = ATTRIBUTES_JSON_REQUEST_DESCRIPTION, required = true) @RequestBody JsonNode request) throws ThingsboardException { @ApiParam(value = ATTRIBUTES_JSON_REQUEST_DESCRIPTION, required = true) @RequestBody JsonNode request) throws ThingsboardException {
try { try {
EntityId entityId = EntityIdFactory.getByTypeAndUuid(EntityType.DEVICE, deviceIdStr); EntityId entityId = EntityIdFactory.getByTypeAndUuid(EntityType.DEVICE, deviceIdStr);
@ -395,7 +394,7 @@ public class TelemetryController extends BaseController {
@ApiOperation(value = "Save entity attributes (saveEntityAttributesV1)", @ApiOperation(value = "Save entity attributes (saveEntityAttributesV1)",
notes = "Creates or updates the entity attributes based on Entity Id and the specified attribute scope. " + notes = "Creates or updates the entity attributes based on Entity Id and the specified attribute scope. " +
ENTITY_ATTRIBUTE_SCOPES + ENTITY_SAVE_ATTRIBUTE_SCOPES +
SAVE_ATTRIBUTES_REQUEST_PAYLOAD SAVE_ATTRIBUTES_REQUEST_PAYLOAD
+ INVALID_ENTITY_ID_OR_ENTITY_TYPE_DESCRIPTION + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH, + INVALID_ENTITY_ID_OR_ENTITY_TYPE_DESCRIPTION + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH,
produces = MediaType.APPLICATION_JSON_VALUE) produces = MediaType.APPLICATION_JSON_VALUE)
@ -411,7 +410,7 @@ public class TelemetryController extends BaseController {
public DeferredResult<ResponseEntity> saveEntityAttributesV1( public DeferredResult<ResponseEntity> saveEntityAttributesV1(
@ApiParam(value = ENTITY_TYPE_PARAM_DESCRIPTION, required = true, defaultValue = "DEVICE") @PathVariable("entityType") String entityType, @ApiParam(value = ENTITY_TYPE_PARAM_DESCRIPTION, required = true, defaultValue = "DEVICE") @PathVariable("entityType") String entityType,
@ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION, required = true) @PathVariable("entityId") String entityIdStr, @ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION, required = true) @PathVariable("entityId") String entityIdStr,
@ApiParam(value = ATTRIBUTES_SCOPE_DESCRIPTION, allowableValues = ATTRIBUTES_SCOPE_ALLOWED_VALUES) @PathVariable("scope") String scope, @ApiParam(value = ATTRIBUTES_SCOPE_DESCRIPTION, allowableValues = ATTRIBUTES_SAVE_SCOPE_ALLOWED_VALUES) @PathVariable("scope") String scope,
@ApiParam(value = ATTRIBUTES_JSON_REQUEST_DESCRIPTION, required = true) @RequestBody JsonNode request) throws ThingsboardException { @ApiParam(value = ATTRIBUTES_JSON_REQUEST_DESCRIPTION, required = true) @RequestBody JsonNode request) throws ThingsboardException {
try { try {
EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr); EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr);
@ -423,7 +422,7 @@ public class TelemetryController extends BaseController {
@ApiOperation(value = "Save entity attributes (saveEntityAttributesV2)", @ApiOperation(value = "Save entity attributes (saveEntityAttributesV2)",
notes = "Creates or updates the entity attributes based on Entity Id and the specified attribute scope. " + notes = "Creates or updates the entity attributes based on Entity Id and the specified attribute scope. " +
ENTITY_ATTRIBUTE_SCOPES + ENTITY_SAVE_ATTRIBUTE_SCOPES +
SAVE_ATTRIBUTES_REQUEST_PAYLOAD SAVE_ATTRIBUTES_REQUEST_PAYLOAD
+ INVALID_ENTITY_ID_OR_ENTITY_TYPE_DESCRIPTION + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH, + INVALID_ENTITY_ID_OR_ENTITY_TYPE_DESCRIPTION + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH,
produces = MediaType.APPLICATION_JSON_VALUE) produces = MediaType.APPLICATION_JSON_VALUE)
@ -439,7 +438,7 @@ public class TelemetryController extends BaseController {
public DeferredResult<ResponseEntity> saveEntityAttributesV2( public DeferredResult<ResponseEntity> saveEntityAttributesV2(
@ApiParam(value = ENTITY_TYPE_PARAM_DESCRIPTION, required = true, defaultValue = "DEVICE") @PathVariable("entityType") String entityType, @ApiParam(value = ENTITY_TYPE_PARAM_DESCRIPTION, required = true, defaultValue = "DEVICE") @PathVariable("entityType") String entityType,
@ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION, required = true) @PathVariable("entityId") String entityIdStr, @ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION, required = true) @PathVariable("entityId") String entityIdStr,
@ApiParam(value = ATTRIBUTES_SCOPE_DESCRIPTION, allowableValues = ATTRIBUTES_SCOPE_ALLOWED_VALUES, required = true) @PathVariable("scope") String scope, @ApiParam(value = ATTRIBUTES_SCOPE_DESCRIPTION, allowableValues = ATTRIBUTES_SAVE_SCOPE_ALLOWED_VALUES, required = true) @PathVariable("scope") String scope,
@ApiParam(value = ATTRIBUTES_JSON_REQUEST_DESCRIPTION, required = true) @RequestBody JsonNode request) throws ThingsboardException { @ApiParam(value = ATTRIBUTES_JSON_REQUEST_DESCRIPTION, required = true) @RequestBody JsonNode request) throws ThingsboardException {
try { try {
EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr); EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr);

12
application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/RuleChainsEdgeEventFetcher.java

@ -15,8 +15,10 @@
*/ */
package org.thingsboard.server.service.edge.rpc.fetch; package org.thingsboard.server.service.edge.rpc.fetch;
import com.fasterxml.jackson.databind.node.ObjectNode;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.common.data.EdgeUtils; import org.thingsboard.server.common.data.EdgeUtils;
import org.thingsboard.server.common.data.edge.Edge; import org.thingsboard.server.common.data.edge.Edge;
import org.thingsboard.server.common.data.edge.EdgeEvent; import org.thingsboard.server.common.data.edge.EdgeEvent;
@ -28,6 +30,8 @@ import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.common.data.rule.RuleChain; import org.thingsboard.server.common.data.rule.RuleChain;
import org.thingsboard.server.dao.rule.RuleChainService; import org.thingsboard.server.dao.rule.RuleChainService;
import static org.thingsboard.server.service.edge.DefaultEdgeNotificationService.EDGE_IS_ROOT_BODY_KEY;
@Slf4j @Slf4j
@AllArgsConstructor @AllArgsConstructor
public class RuleChainsEdgeEventFetcher extends BasePageableEdgeEventFetcher<RuleChain> { public class RuleChainsEdgeEventFetcher extends BasePageableEdgeEventFetcher<RuleChain> {
@ -41,7 +45,13 @@ public class RuleChainsEdgeEventFetcher extends BasePageableEdgeEventFetcher<Rul
@Override @Override
EdgeEvent constructEdgeEvent(TenantId tenantId, Edge edge, RuleChain ruleChain) { EdgeEvent constructEdgeEvent(TenantId tenantId, Edge edge, RuleChain ruleChain) {
ObjectNode isRootBody = JacksonUtil.OBJECT_MAPPER.createObjectNode();
boolean isRoot = false;
try {
isRoot = ruleChain.getId().equals(edge.getRootRuleChainId());
} catch (Exception ignored) {}
isRootBody.put(EDGE_IS_ROOT_BODY_KEY, isRoot);
return EdgeUtils.constructEdgeEvent(tenantId, edge.getId(), EdgeEventType.RULE_CHAIN, return EdgeUtils.constructEdgeEvent(tenantId, edge.getId(), EdgeEventType.RULE_CHAIN,
EdgeEventActionType.ADDED, ruleChain.getId(), null); EdgeEventActionType.ADDED, ruleChain.getId(), isRootBody);
} }
} }

3
application/src/main/java/org/thingsboard/server/service/entitiy/edge/DefaultTbEdgeService.java

@ -48,6 +48,9 @@ public class DefaultTbEdgeService extends AbstractTbEntityService implements TbE
ActionType actionType = edge.getId() == null ? ActionType.ADDED : ActionType.UPDATED; ActionType actionType = edge.getId() == null ? ActionType.ADDED : ActionType.UPDATED;
TenantId tenantId = edge.getTenantId(); TenantId tenantId = edge.getTenantId();
try { try {
if (actionType == ActionType.ADDED && edge.getRootRuleChainId() == null) {
edge.setRootRuleChainId(edgeTemplateRootRuleChain.getId());
}
Edge savedEdge = checkNotNull(edgeService.saveEdge(edge)); Edge savedEdge = checkNotNull(edgeService.saveEdge(edge));
EdgeId edgeId = savedEdge.getId(); EdgeId edgeId = savedEdge.getId();

2
application/src/main/java/org/thingsboard/server/service/session/DefaultDeviceSessionCacheService.java

@ -52,7 +52,7 @@ public class DefaultDeviceSessionCacheService implements DeviceSessionCacheServi
@Override @Override
public DeviceSessionsCacheEntry put(DeviceId deviceId, DeviceSessionsCacheEntry sessions) { public DeviceSessionsCacheEntry put(DeviceId deviceId, DeviceSessionsCacheEntry sessions) {
log.debug("[{}] Pushing session data to cache: {}", deviceId, sessions); log.debug("[{}] Pushing session data to cache: {}", deviceId, sessions);
cache.putIfAbsent(deviceId, sessions); cache.put(deviceId, sessions);
return sessions; return sessions;
} }
} }

14
application/src/test/java/org/thingsboard/server/controller/BaseEdgeControllerTest.java

@ -825,26 +825,30 @@ public abstract class BaseEdgeControllerTest extends AbstractControllerTest {
assertThat(edgeImitator.waitForMessages()).as("await for messages on first connect").isTrue(); assertThat(edgeImitator.waitForMessages()).as("await for messages on first connect").isTrue();
assertThat(edgeImitator.findAllMessagesByType(QueueUpdateMsg.class)).as("one msg during sync process").hasSize(1); assertThat(edgeImitator.findAllMessagesByType(QueueUpdateMsg.class)).as("one msg during sync process").hasSize(1);
assertThat(edgeImitator.findAllMessagesByType(RuleChainUpdateMsg.class)).as("one msg during sync process, another from edge creation").hasSize(2); List<RuleChainUpdateMsg> ruleChainUpdateMsgs = edgeImitator.findAllMessagesByType(RuleChainUpdateMsg.class);
assertThat(ruleChainUpdateMsgs).as("one msg during sync process, another from edge creation").hasSize(2);
assertThat(edgeImitator.findAllMessagesByType(DeviceProfileUpdateMsg.class)).as("one msg during sync process for 'default' device profile").hasSize(3); assertThat(edgeImitator.findAllMessagesByType(DeviceProfileUpdateMsg.class)).as("one msg during sync process for 'default' device profile").hasSize(3);
assertThat(edgeImitator.findAllMessagesByType(DeviceUpdateMsg.class)).as("one msg once device assigned to edge").hasSize(2); assertThat(edgeImitator.findAllMessagesByType(DeviceUpdateMsg.class)).as("one msg once device assigned to edge").hasSize(2);
assertThat(edgeImitator.findAllMessagesByType(AssetProfileUpdateMsg.class)).as("two msgs during sync process for 'default' and 'test' asset profiles").hasSize(4); assertThat(edgeImitator.findAllMessagesByType(AssetProfileUpdateMsg.class)).as("two msgs during sync process for 'default' and 'test' asset profiles").hasSize(4);
assertThat(edgeImitator.findAllMessagesByType(AssetUpdateMsg.class)).as("two msgs - one during sync process, and one more once asset assigned to edge").hasSize(2); assertThat(edgeImitator.findAllMessagesByType(AssetUpdateMsg.class)).as("two msgs - one during sync process, and one more once asset assigned to edge").hasSize(2);
assertThat(edgeImitator.findAllMessagesByType(UserUpdateMsg.class)).as("one msg during sync process for tenant admin user").hasSize(1); assertThat(edgeImitator.findAllMessagesByType(UserUpdateMsg.class)).as("one msg during sync process for tenant admin user").hasSize(1);
assertThat(edgeImitator.findAllMessagesByType(AdminSettingsUpdateMsg.class)).as("admin setting update").hasSize(4); assertThat(edgeImitator.findAllMessagesByType(AdminSettingsUpdateMsg.class)).as("admin setting update").hasSize(4);
verifyRuleChainMsgsAreRoot(ruleChainUpdateMsgs);
edgeImitator.expectMessageAmount(14); edgeImitator.expectMessageAmount(14);
doPost("/api/edge/sync/" + edge.getId()); doPost("/api/edge/sync/" + edge.getId());
assertThat(edgeImitator.waitForMessages()).as("await for messages after edge sync rest api call").isTrue(); assertThat(edgeImitator.waitForMessages()).as("await for messages after edge sync rest api call").isTrue();
assertThat(edgeImitator.findAllMessagesByType(QueueUpdateMsg.class)).as("queue msg").hasSize(1); assertThat(edgeImitator.findAllMessagesByType(QueueUpdateMsg.class)).as("queue msg").hasSize(1);
assertThat(edgeImitator.findAllMessagesByType(RuleChainUpdateMsg.class)).as("rule chain msg").hasSize(1); ruleChainUpdateMsgs = edgeImitator.findAllMessagesByType(RuleChainUpdateMsg.class);
assertThat(ruleChainUpdateMsgs).as("rule chain msg").hasSize(1);
assertThat(edgeImitator.findAllMessagesByType(DeviceProfileUpdateMsg.class)).as("device profile msg").hasSize(2); assertThat(edgeImitator.findAllMessagesByType(DeviceProfileUpdateMsg.class)).as("device profile msg").hasSize(2);
assertThat(edgeImitator.findAllMessagesByType(AssetProfileUpdateMsg.class)).as("asset profile msg").hasSize(3); assertThat(edgeImitator.findAllMessagesByType(AssetProfileUpdateMsg.class)).as("asset profile msg").hasSize(3);
assertThat(edgeImitator.findAllMessagesByType(AssetUpdateMsg.class)).as("asset update msg").hasSize(1); assertThat(edgeImitator.findAllMessagesByType(AssetUpdateMsg.class)).as("asset update msg").hasSize(1);
assertThat(edgeImitator.findAllMessagesByType(UserUpdateMsg.class)).as("user update msg").hasSize(1); assertThat(edgeImitator.findAllMessagesByType(UserUpdateMsg.class)).as("user update msg").hasSize(1);
assertThat(edgeImitator.findAllMessagesByType(AdminSettingsUpdateMsg.class)).as("admin setting update msg").hasSize(4); assertThat(edgeImitator.findAllMessagesByType(AdminSettingsUpdateMsg.class)).as("admin setting update msg").hasSize(4);
assertThat(edgeImitator.findAllMessagesByType(DeviceUpdateMsg.class)).as("asset update msg").hasSize(1); assertThat(edgeImitator.findAllMessagesByType(DeviceUpdateMsg.class)).as("asset update msg").hasSize(1);
verifyRuleChainMsgsAreRoot(ruleChainUpdateMsgs);
edgeImitator.allowIgnoredTypes(); edgeImitator.allowIgnoredTypes();
try { try {
@ -860,6 +864,12 @@ public abstract class BaseEdgeControllerTest extends AbstractControllerTest {
.andExpect(status().isOk()); .andExpect(status().isOk());
} }
private void verifyRuleChainMsgsAreRoot(List<RuleChainUpdateMsg> ruleChainUpdateMsgs) {
for (RuleChainUpdateMsg ruleChainUpdateMsg : ruleChainUpdateMsgs) {
Assert.assertTrue(ruleChainUpdateMsg.getRoot());
}
}
@Test @Test
public void testDeleteEdgeWithDeleteRelationsOk() throws Exception { public void testDeleteEdgeWithDeleteRelationsOk() throws Exception {
EdgeId edgeId = savedEdge("Edge for Test WithRelationsOk").getId(); EdgeId edgeId = savedEdge("Edge for Test WithRelationsOk").getId();

2
common/actor/pom.xml

@ -20,7 +20,7 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
<groupId>org.thingsboard</groupId> <groupId>org.thingsboard</groupId>
<version>3.4.3-SNAPSHOT</version> <version>3.4.4-SNAPSHOT</version>
<artifactId>common</artifactId> <artifactId>common</artifactId>
</parent> </parent>
<groupId>org.thingsboard.common</groupId> <groupId>org.thingsboard.common</groupId>

2
common/cache/pom.xml

@ -20,7 +20,7 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
<groupId>org.thingsboard</groupId> <groupId>org.thingsboard</groupId>
<version>3.4.3-SNAPSHOT</version> <version>3.4.4-SNAPSHOT</version>
<artifactId>common</artifactId> <artifactId>common</artifactId>
</parent> </parent>
<groupId>org.thingsboard.common</groupId> <groupId>org.thingsboard.common</groupId>

2
common/cluster-api/pom.xml

@ -20,7 +20,7 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
<groupId>org.thingsboard</groupId> <groupId>org.thingsboard</groupId>
<version>3.4.3-SNAPSHOT</version> <version>3.4.4-SNAPSHOT</version>
<artifactId>common</artifactId> <artifactId>common</artifactId>
</parent> </parent>
<groupId>org.thingsboard.common</groupId> <groupId>org.thingsboard.common</groupId>

2
common/coap-server/pom.xml

@ -22,7 +22,7 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
<groupId>org.thingsboard</groupId> <groupId>org.thingsboard</groupId>
<version>3.4.3-SNAPSHOT</version> <version>3.4.4-SNAPSHOT</version>
<artifactId>common</artifactId> <artifactId>common</artifactId>
</parent> </parent>
<groupId>org.thingsboard.common</groupId> <groupId>org.thingsboard.common</groupId>

2
common/dao-api/pom.xml

@ -20,7 +20,7 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
<groupId>org.thingsboard</groupId> <groupId>org.thingsboard</groupId>
<version>3.4.3-SNAPSHOT</version> <version>3.4.4-SNAPSHOT</version>
<artifactId>common</artifactId> <artifactId>common</artifactId>
</parent> </parent>
<groupId>org.thingsboard.common</groupId> <groupId>org.thingsboard.common</groupId>

2
common/data/pom.xml

@ -20,7 +20,7 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
<groupId>org.thingsboard</groupId> <groupId>org.thingsboard</groupId>
<version>3.4.3-SNAPSHOT</version> <version>3.4.4-SNAPSHOT</version>
<artifactId>common</artifactId> <artifactId>common</artifactId>
</parent> </parent>
<groupId>org.thingsboard.common</groupId> <groupId>org.thingsboard.common</groupId>

2
common/edge-api/pom.xml

@ -20,7 +20,7 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
<groupId>org.thingsboard</groupId> <groupId>org.thingsboard</groupId>
<version>3.4.3-SNAPSHOT</version> <version>3.4.4-SNAPSHOT</version>
<artifactId>common</artifactId> <artifactId>common</artifactId>
</parent> </parent>
<groupId>org.thingsboard.common</groupId> <groupId>org.thingsboard.common</groupId>

2
common/message/pom.xml

@ -20,7 +20,7 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
<groupId>org.thingsboard</groupId> <groupId>org.thingsboard</groupId>
<version>3.4.3-SNAPSHOT</version> <version>3.4.4-SNAPSHOT</version>
<artifactId>common</artifactId> <artifactId>common</artifactId>
</parent> </parent>
<groupId>org.thingsboard.common</groupId> <groupId>org.thingsboard.common</groupId>

2
common/pom.xml

@ -20,7 +20,7 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
<groupId>org.thingsboard</groupId> <groupId>org.thingsboard</groupId>
<version>3.4.3-SNAPSHOT</version> <version>3.4.4-SNAPSHOT</version>
<artifactId>thingsboard</artifactId> <artifactId>thingsboard</artifactId>
</parent> </parent>
<artifactId>common</artifactId> <artifactId>common</artifactId>

2
common/queue/pom.xml

@ -20,7 +20,7 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
<groupId>org.thingsboard</groupId> <groupId>org.thingsboard</groupId>
<version>3.4.3-SNAPSHOT</version> <version>3.4.4-SNAPSHOT</version>
<artifactId>common</artifactId> <artifactId>common</artifactId>
</parent> </parent>
<groupId>org.thingsboard.common</groupId> <groupId>org.thingsboard.common</groupId>

2
common/script/pom.xml

@ -20,7 +20,7 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
<groupId>org.thingsboard</groupId> <groupId>org.thingsboard</groupId>
<version>3.4.3-SNAPSHOT</version> <version>3.4.4-SNAPSHOT</version>
<artifactId>common</artifactId> <artifactId>common</artifactId>
</parent> </parent>
<groupId>org.thingsboard.common</groupId> <groupId>org.thingsboard.common</groupId>

2
common/script/remote-js-client/pom.xml

@ -20,7 +20,7 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
<groupId>org.thingsboard.common</groupId> <groupId>org.thingsboard.common</groupId>
<version>3.4.3-SNAPSHOT</version> <version>3.4.4-SNAPSHOT</version>
<artifactId>script</artifactId> <artifactId>script</artifactId>
</parent> </parent>
<groupId>org.thingsboard.common.script</groupId> <groupId>org.thingsboard.common.script</groupId>

2
common/script/script-api/pom.xml

@ -20,7 +20,7 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
<groupId>org.thingsboard.common</groupId> <groupId>org.thingsboard.common</groupId>
<version>3.4.3-SNAPSHOT</version> <version>3.4.4-SNAPSHOT</version>
<artifactId>script</artifactId> <artifactId>script</artifactId>
</parent> </parent>
<groupId>org.thingsboard.common.script</groupId> <groupId>org.thingsboard.common.script</groupId>

2
common/stats/pom.xml

@ -22,7 +22,7 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
<groupId>org.thingsboard</groupId> <groupId>org.thingsboard</groupId>
<version>3.4.3-SNAPSHOT</version> <version>3.4.4-SNAPSHOT</version>
<artifactId>common</artifactId> <artifactId>common</artifactId>
</parent> </parent>
<groupId>org.thingsboard.common</groupId> <groupId>org.thingsboard.common</groupId>

2
common/transport/coap/pom.xml

@ -20,7 +20,7 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
<groupId>org.thingsboard.common</groupId> <groupId>org.thingsboard.common</groupId>
<version>3.4.3-SNAPSHOT</version> <version>3.4.4-SNAPSHOT</version>
<artifactId>transport</artifactId> <artifactId>transport</artifactId>
</parent> </parent>
<groupId>org.thingsboard.common.transport</groupId> <groupId>org.thingsboard.common.transport</groupId>

2
common/transport/http/pom.xml

@ -20,7 +20,7 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
<groupId>org.thingsboard.common</groupId> <groupId>org.thingsboard.common</groupId>
<version>3.4.3-SNAPSHOT</version> <version>3.4.4-SNAPSHOT</version>
<artifactId>transport</artifactId> <artifactId>transport</artifactId>
</parent> </parent>
<groupId>org.thingsboard.common.transport</groupId> <groupId>org.thingsboard.common.transport</groupId>

2
common/transport/lwm2m/pom.xml

@ -20,7 +20,7 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
<groupId>org.thingsboard.common</groupId> <groupId>org.thingsboard.common</groupId>
<version>3.4.3-SNAPSHOT</version> <version>3.4.4-SNAPSHOT</version>
<artifactId>transport</artifactId> <artifactId>transport</artifactId>
</parent> </parent>
<groupId>org.thingsboard.common.transport</groupId> <groupId>org.thingsboard.common.transport</groupId>

2
common/transport/mqtt/pom.xml

@ -20,7 +20,7 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
<groupId>org.thingsboard.common</groupId> <groupId>org.thingsboard.common</groupId>
<version>3.4.3-SNAPSHOT</version> <version>3.4.4-SNAPSHOT</version>
<artifactId>transport</artifactId> <artifactId>transport</artifactId>
</parent> </parent>
<groupId>org.thingsboard.common.transport</groupId> <groupId>org.thingsboard.common.transport</groupId>

2
common/transport/pom.xml

@ -20,7 +20,7 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
<groupId>org.thingsboard</groupId> <groupId>org.thingsboard</groupId>
<version>3.4.3-SNAPSHOT</version> <version>3.4.4-SNAPSHOT</version>
<artifactId>common</artifactId> <artifactId>common</artifactId>
</parent> </parent>
<groupId>org.thingsboard.common</groupId> <groupId>org.thingsboard.common</groupId>

2
common/transport/snmp/pom.xml

@ -21,7 +21,7 @@
<parent> <parent>
<groupId>org.thingsboard.common</groupId> <groupId>org.thingsboard.common</groupId>
<version>3.4.3-SNAPSHOT</version> <version>3.4.4-SNAPSHOT</version>
<artifactId>transport</artifactId> <artifactId>transport</artifactId>
</parent> </parent>

2
common/transport/transport-api/pom.xml

@ -20,7 +20,7 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
<groupId>org.thingsboard.common</groupId> <groupId>org.thingsboard.common</groupId>
<version>3.4.3-SNAPSHOT</version> <version>3.4.4-SNAPSHOT</version>
<artifactId>transport</artifactId> <artifactId>transport</artifactId>
</parent> </parent>
<groupId>org.thingsboard.common.transport</groupId> <groupId>org.thingsboard.common.transport</groupId>

2
common/util/pom.xml

@ -20,7 +20,7 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
<groupId>org.thingsboard</groupId> <groupId>org.thingsboard</groupId>
<version>3.4.3-SNAPSHOT</version> <version>3.4.4-SNAPSHOT</version>
<artifactId>common</artifactId> <artifactId>common</artifactId>
</parent> </parent>
<groupId>org.thingsboard.common</groupId> <groupId>org.thingsboard.common</groupId>

2
common/version-control/pom.xml

@ -20,7 +20,7 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
<groupId>org.thingsboard</groupId> <groupId>org.thingsboard</groupId>
<version>3.4.3-SNAPSHOT</version> <version>3.4.4-SNAPSHOT</version>
<artifactId>common</artifactId> <artifactId>common</artifactId>
</parent> </parent>
<groupId>org.thingsboard.common</groupId> <groupId>org.thingsboard.common</groupId>

2
dao/pom.xml

@ -20,7 +20,7 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
<groupId>org.thingsboard</groupId> <groupId>org.thingsboard</groupId>
<version>3.4.3-SNAPSHOT</version> <version>3.4.4-SNAPSHOT</version>
<artifactId>thingsboard</artifactId> <artifactId>thingsboard</artifactId>
</parent> </parent>
<artifactId>dao</artifactId> <artifactId>dao</artifactId>

9
dao/src/main/java/org/thingsboard/server/dao/service/ConstraintValidator.java

@ -53,8 +53,13 @@ public class ConstraintValidator {
public static List<String> getConstraintsViolations(Object data) { public static List<String> getConstraintsViolations(Object data) {
return fieldsValidator.validate(data).stream() return fieldsValidator.validate(data).stream()
.map(constraintViolation -> { .map(constraintViolation -> {
Path propertyPath = constraintViolation.getPropertyPath(); String property;
String property = Iterators.getLast(propertyPath.iterator()).toString(); if (constraintViolation.getConstraintDescriptor().getAttributes().containsKey("fieldName")) {
property = constraintViolation.getConstraintDescriptor().getAttributes().get("fieldName").toString();
} else {
Path propertyPath = constraintViolation.getPropertyPath();
property = Iterators.getLast(propertyPath.iterator()).toString();
}
return property + " " + constraintViolation.getMessage(); return property + " " + constraintViolation.getMessage();
}) })
.distinct() .distinct()

2
msa/black-box-tests/pom.xml

@ -21,7 +21,7 @@
<parent> <parent>
<groupId>org.thingsboard</groupId> <groupId>org.thingsboard</groupId>
<version>3.4.3-SNAPSHOT</version> <version>3.4.4-SNAPSHOT</version>
<artifactId>msa</artifactId> <artifactId>msa</artifactId>
</parent> </parent>
<groupId>org.thingsboard.msa</groupId> <groupId>org.thingsboard.msa</groupId>

2
msa/js-executor/package.json

@ -1,7 +1,7 @@
{ {
"name": "thingsboard-js-executor", "name": "thingsboard-js-executor",
"private": true, "private": true,
"version": "3.4.3", "version": "3.4.4",
"description": "ThingsBoard JavaScript Executor Microservice", "description": "ThingsBoard JavaScript Executor Microservice",
"main": "server.ts", "main": "server.ts",
"bin": "server.js", "bin": "server.js",

2
msa/js-executor/pom.xml

@ -20,7 +20,7 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
<groupId>org.thingsboard</groupId> <groupId>org.thingsboard</groupId>
<version>3.4.3-SNAPSHOT</version> <version>3.4.4-SNAPSHOT</version>
<artifactId>msa</artifactId> <artifactId>msa</artifactId>
</parent> </parent>
<groupId>org.thingsboard.msa</groupId> <groupId>org.thingsboard.msa</groupId>

2
msa/pom.xml

@ -20,7 +20,7 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
<groupId>org.thingsboard</groupId> <groupId>org.thingsboard</groupId>
<version>3.4.3-SNAPSHOT</version> <version>3.4.4-SNAPSHOT</version>
<artifactId>thingsboard</artifactId> <artifactId>thingsboard</artifactId>
</parent> </parent>
<artifactId>msa</artifactId> <artifactId>msa</artifactId>

2
msa/tb-node/pom.xml

@ -20,7 +20,7 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
<groupId>org.thingsboard</groupId> <groupId>org.thingsboard</groupId>
<version>3.4.3-SNAPSHOT</version> <version>3.4.4-SNAPSHOT</version>
<artifactId>msa</artifactId> <artifactId>msa</artifactId>
</parent> </parent>
<groupId>org.thingsboard.msa</groupId> <groupId>org.thingsboard.msa</groupId>

2
msa/tb/pom.xml

@ -20,7 +20,7 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
<groupId>org.thingsboard</groupId> <groupId>org.thingsboard</groupId>
<version>3.4.3-SNAPSHOT</version> <version>3.4.4-SNAPSHOT</version>
<artifactId>msa</artifactId> <artifactId>msa</artifactId>
</parent> </parent>
<groupId>org.thingsboard.msa</groupId> <groupId>org.thingsboard.msa</groupId>

2
msa/transport/coap/pom.xml

@ -20,7 +20,7 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
<groupId>org.thingsboard.msa</groupId> <groupId>org.thingsboard.msa</groupId>
<version>3.4.3-SNAPSHOT</version> <version>3.4.4-SNAPSHOT</version>
<artifactId>transport</artifactId> <artifactId>transport</artifactId>
</parent> </parent>
<groupId>org.thingsboard.msa.transport</groupId> <groupId>org.thingsboard.msa.transport</groupId>

2
msa/transport/http/pom.xml

@ -20,7 +20,7 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
<groupId>org.thingsboard.msa</groupId> <groupId>org.thingsboard.msa</groupId>
<version>3.4.3-SNAPSHOT</version> <version>3.4.4-SNAPSHOT</version>
<artifactId>transport</artifactId> <artifactId>transport</artifactId>
</parent> </parent>
<groupId>org.thingsboard.msa.transport</groupId> <groupId>org.thingsboard.msa.transport</groupId>

2
msa/transport/lwm2m/pom.xml

@ -20,7 +20,7 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
<groupId>org.thingsboard.msa</groupId> <groupId>org.thingsboard.msa</groupId>
<version>3.4.3-SNAPSHOT</version> <version>3.4.4-SNAPSHOT</version>
<artifactId>transport</artifactId> <artifactId>transport</artifactId>
</parent> </parent>
<groupId>org.thingsboard.msa.transport</groupId> <groupId>org.thingsboard.msa.transport</groupId>

2
msa/transport/mqtt/pom.xml

@ -20,7 +20,7 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
<groupId>org.thingsboard.msa</groupId> <groupId>org.thingsboard.msa</groupId>
<version>3.4.3-SNAPSHOT</version> <version>3.4.4-SNAPSHOT</version>
<artifactId>transport</artifactId> <artifactId>transport</artifactId>
</parent> </parent>
<groupId>org.thingsboard.msa.transport</groupId> <groupId>org.thingsboard.msa.transport</groupId>

2
msa/transport/pom.xml

@ -20,7 +20,7 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
<groupId>org.thingsboard</groupId> <groupId>org.thingsboard</groupId>
<version>3.4.3-SNAPSHOT</version> <version>3.4.4-SNAPSHOT</version>
<artifactId>msa</artifactId> <artifactId>msa</artifactId>
</parent> </parent>
<groupId>org.thingsboard.msa</groupId> <groupId>org.thingsboard.msa</groupId>

2
msa/transport/snmp/pom.xml

@ -21,7 +21,7 @@
<parent> <parent>
<groupId>org.thingsboard.msa</groupId> <groupId>org.thingsboard.msa</groupId>
<artifactId>transport</artifactId> <artifactId>transport</artifactId>
<version>3.4.3-SNAPSHOT</version> <version>3.4.4-SNAPSHOT</version>
</parent> </parent>
<groupId>org.thingsboard.msa.transport</groupId> <groupId>org.thingsboard.msa.transport</groupId>

2
msa/vc-executor-docker/pom.xml

@ -20,7 +20,7 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
<groupId>org.thingsboard</groupId> <groupId>org.thingsboard</groupId>
<version>3.4.3-SNAPSHOT</version> <version>3.4.4-SNAPSHOT</version>
<artifactId>msa</artifactId> <artifactId>msa</artifactId>
</parent> </parent>
<groupId>org.thingsboard.msa</groupId> <groupId>org.thingsboard.msa</groupId>

2
msa/vc-executor/pom.xml

@ -21,7 +21,7 @@
<parent> <parent>
<groupId>org.thingsboard</groupId> <groupId>org.thingsboard</groupId>
<version>3.4.3-SNAPSHOT</version> <version>3.4.4-SNAPSHOT</version>
<artifactId>msa</artifactId> <artifactId>msa</artifactId>
</parent> </parent>
<groupId>org.thingsboard.msa</groupId> <groupId>org.thingsboard.msa</groupId>

2
msa/web-ui/package.json

@ -1,7 +1,7 @@
{ {
"name": "thingsboard-web-ui", "name": "thingsboard-web-ui",
"private": true, "private": true,
"version": "3.4.3", "version": "3.4.4",
"description": "ThingsBoard Web UI Microservice", "description": "ThingsBoard Web UI Microservice",
"main": "server.ts", "main": "server.ts",
"bin": "server.js", "bin": "server.js",

2
msa/web-ui/pom.xml

@ -20,7 +20,7 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
<groupId>org.thingsboard</groupId> <groupId>org.thingsboard</groupId>
<version>3.4.3-SNAPSHOT</version> <version>3.4.4-SNAPSHOT</version>
<artifactId>msa</artifactId> <artifactId>msa</artifactId>
</parent> </parent>
<groupId>org.thingsboard.msa</groupId> <groupId>org.thingsboard.msa</groupId>

4
netty-mqtt/pom.xml

@ -19,11 +19,11 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
<groupId>org.thingsboard</groupId> <groupId>org.thingsboard</groupId>
<version>3.4.3-SNAPSHOT</version> <version>3.4.4-SNAPSHOT</version>
<artifactId>thingsboard</artifactId> <artifactId>thingsboard</artifactId>
</parent> </parent>
<artifactId>netty-mqtt</artifactId> <artifactId>netty-mqtt</artifactId>
<version>3.4.3-SNAPSHOT</version> <version>3.4.4-SNAPSHOT</version>
<packaging>jar</packaging> <packaging>jar</packaging>
<name>Netty MQTT Client</name> <name>Netty MQTT Client</name>

2
pom.xml

@ -20,7 +20,7 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<groupId>org.thingsboard</groupId> <groupId>org.thingsboard</groupId>
<artifactId>thingsboard</artifactId> <artifactId>thingsboard</artifactId>
<version>3.4.3-SNAPSHOT</version> <version>3.4.4-SNAPSHOT</version>
<packaging>pom</packaging> <packaging>pom</packaging>
<name>Thingsboard</name> <name>Thingsboard</name>

2
rest-client/pom.xml

@ -20,7 +20,7 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
<groupId>org.thingsboard</groupId> <groupId>org.thingsboard</groupId>
<version>3.4.3-SNAPSHOT</version> <version>3.4.4-SNAPSHOT</version>
<artifactId>thingsboard</artifactId> <artifactId>thingsboard</artifactId>
</parent> </parent>
<artifactId>rest-client</artifactId> <artifactId>rest-client</artifactId>

2
rule-engine/pom.xml

@ -20,7 +20,7 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
<groupId>org.thingsboard</groupId> <groupId>org.thingsboard</groupId>
<version>3.4.3-SNAPSHOT</version> <version>3.4.4-SNAPSHOT</version>
<artifactId>thingsboard</artifactId> <artifactId>thingsboard</artifactId>
</parent> </parent>
<artifactId>rule-engine</artifactId> <artifactId>rule-engine</artifactId>

2
rule-engine/rule-engine-api/pom.xml

@ -22,7 +22,7 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
<groupId>org.thingsboard</groupId> <groupId>org.thingsboard</groupId>
<version>3.4.3-SNAPSHOT</version> <version>3.4.4-SNAPSHOT</version>
<artifactId>rule-engine</artifactId> <artifactId>rule-engine</artifactId>
</parent> </parent>
<groupId>org.thingsboard.rule-engine</groupId> <groupId>org.thingsboard.rule-engine</groupId>

2
rule-engine/rule-engine-components/pom.xml

@ -22,7 +22,7 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
<groupId>org.thingsboard</groupId> <groupId>org.thingsboard</groupId>
<version>3.4.3-SNAPSHOT</version> <version>3.4.4-SNAPSHOT</version>
<artifactId>rule-engine</artifactId> <artifactId>rule-engine</artifactId>
</parent> </parent>
<groupId>org.thingsboard.rule-engine</groupId> <groupId>org.thingsboard.rule-engine</groupId>

2
tools/pom.xml

@ -20,7 +20,7 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
<groupId>org.thingsboard</groupId> <groupId>org.thingsboard</groupId>
<version>3.4.3-SNAPSHOT</version> <version>3.4.4-SNAPSHOT</version>
<artifactId>thingsboard</artifactId> <artifactId>thingsboard</artifactId>
</parent> </parent>
<artifactId>tools</artifactId> <artifactId>tools</artifactId>

2
transport/coap/pom.xml

@ -20,7 +20,7 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
<groupId>org.thingsboard</groupId> <groupId>org.thingsboard</groupId>
<version>3.4.3-SNAPSHOT</version> <version>3.4.4-SNAPSHOT</version>
<artifactId>transport</artifactId> <artifactId>transport</artifactId>
</parent> </parent>
<groupId>org.thingsboard.transport</groupId> <groupId>org.thingsboard.transport</groupId>

2
transport/http/pom.xml

@ -20,7 +20,7 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
<groupId>org.thingsboard</groupId> <groupId>org.thingsboard</groupId>
<version>3.4.3-SNAPSHOT</version> <version>3.4.4-SNAPSHOT</version>
<artifactId>transport</artifactId> <artifactId>transport</artifactId>
</parent> </parent>
<groupId>org.thingsboard.transport</groupId> <groupId>org.thingsboard.transport</groupId>

2
transport/lwm2m/pom.xml

@ -20,7 +20,7 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
<groupId>org.thingsboard</groupId> <groupId>org.thingsboard</groupId>
<version>3.4.3-SNAPSHOT</version> <version>3.4.4-SNAPSHOT</version>
<artifactId>transport</artifactId> <artifactId>transport</artifactId>
</parent> </parent>
<groupId>org.thingsboard.transport</groupId> <groupId>org.thingsboard.transport</groupId>

2
transport/mqtt/pom.xml

@ -20,7 +20,7 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
<groupId>org.thingsboard</groupId> <groupId>org.thingsboard</groupId>
<version>3.4.3-SNAPSHOT</version> <version>3.4.4-SNAPSHOT</version>
<artifactId>transport</artifactId> <artifactId>transport</artifactId>
</parent> </parent>
<groupId>org.thingsboard.transport</groupId> <groupId>org.thingsboard.transport</groupId>

2
transport/pom.xml

@ -20,7 +20,7 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
<groupId>org.thingsboard</groupId> <groupId>org.thingsboard</groupId>
<version>3.4.3-SNAPSHOT</version> <version>3.4.4-SNAPSHOT</version>
<artifactId>thingsboard</artifactId> <artifactId>thingsboard</artifactId>
</parent> </parent>
<artifactId>transport</artifactId> <artifactId>transport</artifactId>

2
transport/snmp/pom.xml

@ -21,7 +21,7 @@
<parent> <parent>
<groupId>org.thingsboard</groupId> <groupId>org.thingsboard</groupId>
<version>3.4.3-SNAPSHOT</version> <version>3.4.4-SNAPSHOT</version>
<artifactId>transport</artifactId> <artifactId>transport</artifactId>
</parent> </parent>

2
ui-ngx/package.json

@ -1,6 +1,6 @@
{ {
"name": "thingsboard", "name": "thingsboard",
"version": "3.4.3", "version": "3.4.4",
"scripts": { "scripts": {
"ng": "ng", "ng": "ng",
"start": "node --max_old_space_size=8048 ./node_modules/@angular/cli/bin/ng serve --configuration development --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",

2
ui-ngx/pom.xml

@ -20,7 +20,7 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
<groupId>org.thingsboard</groupId> <groupId>org.thingsboard</groupId>
<version>3.4.3-SNAPSHOT</version> <version>3.4.4-SNAPSHOT</version>
<artifactId>thingsboard</artifactId> <artifactId>thingsboard</artifactId>
</parent> </parent>
<groupId>org.thingsboard</groupId> <groupId>org.thingsboard</groupId>

1
ui-ngx/src/app/core/api/widget-subscription.ts

@ -204,6 +204,7 @@ export class WidgetSubscription implements IWidgetSubscription {
this.timeWindow = {}; this.timeWindow = {};
this.useDashboardTimewindow = options.useDashboardTimewindow; this.useDashboardTimewindow = options.useDashboardTimewindow;
this.useTimewindow = true; this.useTimewindow = true;
this.onTimewindowChangeFunction = options.onTimewindowChangeFunction || ((timewindow) => timewindow);
if (this.useDashboardTimewindow) { if (this.useDashboardTimewindow) {
this.timeWindowConfig = deepClone(options.dashboardTimewindow); this.timeWindowConfig = deepClone(options.dashboardTimewindow);
} else { } else {

22
ui-ngx/src/app/core/http/entity.service.ts

@ -869,8 +869,26 @@ export class EntityService {
}; };
aliasInfo.currentEntity = null; aliasInfo.currentEntity = null;
if (!aliasInfo.resolveMultiple && aliasInfo.entityFilter) { if (!aliasInfo.resolveMultiple && aliasInfo.entityFilter) {
return this.findSingleEntityInfoByEntityFilter(aliasInfo.entityFilter, let currentEntity: EntityInfo = null;
{ignoreLoading: true, ignoreErrors: true}).pipe( if (result.stateEntity && aliasInfo.entityFilter.type === AliasFilterType.singleEntity) {
if (stateParams) {
let targetParams = stateParams;
if (result.entityParamName && result.entityParamName.length) {
targetParams = stateParams[result.entityParamName];
}
if (targetParams && targetParams.entityId) {
currentEntity = {
id: targetParams.entityId.id,
entityType: targetParams.entityId.entityType as EntityType,
name: targetParams.entityName,
label: targetParams.entityLabel
};
}
}
}
const entityInfoObservable = currentEntity ? of(currentEntity) : this.findSingleEntityInfoByEntityFilter(aliasInfo.entityFilter,
{ignoreLoading: true, ignoreErrors: true});
return entityInfoObservable.pipe(
map((entity) => { map((entity) => {
aliasInfo.currentEntity = entity; aliasInfo.currentEntity = entity;
return aliasInfo; return aliasInfo;

51
ui-ngx/src/app/core/http/widget.service.ts

@ -16,7 +16,7 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { defaultHttpOptionsFromConfig, RequestConfig } from './http-utils'; import { defaultHttpOptionsFromConfig, RequestConfig } from './http-utils';
import { Observable, of, ReplaySubject, Subject } from 'rxjs'; import { Observable, of, ReplaySubject } from 'rxjs';
import { HttpClient } from '@angular/common/http'; import { HttpClient } from '@angular/common/http';
import { PageLink } from '@shared/models/page/page-link'; import { PageLink } from '@shared/models/page/page-link';
import { PageData } from '@shared/models/page/page-data'; import { PageData } from '@shared/models/page/page-data';
@ -43,15 +43,14 @@ import { ActivationEnd, Router } from '@angular/router';
}) })
export class WidgetService { export class WidgetService {
private widgetTypeUpdatedSubject = new Subject<WidgetType>();
private widgetsBundleDeletedSubject = new Subject<WidgetsBundle>();
private allWidgetsBundles: Array<WidgetsBundle>; private allWidgetsBundles: Array<WidgetsBundle>;
private systemWidgetsBundles: Array<WidgetsBundle>; private systemWidgetsBundles: Array<WidgetsBundle>;
private tenantWidgetsBundles: Array<WidgetsBundle>; private tenantWidgetsBundles: Array<WidgetsBundle>;
private widgetTypeInfosCache = new Map<string, Array<WidgetTypeInfo>>(); private widgetTypeInfosCache = new Map<string, Array<WidgetTypeInfo>>();
private widgetsInfoInMemoryCache = new Map<string, WidgetInfo>();
private loadWidgetsBundleCacheSubject: ReplaySubject<any>; private loadWidgetsBundleCacheSubject: ReplaySubject<any>;
constructor( constructor(
@ -117,7 +116,7 @@ export class WidgetService {
defaultHttpOptionsFromConfig(config)).pipe( defaultHttpOptionsFromConfig(config)).pipe(
tap(() => { tap(() => {
this.invalidateWidgetsBundleCache(); this.invalidateWidgetsBundleCache();
this.widgetsBundleDeletedSubject.next(widgetsBundle); this.widgetsBundleDeleted(widgetsBundle);
}) })
); );
} }
@ -217,7 +216,7 @@ export class WidgetService {
return this.http.post<WidgetTypeDetails>('/api/widgetType', widgetTypeDetails, return this.http.post<WidgetTypeDetails>('/api/widgetType', widgetTypeDetails,
defaultHttpOptionsFromConfig(config)).pipe( defaultHttpOptionsFromConfig(config)).pipe(
tap((savedWidgetType) => { tap((savedWidgetType) => {
this.widgetTypeUpdatedSubject.next(savedWidgetType); this.widgetTypeUpdated(savedWidgetType);
})); }));
} }
@ -226,7 +225,7 @@ export class WidgetService {
return this.http.post<WidgetTypeDetails>('/api/widgetType', widgetTypeDetails, return this.http.post<WidgetTypeDetails>('/api/widgetType', widgetTypeDetails,
defaultHttpOptionsFromConfig(config)).pipe( defaultHttpOptionsFromConfig(config)).pipe(
tap((savedWidgetType) => { tap((savedWidgetType) => {
this.widgetTypeUpdatedSubject.next(savedWidgetType); this.widgetTypeUpdated(savedWidgetType);
})); }));
} }
@ -237,7 +236,7 @@ export class WidgetService {
return this.http.delete(`/api/widgetType/${widgetTypeInstance.id.id}`, return this.http.delete(`/api/widgetType/${widgetTypeInstance.id.id}`,
defaultHttpOptionsFromConfig(config)).pipe( defaultHttpOptionsFromConfig(config)).pipe(
tap(() => { tap(() => {
this.widgetTypeUpdatedSubject.next(widgetTypeInstance); this.widgetTypeUpdated(widgetTypeInstance);
}) })
); );
} }
@ -263,12 +262,40 @@ export class WidgetService {
); );
} }
public onWidgetTypeUpdated(): Observable<WidgetType> { public createWidgetInfoCacheKey(bundleAlias: string, widgetTypeAlias: string, isSystem: boolean): string {
return this.widgetTypeUpdatedSubject.asObservable(); return `${isSystem ? 'sys_' : ''}${bundleAlias}_${widgetTypeAlias}`;
}
public getWidgetInfoFromCache(bundleAlias: string, widgetTypeAlias: string, isSystem: boolean): WidgetInfo | undefined {
const key = this.createWidgetInfoCacheKey(bundleAlias, widgetTypeAlias, isSystem);
return this.widgetsInfoInMemoryCache.get(key);
} }
public onWidgetBundleDeleted(): Observable<WidgetsBundle> { public putWidgetInfoToCache(widgetInfo: WidgetInfo, bundleAlias: string, widgetTypeAlias: string, isSystem: boolean) {
return this.widgetsBundleDeletedSubject.asObservable(); const key = this.createWidgetInfoCacheKey(bundleAlias, widgetTypeAlias, isSystem);
this.widgetsInfoInMemoryCache.set(key, widgetInfo);
}
private widgetTypeUpdated(updatedWidgetType: WidgetType): void {
this.deleteWidgetInfoFromCache(updatedWidgetType.bundleAlias, updatedWidgetType.alias, updatedWidgetType.tenantId.id === NULL_UUID);
}
private widgetsBundleDeleted(widgetsBundle: WidgetsBundle): void {
this.deleteWidgetsBundleFromCache(widgetsBundle.alias, widgetsBundle.tenantId.id === NULL_UUID);
}
private deleteWidgetInfoFromCache(bundleAlias: string, widgetTypeAlias: string, isSystem: boolean) {
const key = this.createWidgetInfoCacheKey(bundleAlias, widgetTypeAlias, isSystem);
this.widgetsInfoInMemoryCache.delete(key);
}
private deleteWidgetsBundleFromCache(bundleAlias: string, isSystem: boolean) {
const key = (isSystem ? 'sys_' : '') + bundleAlias;
this.widgetsInfoInMemoryCache.forEach((widgetInfo, cacheKey) => {
if (cacheKey.startsWith(key)) {
this.widgetsInfoInMemoryCache.delete(cacheKey);
}
});
} }
private loadWidgetsBundleCache(config?: RequestConfig): Observable<any> { private loadWidgetsBundleCache(config?: RequestConfig): Observable<any> {

12
ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.html

@ -135,7 +135,7 @@
(click)="openDashboardSettings($event)"> (click)="openDashboardSettings($event)">
<mat-icon>settings</mat-icon> <mat-icon>settings</mat-icon>
</button> </button>
<tb-dashboard-select [fxShow]="!isEdit && !widgetEditMode && !embedded && displayDashboardsSelect()" <tb-dashboard-select *ngIf="!isEdit && !widgetEditMode && !embedded && displayDashboardsSelect()"
[(ngModel)]="currentDashboardId" [(ngModel)]="currentDashboardId"
(ngModelChange)="currentDashboardIdChanged(currentDashboardId)" (ngModelChange)="currentDashboardIdChanged(currentDashboardId)"
[customerId]="currentCustomerId" [customerId]="currentCustomerId"
@ -168,9 +168,9 @@
[ngClass]="{ 'tb-shrinked' : isEditingWidget }"> [ngClass]="{ 'tb-shrinked' : isEditingWidget }">
<mat-drawer *ngIf="layouts.right.show" <mat-drawer *ngIf="layouts.right.show"
id="tb-right-layout" id="tb-right-layout"
[ngStyle]="{minWidth: rightLayoutWidth(), [ngStyle]="{minWidth: rightLayoutSize.width,
maxWidth: rightLayoutWidth(), maxWidth: rightLayoutSize.width,
height: rightLayoutHeight(), height: rightLayoutSize.height,
borderLeft: 'none'}" borderLeft: 'none'}"
disableClose="true" disableClose="true"
[@.disabled]="!isMobile" [@.disabled]="!isMobile"
@ -191,8 +191,8 @@
</mat-drawer> </mat-drawer>
<mat-drawer-content [fxShow]="layouts.main.show" <mat-drawer-content [fxShow]="layouts.main.show"
id="tb-main-layout" id="tb-main-layout"
[ngStyle]="{width: mainLayoutWidth(), [ngStyle]="{width: mainLayoutSize.width,
height: mainLayoutHeight()}"> height: mainLayoutSize.height}">
<tb-dashboard-layout <tb-dashboard-layout
[dashboardCheatSheet]="cheatSheetComponent" [dashboardCheatSheet]="cheatSheetComponent"
[layoutCtx]="layouts.main.layoutCtx" [layoutCtx]="layouts.main.layoutCtx"

76
ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.ts

@ -15,6 +15,7 @@
/// ///
import { import {
AfterViewInit,
ChangeDetectionStrategy, ChangeDetectionStrategy,
ChangeDetectorRef, ChangeDetectorRef,
Component, Component,
@ -56,7 +57,8 @@ import { WINDOW } from '@core/services/window.service';
import { WindowMessage } from '@shared/models/window-message.model'; import { WindowMessage } from '@shared/models/window-message.model';
import { deepClone, guid, isDefined, isDefinedAndNotNull, isNotEmptyStr } from '@app/core/utils'; import { deepClone, guid, isDefined, isDefinedAndNotNull, isNotEmptyStr } from '@app/core/utils';
import { import {
DashboardContext, DashboardPageInitData, DashboardContext,
DashboardPageInitData,
DashboardPageLayout, DashboardPageLayout,
DashboardPageLayoutContext, DashboardPageLayoutContext,
DashboardPageLayouts, DashboardPageLayouts,
@ -148,6 +150,7 @@ import { TbPopoverService } from '@shared/components/popover.service';
import { tap } from 'rxjs/operators'; import { tap } from 'rxjs/operators';
import { LayoutFixedSize, LayoutWidthType } from '@home/components/dashboard-page/layout/layout.models'; import { LayoutFixedSize, LayoutWidthType } from '@home/components/dashboard-page/layout/layout.models';
import { TbPopoverComponent } from '@shared/components/popover.component'; import { TbPopoverComponent } from '@shared/components/popover.component';
import { ResizeObserver } from '@juggle/resize-observer';
// @dynamic // @dynamic
@Component({ @Component({
@ -157,7 +160,7 @@ import { TbPopoverComponent } from '@shared/components/popover.component';
encapsulation: ViewEncapsulation.None, encapsulation: ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush changeDetection: ChangeDetectionStrategy.OnPush
}) })
export class DashboardPageComponent extends PageComponent implements IDashboardController, OnInit, OnDestroy { export class DashboardPageComponent extends PageComponent implements IDashboardController, OnInit, AfterViewInit, OnDestroy {
authState: AuthState = getCurrentAuthState(this.store); authState: AuthState = getCurrentAuthState(this.store);
@ -244,9 +247,14 @@ export class DashboardPageComponent extends PageComponent implements IDashboardC
addingLayoutCtx: DashboardPageLayoutContext; addingLayoutCtx: DashboardPageLayoutContext;
mainLayoutSize: {width: string; height: string} = {width: '100%', height: '100%'};
rightLayoutSize: {width: string; height: string} = {width: '100%', height: '100%'};
private dashboardLogoCache: SafeUrl; private dashboardLogoCache: SafeUrl;
private defaultDashboardLogo = 'assets/logo_title_white.svg'; private defaultDashboardLogo = 'assets/logo_title_white.svg';
private dashboardResize$: ResizeObserver;
dashboardCtx: DashboardContext = { dashboardCtx: DashboardContext = {
instanceId: this.utils.guid(), instanceId: this.utils.guid(),
getDashboard: () => this.dashboard, getDashboard: () => this.dashboard,
@ -402,6 +410,7 @@ export class DashboardPageComponent extends PageComponent implements IDashboardC
.observe(MediaBreakpoints['gt-sm']) .observe(MediaBreakpoints['gt-sm'])
.subscribe((state: BreakpointState) => { .subscribe((state: BreakpointState) => {
this.isMobile = !state.matches; this.isMobile = !state.matches;
this.updateLayoutSizes();
} }
)); ));
if (this.isMobileApp && this.syncStateWithQueryParam) { if (this.isMobileApp && this.syncStateWithQueryParam) {
@ -414,6 +423,13 @@ export class DashboardPageComponent extends PageComponent implements IDashboardC
} }
} }
ngAfterViewInit() {
this.dashboardResize$ = new ResizeObserver(() => {
this.updateLayoutSizes();
});
this.dashboardResize$.observe(this.dashboardContainer.nativeElement);
}
private init(data: DashboardPageInitData) { private init(data: DashboardPageInitData) {
this.reset(); this.reset();
@ -537,6 +553,9 @@ export class DashboardPageComponent extends PageComponent implements IDashboardC
subscription.unsubscribe(); subscription.unsubscribe();
}); });
this.rxSubscriptions.length = 0; this.rxSubscriptions.length = 0;
if (this.dashboardResize$) {
this.dashboardResize$.disconnect();
}
} }
public runChangeDetection() { public runChangeDetection() {
@ -679,28 +698,48 @@ export class DashboardPageComponent extends PageComponent implements IDashboardC
this.mobileService.onDashboardRightLayoutChanged(this.isRightLayoutOpened); this.mobileService.onDashboardRightLayoutChanged(this.isRightLayoutOpened);
} }
public mainLayoutWidth(): string { private updateLayoutSizes() {
if (this.isEditingWidget && this.editingLayoutCtx.id === 'main') { let changeMainLayoutSize = false;
return '100%'; let changeRightLayoutSize = false;
} else { if (this.dashboardCtx.state) {
return this.layouts.right.show && !this.isMobile ? this.calculateWidth('main') : '100%'; changeMainLayoutSize = this.updateMainLayoutSize();
changeRightLayoutSize = this.updateRightLayoutSize();
}
if (changeMainLayoutSize || changeRightLayoutSize) {
this.cd.markForCheck();
} }
} }
public mainLayoutHeight(): string { private updateMainLayoutSize(): boolean {
const prevMainLayoutWidth = this.mainLayoutSize.width;
const prevMainLayoutHeight = this.mainLayoutSize.height;
if (this.isEditingWidget && this.editingLayoutCtx.id === 'main') {
this.mainLayoutSize.width = '100%';
} else {
this.mainLayoutSize.width = this.layouts.right.show && !this.isMobile ? this.calculateWidth('main') : '100%';
}
if (!this.isEditingWidget || this.editingLayoutCtx.id === 'main') { if (!this.isEditingWidget || this.editingLayoutCtx.id === 'main') {
return '100%'; this.mainLayoutSize.height = '100%';
} else { } else {
return '0px'; this.mainLayoutSize.height = '0px';
} }
return prevMainLayoutWidth !== this.mainLayoutSize.width || prevMainLayoutHeight !== this.mainLayoutSize.height;
} }
public rightLayoutWidth(): string { private updateRightLayoutSize(): boolean {
const prevRightLayoutWidth = this.rightLayoutSize.width;
const prevRightLayoutHeight = this.rightLayoutSize.height;
if (this.isEditingWidget && this.editingLayoutCtx.id === 'right') { if (this.isEditingWidget && this.editingLayoutCtx.id === 'right') {
return '100%'; this.rightLayoutSize.width = '100%';
} else {
this.rightLayoutSize.width = this.isMobile ? '100%' : this.calculateWidth('right');
}
if (!this.isEditingWidget || this.editingLayoutCtx.id === 'right') {
this.rightLayoutSize.height = '100%';
} else { } else {
return this.isMobile ? '100%' : this.calculateWidth('right'); this.rightLayoutSize.height = '0px';
} }
return prevRightLayoutWidth !== this.rightLayoutSize.width || prevRightLayoutHeight !== this.rightLayoutSize.height;
} }
private calculateWidth(layout: DashboardLayoutId): string { private calculateWidth(layout: DashboardLayoutId): string {
@ -743,14 +782,6 @@ export class DashboardPageComponent extends PageComponent implements IDashboardC
} }
} }
public rightLayoutHeight(): string {
if (!this.isEditingWidget || this.editingLayoutCtx.id === 'right') {
return '100%';
} else {
return '0px';
}
}
public isPublicUser(): boolean { public isPublicUser(): boolean {
return this.authUser.isPublic; return this.authUser.isPublic;
} }
@ -977,6 +1008,7 @@ export class DashboardPageComponent extends PageComponent implements IDashboardC
layout.layoutCtx.ctrl.reload(); layout.layoutCtx.ctrl.reload();
} }
layout.layoutCtx.ignoreLoading = true; layout.layoutCtx.ignoreLoading = true;
this.updateLayoutSizes();
} }
private setEditMode(isEdit: boolean, revert: boolean) { private setEditMode(isEdit: boolean, revert: boolean) {
@ -1191,6 +1223,7 @@ export class DashboardPageComponent extends PageComponent implements IDashboardC
this.editingLayoutCtx = null; this.editingLayoutCtx = null;
this.editingWidgetSubtitle = null; this.editingWidgetSubtitle = null;
this.isEditingWidget = false; this.isEditingWidget = false;
this.updateLayoutSizes();
this.resetHighlight(); this.resetHighlight();
this.forceDashboardMobileMode = false; this.forceDashboardMobileMode = false;
} }
@ -1216,6 +1249,7 @@ export class DashboardPageComponent extends PageComponent implements IDashboardC
this.editingWidgetSubtitle = this.widgetComponentService.getInstantWidgetInfo(this.editingWidget).widgetName; this.editingWidgetSubtitle = this.widgetComponentService.getInstantWidgetInfo(this.editingWidget).widgetName;
this.forceDashboardMobileMode = true; this.forceDashboardMobileMode = true;
this.isEditingWidget = true; this.isEditingWidget = true;
this.updateLayoutSizes();
if (layoutCtx) { if (layoutCtx) {
const delayOffset = transition ? 350 : 0; const delayOffset = transition ? 350 : 0;
const delay = transition ? 400 : 300; const delay = transition ? 400 : 300;

1
ui-ngx/src/app/modules/home/components/dashboard-page/layout/manage-dashboard-layouts-dialog.component.ts

@ -297,6 +297,7 @@ export class ManageDashboardLayoutsDialogComponent extends DialogComponent<Manag
setFixedLayout(layout: string): void { setFixedLayout(layout: string): void {
if (this.layoutsFormGroup.get('type').value === LayoutWidthType.FIXED && this.layoutsFormGroup.get('right').value) { if (this.layoutsFormGroup.get('type').value === LayoutWidthType.FIXED && this.layoutsFormGroup.get('right').value) {
this.layoutsFormGroup.get('fixedLayout').setValue(layout); this.layoutsFormGroup.get('fixedLayout').setValue(layout);
this.layoutsFormGroup.get('fixedLayout').markAsDirty();
} }
} }

53
ui-ngx/src/app/modules/home/components/widget/widget-component.service.ts

@ -50,14 +50,11 @@ import { widgetSettingsComponentsMap } from '@home/components/widget/lib/setting
const tinycolor = tinycolor_; const tinycolor = tinycolor_;
// @dynamic
@Injectable() @Injectable()
export class WidgetComponentService { export class WidgetComponentService {
private cssParser = new cssjs(); private cssParser = new cssjs();
private widgetsInfoInMemoryCache = new Map<string, WidgetInfo>();
private widgetsInfoFetchQueue = new Map<string, Array<Subject<WidgetInfo>>>(); private widgetsInfoFetchQueue = new Map<string, Array<Subject<WidgetInfo>>>();
private init$: Observable<any>; private init$: Observable<any>;
@ -77,14 +74,6 @@ export class WidgetComponentService {
this.cssParser.testMode = false; this.cssParser.testMode = false;
this.widgetService.onWidgetTypeUpdated().subscribe((widgetType) => {
this.deleteWidgetInfoFromCache(widgetType.bundleAlias, widgetType.alias, widgetType.tenantId.id === NULL_UUID);
});
this.widgetService.onWidgetBundleDeleted().subscribe((widgetsBundle) => {
this.deleteWidgetsBundleFromCache(widgetsBundle.alias, widgetsBundle.tenantId.id === NULL_UUID);
});
this.init(); this.init();
} }
@ -223,7 +212,7 @@ export class WidgetComponentService {
} }
public getInstantWidgetInfo(widget: Widget): WidgetInfo { public getInstantWidgetInfo(widget: Widget): WidgetInfo {
const widgetInfo = this.getWidgetInfoFromCache(widget.bundleAlias, widget.typeAlias, widget.isSystemType); const widgetInfo = this.widgetService.getWidgetInfoFromCache(widget.bundleAlias, widget.typeAlias, widget.isSystemType);
if (widgetInfo) { if (widgetInfo) {
return widgetInfo; return widgetInfo;
} else { } else {
@ -239,7 +228,7 @@ export class WidgetComponentService {
private getWidgetInfoInternal(bundleAlias: string, widgetTypeAlias: string, isSystem: boolean): Observable<WidgetInfo> { private getWidgetInfoInternal(bundleAlias: string, widgetTypeAlias: string, isSystem: boolean): Observable<WidgetInfo> {
const widgetInfoSubject = new ReplaySubject<WidgetInfo>(); const widgetInfoSubject = new ReplaySubject<WidgetInfo>();
const widgetInfo = this.getWidgetInfoFromCache(bundleAlias, widgetTypeAlias, isSystem); const widgetInfo = this.widgetService.getWidgetInfoFromCache(bundleAlias, widgetTypeAlias, isSystem);
if (widgetInfo) { if (widgetInfo) {
widgetInfoSubject.next(widgetInfo); widgetInfoSubject.next(widgetInfo);
widgetInfoSubject.complete(); widgetInfoSubject.complete();
@ -247,7 +236,7 @@ export class WidgetComponentService {
if (this.utils.widgetEditMode) { if (this.utils.widgetEditMode) {
this.loadWidget(this.editingWidgetType, bundleAlias, isSystem, widgetInfoSubject); this.loadWidget(this.editingWidgetType, bundleAlias, isSystem, widgetInfoSubject);
} else { } else {
const key = this.createWidgetInfoCacheKey(bundleAlias, widgetTypeAlias, isSystem); const key = this.widgetService.createWidgetInfoCacheKey(bundleAlias, widgetTypeAlias, isSystem);
let fetchQueue = this.widgetsInfoFetchQueue.get(key); let fetchQueue = this.widgetsInfoFetchQueue.get(key);
if (fetchQueue) { if (fetchQueue) {
fetchQueue.push(widgetInfoSubject); fetchQueue.push(widgetInfoSubject);
@ -272,7 +261,7 @@ export class WidgetComponentService {
private loadWidget(widgetType: WidgetType, bundleAlias: string, isSystem: boolean, widgetInfoSubject: Subject<WidgetInfo>) { private loadWidget(widgetType: WidgetType, bundleAlias: string, isSystem: boolean, widgetInfoSubject: Subject<WidgetInfo>) {
const widgetInfo = toWidgetInfo(widgetType); const widgetInfo = toWidgetInfo(widgetType);
const key = this.createWidgetInfoCacheKey(bundleAlias, widgetInfo.alias, isSystem); const key = this.widgetService.createWidgetInfoCacheKey(bundleAlias, widgetInfo.alias, isSystem);
let widgetControllerDescriptor: WidgetControllerDescriptor = null; let widgetControllerDescriptor: WidgetControllerDescriptor = null;
try { try {
widgetControllerDescriptor = this.createWidgetControllerDescriptor(widgetInfo, key); widgetControllerDescriptor = this.createWidgetControllerDescriptor(widgetInfo, key);
@ -297,7 +286,7 @@ export class WidgetComponentService {
widgetInfo.typeParameters = widgetControllerDescriptor.typeParameters; widgetInfo.typeParameters = widgetControllerDescriptor.typeParameters;
widgetInfo.actionSources = widgetControllerDescriptor.actionSources; widgetInfo.actionSources = widgetControllerDescriptor.actionSources;
widgetInfo.widgetTypeFunction = widgetControllerDescriptor.widgetTypeFunction; widgetInfo.widgetTypeFunction = widgetControllerDescriptor.widgetTypeFunction;
this.putWidgetInfoToCache(widgetInfo, bundleAlias, widgetInfo.alias, isSystem); this.widgetService.putWidgetInfoToCache(widgetInfo, bundleAlias, widgetInfo.alias, isSystem);
if (widgetInfoSubject) { if (widgetInfoSubject) {
widgetInfoSubject.next(widgetInfo); widgetInfoSubject.next(widgetInfo);
widgetInfoSubject.complete(); widgetInfoSubject.complete();
@ -331,7 +320,7 @@ export class WidgetComponentService {
(resource) => { (resource) => {
resourceTasks.push( resourceTasks.push(
this.resources.loadResource(resource.url).pipe( this.resources.loadResource(resource.url).pipe(
catchError(e => of(`Failed to load widget resource: '${resource.url}'`)) catchError(() => of(`Failed to load widget resource: '${resource.url}'`))
) )
); );
} }
@ -586,34 +575,4 @@ export class WidgetComponentService {
this.widgetsInfoFetchQueue.delete(key); this.widgetsInfoFetchQueue.delete(key);
} }
} }
// Cache functions
private createWidgetInfoCacheKey(bundleAlias: string, widgetTypeAlias: string, isSystem: boolean): string {
return `${isSystem ? 'sys_' : ''}${bundleAlias}_${widgetTypeAlias}`;
}
private getWidgetInfoFromCache(bundleAlias: string, widgetTypeAlias: string, isSystem: boolean): WidgetInfo | undefined {
const key = this.createWidgetInfoCacheKey(bundleAlias, widgetTypeAlias, isSystem);
return this.widgetsInfoInMemoryCache.get(key);
}
private putWidgetInfoToCache(widgetInfo: WidgetInfo, bundleAlias: string, widgetTypeAlias: string, isSystem: boolean) {
const key = this.createWidgetInfoCacheKey(bundleAlias, widgetTypeAlias, isSystem);
this.widgetsInfoInMemoryCache.set(key, widgetInfo);
}
private deleteWidgetInfoFromCache(bundleAlias: string, widgetTypeAlias: string, isSystem: boolean) {
const key = this.createWidgetInfoCacheKey(bundleAlias, widgetTypeAlias, isSystem);
this.widgetsInfoInMemoryCache.delete(key);
}
private deleteWidgetsBundleFromCache(bundleAlias: string, isSystem: boolean) {
const key = (isSystem ? 'sys_' : '') + bundleAlias;
this.widgetsInfoInMemoryCache.forEach((widgetInfo, cacheKey) => {
if (cacheKey.startsWith(key)) {
this.widgetsInfoInMemoryCache.delete(cacheKey);
}
});
}
} }

Loading…
Cancel
Save