diff --git a/application/pom.xml b/application/pom.xml index 17b179c767..ef57037448 100644 --- a/application/pom.xml +++ b/application/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.9.0-SNAPSHOT + 3.9.0-RC thingsboard application 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 8470566af3..2d868a1135 100644 --- a/application/src/main/java/org/thingsboard/server/controller/BaseController.java +++ b/application/src/main/java/org/thingsboard/server/controller/BaseController.java @@ -19,6 +19,7 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.node.ObjectNode; import com.google.common.util.concurrent.ListenableFuture; import jakarta.mail.MessagingException; +import jakarta.servlet.ServletOutputStream; import jakarta.servlet.http.HttpServletResponse; import jakarta.validation.ConstraintViolation; import lombok.Getter; @@ -28,6 +29,7 @@ import org.slf4j.Logger; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.dao.DataAccessException; +import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; @@ -182,7 +184,9 @@ import org.thingsboard.server.service.sync.vc.EntitiesVersionControlService; import org.thingsboard.server.service.telemetry.AlarmSubscriptionService; import org.thingsboard.server.service.telemetry.TelemetrySubscriptionService; +import java.io.IOException; import java.net.URI; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -194,6 +198,7 @@ import java.util.function.BiConsumer; import java.util.function.BiFunction; import java.util.function.Function; import java.util.stream.Collectors; +import java.util.zip.GZIPOutputStream; import static org.thingsboard.server.common.data.StringUtils.isNotEmpty; import static org.thingsboard.server.common.data.query.EntityKeyType.ENTITY_FIELD; @@ -1008,6 +1013,22 @@ public abstract class BaseController { } } + protected void compressResponseWithGzipIFAccepted(String acceptEncodingHeader, HttpServletResponse response, byte[] content) throws IOException { + if (StringUtils.isNotEmpty(acceptEncodingHeader) && acceptEncodingHeader.contains("gzip")) { + response.setHeader(HttpHeaders.CONTENT_ENCODING, "gzip"); + response.setCharacterEncoding(StandardCharsets.UTF_8.displayName()); + try (GZIPOutputStream gzipOutputStream = new GZIPOutputStream(response.getOutputStream())) { + gzipOutputStream.write(content); + gzipOutputStream.finish(); + } + } else { + try (ServletOutputStream outputStream = response.getOutputStream()) { + outputStream.write(content); + outputStream.flush(); + } + } + } + protected ResponseEntity response(HttpStatus status) { return ResponseEntity.status(status).build(); } 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 e3e793014d..e50484bed3 100644 --- a/application/src/main/java/org/thingsboard/server/controller/DashboardController.java +++ b/application/src/main/java/org/thingsboard/server/controller/DashboardController.java @@ -22,8 +22,10 @@ import io.swagger.v3.oas.annotations.media.Content; import io.swagger.v3.oas.annotations.media.ExampleObject; import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.responses.ApiResponse; +import jakarta.servlet.http.HttpServletResponse; import lombok.RequiredArgsConstructor; import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.DeleteMapping; @@ -31,6 +33,7 @@ import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestHeader; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; @@ -67,6 +70,7 @@ import java.util.Set; import java.util.UUID; import java.util.stream.Collectors; +import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; 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; @@ -149,17 +153,20 @@ public class DashboardController extends BaseController { ) @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @GetMapping(value = "/dashboard/{dashboardId}") - public Dashboard getDashboardById(@Parameter(description = DASHBOARD_ID_PARAM_DESCRIPTION) + public void getDashboardById(@Parameter(description = DASHBOARD_ID_PARAM_DESCRIPTION) @PathVariable(DASHBOARD_ID) String strDashboardId, @Parameter(description = INCLUDE_RESOURCES_DESCRIPTION) - @RequestParam(value = INCLUDE_RESOURCES, required = false) boolean includeResources) throws ThingsboardException { + @RequestParam(value = INCLUDE_RESOURCES, required = false) boolean includeResources, + @RequestHeader(name = HttpHeaders.ACCEPT_ENCODING, required = false) String acceptEncodingHeader, + HttpServletResponse response) throws Exception { checkParameter(DASHBOARD_ID, strDashboardId); DashboardId dashboardId = new DashboardId(toUUID(strDashboardId)); Dashboard dashboard = checkDashboardId(dashboardId, Operation.READ); if (includeResources) { dashboard.setResources(tbResourceService.exportResources(dashboard, getCurrentUser())); } - return dashboard; + response.setContentType(APPLICATION_JSON_VALUE); + compressResponseWithGzipIFAccepted(acceptEncodingHeader, response, JacksonUtil.writeValueAsBytes(dashboard)); } @ApiOperation(value = "Create Or Update Dashboard (saveDashboard)", @@ -171,11 +178,15 @@ public class DashboardController extends BaseController { TENANT_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAuthority('TENANT_ADMIN')") @PostMapping(value = "/dashboard") - public Dashboard saveDashboard(@io.swagger.v3.oas.annotations.parameters.RequestBody(description = "A JSON value representing the dashboard.") - @RequestBody Dashboard dashboard) throws Exception { + public void saveDashboard(@io.swagger.v3.oas.annotations.parameters.RequestBody(description = "A JSON value representing the dashboard.") + @RequestBody Dashboard dashboard, + @RequestHeader(name = HttpHeaders.ACCEPT_ENCODING, required = false) String acceptEncodingHeader, + HttpServletResponse response) throws Exception { dashboard.setTenantId(getTenantId()); checkEntity(dashboard.getId(), dashboard, Resource.DASHBOARD); - return tbDashboardService.save(dashboard, getCurrentUser()); + var savedDashboard = tbDashboardService.save(dashboard, getCurrentUser()); + response.setContentType(APPLICATION_JSON_VALUE); + compressResponseWithGzipIFAccepted(acceptEncodingHeader, response, JacksonUtil.writeValueAsBytes(savedDashboard)); } @ApiOperation(value = "Delete the Dashboard (deleteDashboard)", @@ -408,12 +419,13 @@ public class DashboardController extends BaseController { "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 + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") - @RequestMapping(value = "/dashboard/home", method = RequestMethod.GET) - @ResponseBody - public HomeDashboard getHomeDashboard() throws ThingsboardException { + @GetMapping(value = "/dashboard/home") + public void getHomeDashboard(@RequestHeader(name = HttpHeaders.ACCEPT_ENCODING, required = false) String acceptEncodingHeader, + HttpServletResponse response) throws Exception { SecurityUser securityUser = getCurrentUser(); + response.setContentType(APPLICATION_JSON_VALUE); if (securityUser.isSystemAdmin()) { - return null; + return; } User user = userService.findUserById(securityUser.getTenantId(), securityUser.getId()); JsonNode additionalInfo = user.getAdditionalInfo(); @@ -431,7 +443,9 @@ public class DashboardController extends BaseController { homeDashboard = extractHomeDashboardFromAdditionalInfo(additionalInfo); } } - return homeDashboard; + if (homeDashboard != null) { + compressResponseWithGzipIFAccepted(acceptEncodingHeader, response, JacksonUtil.writeValueAsBytes(homeDashboard)); + } } @ApiOperation(value = "Get Home Dashboard Info (getHomeDashboardInfo)", diff --git a/application/src/main/java/org/thingsboard/server/controller/ImageController.java b/application/src/main/java/org/thingsboard/server/controller/ImageController.java index cd1116a420..5a7bd19d8e 100644 --- a/application/src/main/java/org/thingsboard/server/controller/ImageController.java +++ b/application/src/main/java/org/thingsboard/server/controller/ImageController.java @@ -61,7 +61,9 @@ import org.thingsboard.server.service.security.model.SecurityUser; import org.thingsboard.server.service.security.permission.Operation; import org.thingsboard.server.service.security.permission.Resource; +import java.io.ByteArrayOutputStream; import java.util.concurrent.TimeUnit; +import java.util.zip.GZIPOutputStream; import static org.thingsboard.server.controller.ControllerConstants.PAGE_NUMBER_DESCRIPTION; import static org.thingsboard.server.controller.ControllerConstants.PAGE_SIZE_DESCRIPTION; @@ -70,6 +72,7 @@ import static org.thingsboard.server.controller.ControllerConstants.RESOURCE_INC import static org.thingsboard.server.controller.ControllerConstants.RESOURCE_TEXT_SEARCH_DESCRIPTION; 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.dao.util.ImageUtils.mediaTypeToFileExtension; @Slf4j @RestController @@ -179,15 +182,17 @@ public class ImageController extends BaseController { @PathVariable String type, @Parameter(description = IMAGE_KEY_PARAM_DESCRIPTION, required = true) @PathVariable String key, - @RequestHeader(name = HttpHeaders.IF_NONE_MATCH, required = false) String etag) throws Exception { - return downloadIfChanged(type, key, etag, false); + @RequestHeader(name = HttpHeaders.IF_NONE_MATCH, required = false) String etag, + @RequestHeader(name = HttpHeaders.ACCEPT_ENCODING, required = false) String acceptEncodingHeader) throws Exception { + return downloadIfChanged(type, key, etag, acceptEncodingHeader, false); } @GetMapping(value = "/api/images/public/{publicResourceKey}", produces = "image/*") public ResponseEntity downloadPublicImage(@PathVariable String publicResourceKey, - @RequestHeader(name = HttpHeaders.IF_NONE_MATCH, required = false) String etag) throws Exception { + @RequestHeader(name = HttpHeaders.IF_NONE_MATCH, required = false) String etag, + @RequestHeader(name = HttpHeaders.ACCEPT_ENCODING, required = false) String acceptEncodingHeader) throws Exception { ImageCacheKey cacheKey = ImageCacheKey.forPublicImage(publicResourceKey); - return downloadIfChanged(cacheKey, etag, () -> imageService.getPublicImageInfoByKey(publicResourceKey)); + return downloadIfChanged(cacheKey, etag, acceptEncodingHeader, () -> imageService.getPublicImageInfoByKey(publicResourceKey)); } @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") @@ -213,8 +218,9 @@ public class ImageController extends BaseController { @PathVariable String type, @Parameter(description = IMAGE_KEY_PARAM_DESCRIPTION, required = true) @PathVariable String key, - @RequestHeader(name = HttpHeaders.IF_NONE_MATCH, required = false) String etag) throws Exception { - return downloadIfChanged(type, key, etag, true); + @RequestHeader(name = HttpHeaders.IF_NONE_MATCH, required = false) String etag, + @RequestHeader(name = HttpHeaders.ACCEPT_ENCODING, required = false) String acceptEncodingHeader) throws Exception { + return downloadIfChanged(type, key, etag, acceptEncodingHeader, true); } @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") @@ -268,12 +274,12 @@ public class ImageController extends BaseController { return (result.isSuccess() ? ResponseEntity.ok() : ResponseEntity.badRequest()).body(result); } - private ResponseEntity downloadIfChanged(String type, String key, String etag, boolean preview) throws Exception { + private ResponseEntity downloadIfChanged(String type, String key, String etag, String acceptEncodingHeader, boolean preview) throws Exception { ImageCacheKey cacheKey = ImageCacheKey.forImage(getTenantId(type), key, preview); - return downloadIfChanged(cacheKey, etag, () -> checkImageInfo(type, key, Operation.READ)); + return downloadIfChanged(cacheKey, etag, acceptEncodingHeader, () -> checkImageInfo(type, key, Operation.READ)); } - private ResponseEntity downloadIfChanged(ImageCacheKey cacheKey, String etag, ThrowingSupplier imageInfoSupplier) throws Exception { + private ResponseEntity downloadIfChanged(ImageCacheKey cacheKey, String etag, String acceptEncodingHeader, ThrowingSupplier imageInfoSupplier) throws Exception { if (StringUtils.isNotEmpty(etag)) { etag = StringUtils.remove(etag, '\"'); // etag is wrapped in double quotes due to HTTP specification if (etag.equals(tbImageService.getETag(cacheKey))) { @@ -294,7 +300,6 @@ public class ImageController extends BaseController { tbImageService.putETag(cacheKey, descriptor.getEtag()); var result = ResponseEntity.ok() .header("Content-Type", descriptor.getMediaType()) - .contentLength(data.length) .eTag(descriptor.getEtag()); if (!cacheKey.isPublic()) { result @@ -308,7 +313,19 @@ public class ImageController extends BaseController { } else { result.cacheControl(CacheControl.noCache()); } - return result.body(new ByteArrayResource(data)); + var responseData = data; + if (mediaTypeToFileExtension(descriptor.getMediaType()).equals("svg") && + StringUtils.isNotEmpty(acceptEncodingHeader) && acceptEncodingHeader.contains("gzip")) { + result.header(HttpHeaders.CONTENT_ENCODING, "gzip"); + var outputStream = new ByteArrayOutputStream(); + try (GZIPOutputStream gzipOutputStream = new GZIPOutputStream(outputStream)) { + gzipOutputStream.write(data); + gzipOutputStream.finish(); + } + responseData = outputStream.toByteArray(); + } + result.contentLength(responseData.length); + return result.body(new ByteArrayResource(responseData)); } private TbResourceInfo checkImageInfo(String imageType, String key, Operation operation) throws ThingsboardException { diff --git a/application/src/main/java/org/thingsboard/server/controller/NotificationController.java b/application/src/main/java/org/thingsboard/server/controller/NotificationController.java index e055c6d6ae..72c339c635 100644 --- a/application/src/main/java/org/thingsboard/server/controller/NotificationController.java +++ b/application/src/main/java/org/thingsboard/server/controller/NotificationController.java @@ -477,7 +477,7 @@ public class NotificationController extends BaseController { SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH) @GetMapping("/notification/deliveryMethods") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") - public Set getAvailableDeliveryMethods(@AuthenticationPrincipal SecurityUser user) throws ThingsboardException { + public List getAvailableDeliveryMethods(@AuthenticationPrincipal SecurityUser user) throws ThingsboardException { return notificationCenter.getAvailableDeliveryMethods(user.getTenantId()); } diff --git a/application/src/main/java/org/thingsboard/server/service/install/update/ResourcesUpdater.java b/application/src/main/java/org/thingsboard/server/service/install/update/ResourcesUpdater.java index 00797da449..da2b7276dd 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/update/ResourcesUpdater.java +++ b/application/src/main/java/org/thingsboard/server/service/install/update/ResourcesUpdater.java @@ -101,7 +101,7 @@ public class ResourcesUpdater { for (DashboardId dashboardId : dashboards) { executor.submit(() -> { Dashboard dashboard = dashboardService.findDashboardById(TenantId.SYS_TENANT_ID, dashboardId); - boolean updated = resourceService.updateResourcesUsage(dashboard); // will convert resources ids to new structure + boolean updated = resourceService.updateResourcesUsage(dashboard.getTenantId(), dashboard); // will convert resources ids to new structure if (updated) { dashboardService.saveDashboard(dashboard); updatedCount.incrementAndGet(); @@ -130,7 +130,7 @@ public class ResourcesUpdater { for (WidgetTypeId widgetTypeId : widgets) { executor.submit(() -> { WidgetTypeDetails widgetTypeDetails = widgetTypeService.findWidgetTypeDetailsById(TenantId.SYS_TENANT_ID, widgetTypeId); - boolean updated = resourceService.updateResourcesUsage(widgetTypeDetails); + boolean updated = resourceService.updateResourcesUsage(widgetTypeDetails.getTenantId(), widgetTypeDetails); if (updated) { widgetTypeService.saveWidgetType(widgetTypeDetails); updatedCount.incrementAndGet(); diff --git a/application/src/main/java/org/thingsboard/server/service/notification/DefaultNotificationCenter.java b/application/src/main/java/org/thingsboard/server/service/notification/DefaultNotificationCenter.java index 311fe6cb2c..af63256f0f 100644 --- a/application/src/main/java/org/thingsboard/server/service/notification/DefaultNotificationCenter.java +++ b/application/src/main/java/org/thingsboard/server/service/notification/DefaultNotificationCenter.java @@ -417,7 +417,7 @@ public class DefaultNotificationCenter extends AbstractSubscriptionService imple } @Override - public Set getAvailableDeliveryMethods(TenantId tenantId) { + public List getAvailableDeliveryMethods(TenantId tenantId) { return channels.values().stream() .filter(channel -> { try { @@ -428,7 +428,7 @@ public class DefaultNotificationCenter extends AbstractSubscriptionService imple } }) .map(NotificationChannel::getDeliveryMethod) - .collect(Collectors.toSet()); + .sorted().toList(); } @Override diff --git a/application/src/main/java/org/thingsboard/server/service/resource/DefaultTbResourceService.java b/application/src/main/java/org/thingsboard/server/service/resource/DefaultTbResourceService.java index 90ad3e38dd..e3a79a8ba5 100644 --- a/application/src/main/java/org/thingsboard/server/service/resource/DefaultTbResourceService.java +++ b/application/src/main/java/org/thingsboard/server/service/resource/DefaultTbResourceService.java @@ -46,7 +46,7 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Comparator; import java.util.List; -import java.util.function.Function; +import java.util.function.Supplier; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -132,12 +132,12 @@ public class DefaultTbResourceService extends AbstractTbEntityService implements @Override public List exportResources(Dashboard dashboard, SecurityUser user) throws ThingsboardException { - return exportResources(dashboard, imageService::getUsedImages, resourceService::getUsedResources, user); + return exportResources(() -> imageService.getUsedImages(dashboard), () -> resourceService.getUsedResources(user.getTenantId(), dashboard), user); } @Override public List exportResources(WidgetTypeDetails widgetTypeDetails, SecurityUser user) throws ThingsboardException { - return exportResources(widgetTypeDetails, imageService::getUsedImages, resourceService::getUsedResources, user); + return exportResources(() -> imageService.getUsedImages(widgetTypeDetails), () -> resourceService.getUsedResources(user.getTenantId(), widgetTypeDetails), user); } @Override @@ -153,13 +153,12 @@ public class DefaultTbResourceService extends AbstractTbEntityService implements } } - private List exportResources(T entity, - Function> imagesProcessor, - Function> resourcesProcessor, + private List exportResources(Supplier> imagesProcessor, + Supplier> resourcesProcessor, SecurityUser user) throws ThingsboardException { List resources = new ArrayList<>(); - resources.addAll(imagesProcessor.apply(entity)); - resources.addAll(resourcesProcessor.apply(entity)); + resources.addAll(imagesProcessor.get()); + resources.addAll(resourcesProcessor.get()); for (TbResourceInfo resourceInfo : resources) { accessControlService.checkPermission(user, Resource.TB_RESOURCE, Operation.READ, resourceInfo.getId(), resourceInfo); } diff --git a/application/src/test/java/org/thingsboard/server/controller/DashboardControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/DashboardControllerTest.java index 88dd8f241c..ffbf95d990 100644 --- a/application/src/test/java/org/thingsboard/server/controller/DashboardControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/DashboardControllerTest.java @@ -17,6 +17,7 @@ package org.thingsboard.server.controller; import com.datastax.oss.driver.api.core.uuid.Uuids; import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.node.ObjectNode; import org.junit.After; import org.junit.Assert; import org.junit.Before; @@ -602,13 +603,14 @@ public class DashboardControllerTest extends AbstractControllerTest { dashboard.setTitle("My dashboard"); dashboard.setConfiguration(JacksonUtil.newObjectNode() .put("someImage", "tb-image;/api/images/tenant/" + imageInfo.getResourceKey()) - .set("widgets", JacksonUtil.toJsonNode(""" + .set("widgets", JacksonUtil.toJsonNode(""" {"xxx": {"config":{"actions":{"elementClick":[ {"customResources":[{"url":{"entityType":"TB_RESOURCE","id": "tb-resource;/api/resource/js_module/tenant/gateway-management-extension.js"},"isModule":true}, {"url":"tb-resource;/api/resource/js_module/tenant/gateway-management-extension.js","isModule":true}]}]}}}} - """))); + """)) + .put("someResource", "tb-resource;/api/resource/js_module/tenant/gateway-management-extension.js")); dashboard = doPost("/api/dashboard", dashboard, Dashboard.class); Dashboard exportedDashboard = doGet("/api/dashboard/" + dashboard.getUuidId() + "?includeResources=true", Dashboard.class); @@ -637,12 +639,18 @@ public class DashboardControllerTest extends AbstractControllerTest { doPost("/api/resource", resource, TbResourceInfo.class); Dashboard importedDashboard = doPost("/api/dashboard", exportedDashboard, Dashboard.class); + String newResourceKey = "gateway-management-extension_(1).js"; + imageRef = importedDashboard.getConfiguration().get("someImage").asText(); assertThat(imageRef).isEqualTo("tb-image;/api/images/tenant/" + imageInfo.getResourceKey()); - resourceRef = importedDashboard.getConfiguration().get("widgets").get("xxx").get("config") - .get("actions").get("elementClick").get(0).get("customResources").get(0).get("url").asText(); - String newResourceKey = "gateway-management-extension_(1).js"; - assertThat(resourceRef).isEqualTo("tb-resource;/api/resource/js_module/tenant/" + newResourceKey); + + List resourcesRefs = new ArrayList<>(); + resourcesRefs.add(importedDashboard.getConfiguration().get("widgets").get("xxx").get("config") + .get("actions").get("elementClick").get(0).get("customResources").get(0).get("url").asText()); + resourcesRefs.add(importedDashboard.getConfiguration().get("someResource").asText()); + assertThat(resourcesRefs).allSatisfy(ref -> { + assertThat(ref).isEqualTo("tb-resource;/api/resource/js_module/tenant/" + newResourceKey); + }); TbResourceInfo importedImageInfo = doGet("/api/images/tenant/" + imageInfo.getResourceKey() + "/info", TbResourceInfo.class); assertThat(importedImageInfo.getEtag()).isEqualTo(imageInfo.getEtag()); diff --git a/common/actor/pom.xml b/common/actor/pom.xml index cc19cc949f..cbbce12336 100644 --- a/common/actor/pom.xml +++ b/common/actor/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.9.0-SNAPSHOT + 3.9.0-RC common org.thingsboard.common diff --git a/common/cache/pom.xml b/common/cache/pom.xml index 1ecb95c6c5..a4f7dd4f7b 100644 --- a/common/cache/pom.xml +++ b/common/cache/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.9.0-SNAPSHOT + 3.9.0-RC common org.thingsboard.common diff --git a/common/cluster-api/pom.xml b/common/cluster-api/pom.xml index bd7dc214cf..4bbe65d99f 100644 --- a/common/cluster-api/pom.xml +++ b/common/cluster-api/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.9.0-SNAPSHOT + 3.9.0-RC common org.thingsboard.common diff --git a/common/coap-server/pom.xml b/common/coap-server/pom.xml index 401d1e94fd..32da47ca08 100644 --- a/common/coap-server/pom.xml +++ b/common/coap-server/pom.xml @@ -22,7 +22,7 @@ 4.0.0 org.thingsboard - 3.9.0-SNAPSHOT + 3.9.0-RC common org.thingsboard.common diff --git a/common/dao-api/pom.xml b/common/dao-api/pom.xml index 62c1e420c2..7d48a63903 100644 --- a/common/dao-api/pom.xml +++ b/common/dao-api/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.9.0-SNAPSHOT + 3.9.0-RC common org.thingsboard.common diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/resource/ResourceService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/resource/ResourceService.java index 0e2acb2e4e..f7f4b1ce4b 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/resource/ResourceService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/resource/ResourceService.java @@ -80,13 +80,13 @@ public interface ResourceService extends EntityDaoService { TbResourceInfo findSystemOrTenantResourceByEtag(TenantId tenantId, ResourceType resourceType, String etag); - boolean updateResourcesUsage(Dashboard dashboard); + boolean updateResourcesUsage(TenantId tenantId, Dashboard dashboard); - boolean updateResourcesUsage(WidgetTypeDetails widgetTypeDetails); + boolean updateResourcesUsage(TenantId tenantId, WidgetTypeDetails widgetTypeDetails); - Collection getUsedResources(Dashboard dashboard); + Collection getUsedResources(TenantId tenantId, Dashboard dashboard); - Collection getUsedResources(WidgetTypeDetails widgetTypeDetails); + Collection getUsedResources(TenantId tenantId, WidgetTypeDetails widgetTypeDetails); TbResource createOrUpdateSystemResource(ResourceType resourceType, String resourceKey, byte[] data); diff --git a/common/data/pom.xml b/common/data/pom.xml index b206f0b173..e6eca1aa93 100644 --- a/common/data/pom.xml +++ b/common/data/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.9.0-SNAPSHOT + 3.9.0-RC common org.thingsboard.common 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 d025aab3d5..fed271cbbe 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 @@ -50,7 +50,8 @@ public class WidgetType extends BaseWidgetType { @JsonIgnore public JsonNode getDefaultConfig() { - return Optional.ofNullable(descriptor.get("defaultConfig")) + return Optional.ofNullable(descriptor) + .map(descriptor -> descriptor.get("defaultConfig")) .filter(JsonNode::isTextual).map(JsonNode::asText) .map(json -> { try { diff --git a/common/edge-api/pom.xml b/common/edge-api/pom.xml index 31d90de948..68e647642d 100644 --- a/common/edge-api/pom.xml +++ b/common/edge-api/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.9.0-SNAPSHOT + 3.9.0-RC common org.thingsboard.common diff --git a/common/message/pom.xml b/common/message/pom.xml index ac56095e7e..0614c94bc4 100644 --- a/common/message/pom.xml +++ b/common/message/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.9.0-SNAPSHOT + 3.9.0-RC common org.thingsboard.common diff --git a/common/pom.xml b/common/pom.xml index c905e0eee9..8bd1904d72 100644 --- a/common/pom.xml +++ b/common/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.9.0-SNAPSHOT + 3.9.0-RC thingsboard common diff --git a/common/proto/pom.xml b/common/proto/pom.xml index 4409d6b97f..fded7298e4 100644 --- a/common/proto/pom.xml +++ b/common/proto/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.9.0-SNAPSHOT + 3.9.0-RC common org.thingsboard.common diff --git a/common/queue/pom.xml b/common/queue/pom.xml index 7485294f6e..fab4ff3989 100644 --- a/common/queue/pom.xml +++ b/common/queue/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.9.0-SNAPSHOT + 3.9.0-RC common org.thingsboard.common diff --git a/common/script/pom.xml b/common/script/pom.xml index 88e35e8429..1aad1dd39e 100644 --- a/common/script/pom.xml +++ b/common/script/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.9.0-SNAPSHOT + 3.9.0-RC common org.thingsboard.common diff --git a/common/script/remote-js-client/pom.xml b/common/script/remote-js-client/pom.xml index 7309e6af51..38a14cd8f3 100644 --- a/common/script/remote-js-client/pom.xml +++ b/common/script/remote-js-client/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard.common - 3.9.0-SNAPSHOT + 3.9.0-RC script org.thingsboard.common.script diff --git a/common/script/script-api/pom.xml b/common/script/script-api/pom.xml index 08ef60713e..4210f1f528 100644 --- a/common/script/script-api/pom.xml +++ b/common/script/script-api/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard.common - 3.9.0-SNAPSHOT + 3.9.0-RC script org.thingsboard.common.script diff --git a/common/stats/pom.xml b/common/stats/pom.xml index 31fbc72dcc..231811144a 100644 --- a/common/stats/pom.xml +++ b/common/stats/pom.xml @@ -22,7 +22,7 @@ 4.0.0 org.thingsboard - 3.9.0-SNAPSHOT + 3.9.0-RC common org.thingsboard.common diff --git a/common/transport/coap/pom.xml b/common/transport/coap/pom.xml index d4528944e0..0bd4c0d6e3 100644 --- a/common/transport/coap/pom.xml +++ b/common/transport/coap/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard.common - 3.9.0-SNAPSHOT + 3.9.0-RC transport org.thingsboard.common.transport diff --git a/common/transport/http/pom.xml b/common/transport/http/pom.xml index 054fc3cbbe..5a0dd9e4ff 100644 --- a/common/transport/http/pom.xml +++ b/common/transport/http/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard.common - 3.9.0-SNAPSHOT + 3.9.0-RC transport org.thingsboard.common.transport diff --git a/common/transport/lwm2m/pom.xml b/common/transport/lwm2m/pom.xml index 54232ac104..ddb9d7a399 100644 --- a/common/transport/lwm2m/pom.xml +++ b/common/transport/lwm2m/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard.common - 3.9.0-SNAPSHOT + 3.9.0-RC transport org.thingsboard.common.transport diff --git a/common/transport/mqtt/pom.xml b/common/transport/mqtt/pom.xml index e672f7a5dd..45d228f225 100644 --- a/common/transport/mqtt/pom.xml +++ b/common/transport/mqtt/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard.common - 3.9.0-SNAPSHOT + 3.9.0-RC transport org.thingsboard.common.transport diff --git a/common/transport/pom.xml b/common/transport/pom.xml index c87fa8c2bf..6c4310151d 100644 --- a/common/transport/pom.xml +++ b/common/transport/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.9.0-SNAPSHOT + 3.9.0-RC common org.thingsboard.common diff --git a/common/transport/snmp/pom.xml b/common/transport/snmp/pom.xml index 78665bfde2..a2b9dd7c84 100644 --- a/common/transport/snmp/pom.xml +++ b/common/transport/snmp/pom.xml @@ -21,7 +21,7 @@ org.thingsboard.common - 3.9.0-SNAPSHOT + 3.9.0-RC transport diff --git a/common/transport/transport-api/pom.xml b/common/transport/transport-api/pom.xml index 7d221c48bf..8f01cab08b 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.9.0-SNAPSHOT + 3.9.0-RC transport org.thingsboard.common.transport diff --git a/common/util/pom.xml b/common/util/pom.xml index ad3bbaba58..194724b70f 100644 --- a/common/util/pom.xml +++ b/common/util/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.9.0-SNAPSHOT + 3.9.0-RC common org.thingsboard.common diff --git a/common/version-control/pom.xml b/common/version-control/pom.xml index f37139b3c5..8e3fceff99 100644 --- a/common/version-control/pom.xml +++ b/common/version-control/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.9.0-SNAPSHOT + 3.9.0-RC common org.thingsboard.common diff --git a/dao/pom.xml b/dao/pom.xml index 1dac54c142..c1f5a1f62b 100644 --- a/dao/pom.xml +++ b/dao/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.9.0-SNAPSHOT + 3.9.0-RC thingsboard dao diff --git a/dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardServiceImpl.java index b547de1eca..2e9e37577c 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardServiceImpl.java @@ -162,18 +162,19 @@ public class DashboardServiceImpl extends AbstractEntityService implements Dashb dashboardValidator.validate(dashboard, DashboardInfo::getTenantId); } try { + TenantId tenantId = dashboard.getTenantId(); if (CollectionUtils.isNotEmpty(dashboard.getResources())) { - resourceService.importResources(dashboard.getTenantId(), dashboard.getResources()); + resourceService.importResources(tenantId, dashboard.getResources()); } imageService.updateImagesUsage(dashboard); - resourceService.updateResourcesUsage(dashboard); + resourceService.updateResourcesUsage(tenantId, dashboard); - var saved = dashboardDao.save(dashboard.getTenantId(), dashboard); + var saved = dashboardDao.save(tenantId, dashboard); publishEvictEvent(new DashboardTitleEvictEvent(saved.getId())); - eventPublisher.publishEvent(SaveEntityEvent.builder().tenantId(saved.getTenantId()) + eventPublisher.publishEvent(SaveEntityEvent.builder().tenantId(tenantId) .entityId(saved.getId()).created(dashboard.getId() == null).build()); if (dashboard.getId() == null) { - countService.publishCountEntityEvictEvent(saved.getTenantId(), EntityType.DASHBOARD); + countService.publishCountEntityEvictEvent(tenantId, EntityType.DASHBOARD); } return saved; } catch (Exception e) { diff --git a/dao/src/main/java/org/thingsboard/server/dao/oauth2/OAuth2ClientServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/oauth2/OAuth2ClientServiceImpl.java index 683c323ab5..452bd7ccf7 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/oauth2/OAuth2ClientServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/oauth2/OAuth2ClientServiceImpl.java @@ -64,7 +64,7 @@ public class OAuth2ClientServiceImpl extends AbstractEntityService implements OA @Override public List findOAuth2ClientLoginInfosByMobilePkgNameAndPlatformType(String pkgName, PlatformType platformType) { - log.trace("Executing findOAuth2ClientLoginInfosByMobilePkgNameAndPlatformType pkgName=[{}] platformType=[{}]",pkgName, platformType); + log.trace("Executing findOAuth2ClientLoginInfosByMobilePkgNameAndPlatformType pkgName=[{}] platformType=[{}]", pkgName, platformType); return oauth2ClientDao.findEnabledByPkgNameAndPlatformType(pkgName, platformType) .stream() .map(OAuth2Utils::toClientLoginInfo) diff --git a/dao/src/main/java/org/thingsboard/server/dao/resource/BaseResourceService.java b/dao/src/main/java/org/thingsboard/server/dao/resource/BaseResourceService.java index 22aa2ae748..9395aae6c7 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/resource/BaseResourceService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/resource/BaseResourceService.java @@ -57,6 +57,7 @@ import org.thingsboard.server.dao.service.Validator; import org.thingsboard.server.dao.service.validator.ResourceDataValidator; import java.nio.charset.StandardCharsets; +import java.util.ArrayList; import java.util.Base64; import java.util.Collection; import java.util.Collections; @@ -401,18 +402,33 @@ public class BaseResourceService extends AbstractCachedEntityService links = getResourcesLinks(dashboard.getResources()); - return updateResourcesUsage(dashboard.getTenantId(), dashboard.getConfiguration(), DASHBOARD_RESOURCES_MAPPING, links); + return updateResourcesUsage(tenantId, List.of(dashboard.getConfiguration()), List.of(DASHBOARD_RESOURCES_MAPPING), links); } @Override - public boolean updateResourcesUsage(WidgetTypeDetails widgetTypeDetails) { + public boolean updateResourcesUsage(TenantId tenantId, WidgetTypeDetails widgetTypeDetails) { Map links = getResourcesLinks(widgetTypeDetails.getResources()); - boolean updated = updateResourcesUsage(widgetTypeDetails.getTenantId(), widgetTypeDetails.getDescriptor(), WIDGET_RESOURCES_MAPPING, links); + List jsonNodes = new ArrayList<>(2); + List> mappings = new ArrayList<>(2); + + if (widgetTypeDetails.getDescriptor() != null) { + jsonNodes.add(widgetTypeDetails.getDescriptor()); + mappings.add(WIDGET_RESOURCES_MAPPING); + } + JsonNode defaultConfig = widgetTypeDetails.getDefaultConfig(); if (defaultConfig != null) { - updated |= updateResourcesUsage(widgetTypeDetails.getTenantId(), defaultConfig, WIDGET_DEFAULT_CONFIG_RESOURCES_MAPPING, links); + jsonNodes.add(defaultConfig); + mappings.add(WIDGET_DEFAULT_CONFIG_RESOURCES_MAPPING); + } + + boolean updated = updateResourcesUsage(tenantId, jsonNodes, mappings, links); + if (defaultConfig != null) { widgetTypeDetails.setDefaultConfig(defaultConfig); } return updated; @@ -433,8 +449,9 @@ public class BaseResourceService extends AbstractCachedEntityService mapping, Map links) { - return processResources(jsonNode, mapping, value -> { + private boolean updateResourcesUsage(TenantId tenantId, List jsonNodes, List> mappings, Map links) { + log.trace("[{}] updateResourcesUsage (new links: {}) for {}", tenantId, links, jsonNodes); + return processResources(jsonNodes, mappings, value -> { String link = getResourceLink(value); if (link != null) { String newLink = links.get(link); @@ -462,23 +479,31 @@ public class BaseResourceService extends AbstractCachedEntityService getUsedResources(Dashboard dashboard) { - return getUsedResources(dashboard.getTenantId(), dashboard.getConfiguration(), DASHBOARD_RESOURCES_MAPPING).values(); + public Collection getUsedResources(TenantId tenantId, Dashboard dashboard) { + return getUsedResources(tenantId, List.of(dashboard.getConfiguration()), List.of(DASHBOARD_RESOURCES_MAPPING)).values(); } @Override - public Collection getUsedResources(WidgetTypeDetails widgetTypeDetails) { - Map resources = getUsedResources(widgetTypeDetails.getTenantId(), widgetTypeDetails.getDescriptor(), WIDGET_RESOURCES_MAPPING); + public Collection getUsedResources(TenantId tenantId, WidgetTypeDetails widgetTypeDetails) { + List jsonNodes = new ArrayList<>(2); + List> mappings = new ArrayList<>(2); + + jsonNodes.add(widgetTypeDetails.getDescriptor()); + mappings.add(WIDGET_RESOURCES_MAPPING); + JsonNode defaultConfig = widgetTypeDetails.getDefaultConfig(); if (defaultConfig != null) { - resources.putAll(getUsedResources(widgetTypeDetails.getTenantId(), defaultConfig, WIDGET_DEFAULT_CONFIG_RESOURCES_MAPPING)); + jsonNodes.add(defaultConfig); + mappings.add(WIDGET_DEFAULT_CONFIG_RESOURCES_MAPPING); } - return resources.values(); + + return getUsedResources(tenantId, jsonNodes, mappings).values(); } - private Map getUsedResources(TenantId tenantId, JsonNode jsonNode, Map mapping) { + private Map getUsedResources(TenantId tenantId, List jsonNodes, List> mappings) { Map resources = new HashMap<>(); - processResources(jsonNode, mapping, value -> { + log.trace("[{}] getUsedResources for {}", tenantId, jsonNodes); + processResources(jsonNodes, mappings, value -> { String link = getResourceLink(value); if (link == null) { return value; @@ -517,32 +542,57 @@ public class BaseResourceService extends AbstractCachedEntityService mapping, UnaryOperator processor) { + private boolean processResources(List jsonNodes, List> mappings, UnaryOperator processor) { AtomicBoolean updated = new AtomicBoolean(false); - JacksonUtil.replaceByMapping(jsonNode, mapping, Collections.emptyMap(), (name, urlNode) -> { - String value = null; - if (urlNode.isTextual()) { // link is in the right place - value = urlNode.asText(); - } else { - JsonNode id = urlNode.get("id"); // old structure is used - if (id != null && id.isTextual()) { - value = id.asText(); - } - } - if (StringUtils.isNotBlank(value)) { - value = processor.apply(value); - } else { - value = ""; - } + for (int i = 0; i < jsonNodes.size(); i++) { + JsonNode jsonNode = jsonNodes.get(i); + // processing by mappings first + if (i <= mappings.size() - 1) { + JacksonUtil.replaceByMapping(jsonNode, mappings.get(i), Collections.emptyMap(), (name, urlNode) -> { + String value = null; + if (urlNode.isTextual()) { // link is in the right place + value = urlNode.asText(); + } else { + JsonNode id = urlNode.get("id"); // old structure is used + if (id != null && id.isTextual()) { + value = id.asText(); + } + } - JsonNode newValue = new TextNode(value); - if (!newValue.toString().equals(urlNode.toString())) { - updated.set(true); - log.trace("Replaced '{}' with '{}'", urlNode, newValue); + if (StringUtils.isNotBlank(value)) { + value = processor.apply(value); + } else { + value = ""; + } + + JsonNode newValue = new TextNode(value); + if (!newValue.toString().equals(urlNode.toString())) { + updated.set(true); + log.trace("Replaced by mapping '{}' ({}) with '{}'", value, name, newValue); + } + return newValue; + }); } - return newValue; - }); + + + // processing all + JacksonUtil.replaceAll(jsonNode, "", (name, value) -> { + if (!StringUtils.startsWith(value, DataConstants.TB_RESOURCE_PREFIX + "/api/resource/")) { + return value; + } + + String newValue = processor.apply(value); + if (StringUtils.equals(value, newValue)) { + return value; + } else { + updated.set(true); + log.trace("Replaced '{}' ({}) with '{}'", value, name, newValue); + return newValue; + } + }); + } + return updated.get(); } @@ -555,7 +605,7 @@ public class BaseResourceService extends AbstractCachedEntityService findEnabledByPkgNameAndPlatformType(String pkgName, PlatformType platformType) { - return DaoUtil.convertDataList(repository.findEnabledByPkgNameAndPlatformType(pkgName, - platformType != null ? platformType.name() : null)); + List clientEntities; + if (platformType != null) { + clientEntities = switch (platformType) { + case ANDROID -> repository.findEnabledByAndroidPkgNameAndPlatformType(pkgName, platformType.name()); + case IOS -> repository.findEnabledByIosPkgNameAndPlatformType(pkgName, platformType.name()); + default -> Collections.emptyList(); + }; + } else { + clientEntities = Collections.emptyList(); + } + return DaoUtil.convertDataList(clientEntities); } @Override diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/oauth2/OAuth2ClientRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/oauth2/OAuth2ClientRepository.java index f7fe5bce3a..2a5526c146 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/oauth2/OAuth2ClientRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/oauth2/OAuth2ClientRepository.java @@ -49,11 +49,21 @@ public interface OAuth2ClientRepository extends JpaRepository findEnabledByPkgNameAndPlatformType(@Param("pkgName") String pkgName, - @Param("platformFilter") String platformFilter); + List findEnabledByAndroidPkgNameAndPlatformType(@Param("pkgName") String pkgName, + @Param("platformFilter") String platformFilter); + + @Query("SELECT c " + + "FROM OAuth2ClientEntity c " + + "LEFT JOIN MobileAppBundleOauth2ClientEntity ac ON c.id = ac.oauth2ClientId " + + "LEFT JOIN MobileAppBundleEntity b ON ac.mobileAppBundleId = b.id " + + "LEFT JOIN MobileAppEntity iosApp ON b.iosAppID = iosApp.id " + + "WHERE iosApp.pkgName = :pkgName AND b.oauth2Enabled = true " + + "AND (:platformFilter IS NULL OR c.platforms IS NULL OR c.platforms = '' OR ilike(c.platforms, CONCAT('%', :platformFilter, '%')) = true)") + List findEnabledByIosPkgNameAndPlatformType(@Param("pkgName") String pkgName, + @Param("platformFilter") String platformFilter); @Query("SELECT c " + "FROM OAuth2ClientEntity c " + diff --git a/dao/src/main/java/org/thingsboard/server/dao/widget/WidgetTypeServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/widget/WidgetTypeServiceImpl.java index fd9b1260ba..a1e241073f 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/widget/WidgetTypeServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/widget/WidgetTypeServiceImpl.java @@ -99,14 +99,15 @@ public class WidgetTypeServiceImpl implements WidgetTypeService { log.trace("Executing saveWidgetType [{}]", widgetTypeDetails); widgetTypeValidator.validate(widgetTypeDetails, WidgetType::getTenantId); try { + TenantId tenantId = widgetTypeDetails.getTenantId(); if (CollectionUtils.isNotEmpty(widgetTypeDetails.getResources())) { - resourceService.importResources(widgetTypeDetails.getTenantId(), widgetTypeDetails.getResources()); + resourceService.importResources(tenantId, widgetTypeDetails.getResources()); } imageService.updateImagesUsage(widgetTypeDetails); - resourceService.updateResourcesUsage(widgetTypeDetails); + resourceService.updateResourcesUsage(tenantId, widgetTypeDetails); - WidgetTypeDetails result = widgetTypeDao.save(widgetTypeDetails.getTenantId(), widgetTypeDetails); - eventPublisher.publishEvent(SaveEntityEvent.builder().tenantId(result.getTenantId()) + WidgetTypeDetails result = widgetTypeDao.save(tenantId, widgetTypeDetails); + eventPublisher.publishEvent(SaveEntityEvent.builder().tenantId(tenantId) .entityId(result.getId()).created(widgetTypeDetails.getId() == null).build()); return result; } catch (Exception t) { diff --git a/monitoring/pom.xml b/monitoring/pom.xml index 013a0b5c47..e19acb0fe6 100644 --- a/monitoring/pom.xml +++ b/monitoring/pom.xml @@ -21,7 +21,7 @@ 4.0.0 org.thingsboard - 3.9.0-SNAPSHOT + 3.9.0-RC thingsboard diff --git a/msa/black-box-tests/pom.xml b/msa/black-box-tests/pom.xml index 4d34a13f38..5563fcc8d8 100644 --- a/msa/black-box-tests/pom.xml +++ b/msa/black-box-tests/pom.xml @@ -21,7 +21,7 @@ org.thingsboard - 3.9.0-SNAPSHOT + 3.9.0-RC msa org.thingsboard.msa diff --git a/msa/js-executor/pom.xml b/msa/js-executor/pom.xml index f747db1438..daea52bfa5 100644 --- a/msa/js-executor/pom.xml +++ b/msa/js-executor/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.9.0-SNAPSHOT + 3.9.0-RC msa org.thingsboard.msa diff --git a/msa/monitoring/pom.xml b/msa/monitoring/pom.xml index 3a4834236c..20f8d90695 100644 --- a/msa/monitoring/pom.xml +++ b/msa/monitoring/pom.xml @@ -22,7 +22,7 @@ 4.0.0 org.thingsboard - 3.9.0-SNAPSHOT + 3.9.0-RC msa diff --git a/msa/pom.xml b/msa/pom.xml index d77384cc74..057f37a575 100644 --- a/msa/pom.xml +++ b/msa/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.9.0-SNAPSHOT + 3.9.0-RC thingsboard msa diff --git a/msa/tb-node/pom.xml b/msa/tb-node/pom.xml index 11295dc4b9..3ca22bcf55 100644 --- a/msa/tb-node/pom.xml +++ b/msa/tb-node/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.9.0-SNAPSHOT + 3.9.0-RC msa org.thingsboard.msa diff --git a/msa/tb/pom.xml b/msa/tb/pom.xml index 79a2a66385..3789fe14a1 100644 --- a/msa/tb/pom.xml +++ b/msa/tb/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.9.0-SNAPSHOT + 3.9.0-RC msa org.thingsboard.msa diff --git a/msa/transport/coap/pom.xml b/msa/transport/coap/pom.xml index 9ec8589d9a..089581f1cb 100644 --- a/msa/transport/coap/pom.xml +++ b/msa/transport/coap/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard.msa - 3.9.0-SNAPSHOT + 3.9.0-RC transport org.thingsboard.msa.transport diff --git a/msa/transport/http/pom.xml b/msa/transport/http/pom.xml index d562f89cd5..4d9e17df5f 100644 --- a/msa/transport/http/pom.xml +++ b/msa/transport/http/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard.msa - 3.9.0-SNAPSHOT + 3.9.0-RC transport org.thingsboard.msa.transport diff --git a/msa/transport/lwm2m/pom.xml b/msa/transport/lwm2m/pom.xml index 992187316a..94b86d035f 100644 --- a/msa/transport/lwm2m/pom.xml +++ b/msa/transport/lwm2m/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard.msa - 3.9.0-SNAPSHOT + 3.9.0-RC transport org.thingsboard.msa.transport diff --git a/msa/transport/mqtt/pom.xml b/msa/transport/mqtt/pom.xml index 32aa6a4f23..2b637ddd19 100644 --- a/msa/transport/mqtt/pom.xml +++ b/msa/transport/mqtt/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard.msa - 3.9.0-SNAPSHOT + 3.9.0-RC transport org.thingsboard.msa.transport diff --git a/msa/transport/pom.xml b/msa/transport/pom.xml index 34be0bd338..4f7e0ad030 100644 --- a/msa/transport/pom.xml +++ b/msa/transport/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.9.0-SNAPSHOT + 3.9.0-RC msa org.thingsboard.msa diff --git a/msa/transport/snmp/pom.xml b/msa/transport/snmp/pom.xml index 95919ad175..94bc03f29d 100644 --- a/msa/transport/snmp/pom.xml +++ b/msa/transport/snmp/pom.xml @@ -21,7 +21,7 @@ org.thingsboard.msa transport - 3.9.0-SNAPSHOT + 3.9.0-RC org.thingsboard.msa.transport diff --git a/msa/vc-executor-docker/pom.xml b/msa/vc-executor-docker/pom.xml index 8aeeed2b1e..f6dc43ea13 100644 --- a/msa/vc-executor-docker/pom.xml +++ b/msa/vc-executor-docker/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.9.0-SNAPSHOT + 3.9.0-RC msa org.thingsboard.msa diff --git a/msa/vc-executor/pom.xml b/msa/vc-executor/pom.xml index 0932bf7c06..725c3e40ad 100644 --- a/msa/vc-executor/pom.xml +++ b/msa/vc-executor/pom.xml @@ -21,7 +21,7 @@ org.thingsboard - 3.9.0-SNAPSHOT + 3.9.0-RC msa org.thingsboard.msa diff --git a/msa/web-ui/pom.xml b/msa/web-ui/pom.xml index 195ae123f4..c5a900e004 100644 --- a/msa/web-ui/pom.xml +++ b/msa/web-ui/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.9.0-SNAPSHOT + 3.9.0-RC msa org.thingsboard.msa diff --git a/netty-mqtt/pom.xml b/netty-mqtt/pom.xml index 7de766b2da..d4cd55629d 100644 --- a/netty-mqtt/pom.xml +++ b/netty-mqtt/pom.xml @@ -19,11 +19,11 @@ 4.0.0 org.thingsboard - 3.9.0-SNAPSHOT + 3.9.0-RC thingsboard netty-mqtt - 3.9.0-SNAPSHOT + 3.9.0-RC jar Netty MQTT Client diff --git a/pom.xml b/pom.xml index 8dc3e1c40a..9ea372e47b 100755 --- a/pom.xml +++ b/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard thingsboard - 3.9.0-SNAPSHOT + 3.9.0-RC pom Thingsboard @@ -83,7 +83,7 @@ 3.9.2 3.25.5 1.63.0 - 1.2.4 + 1.2.5 1.18.32 1.2.5 1.2.5 diff --git a/rest-client/pom.xml b/rest-client/pom.xml index 069f7b84f0..f868acabf5 100644 --- a/rest-client/pom.xml +++ b/rest-client/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.9.0-SNAPSHOT + 3.9.0-RC thingsboard rest-client diff --git a/rule-engine/pom.xml b/rule-engine/pom.xml index e6abae70ef..fbefcd1de9 100644 --- a/rule-engine/pom.xml +++ b/rule-engine/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.9.0-SNAPSHOT + 3.9.0-RC thingsboard rule-engine diff --git a/rule-engine/rule-engine-api/pom.xml b/rule-engine/rule-engine-api/pom.xml index 57bc5771d2..3ee6496452 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.9.0-SNAPSHOT + 3.9.0-RC rule-engine org.thingsboard.rule-engine diff --git a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/NotificationCenter.java b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/NotificationCenter.java index 02ee53f3ad..b8fb9b61ff 100644 --- a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/NotificationCenter.java +++ b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/NotificationCenter.java @@ -30,7 +30,7 @@ import org.thingsboard.server.common.data.notification.info.NotificationInfo; import org.thingsboard.server.common.data.notification.targets.platform.UsersFilter; import org.thingsboard.server.common.data.notification.template.NotificationTemplate; -import java.util.Set; +import java.util.List; public interface NotificationCenter { @@ -48,6 +48,6 @@ public interface NotificationCenter { void deleteNotification(TenantId tenantId, UserId recipientId, NotificationId notificationId); - Set getAvailableDeliveryMethods(TenantId tenantId); + List getAvailableDeliveryMethods(TenantId tenantId); } diff --git a/rule-engine/rule-engine-components/pom.xml b/rule-engine/rule-engine-components/pom.xml index 99853b0950..33bb15af00 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.9.0-SNAPSHOT + 3.9.0-RC rule-engine org.thingsboard.rule-engine diff --git a/tools/pom.xml b/tools/pom.xml index 2d196cec7d..dce8e1606d 100644 --- a/tools/pom.xml +++ b/tools/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.9.0-SNAPSHOT + 3.9.0-RC thingsboard tools diff --git a/transport/coap/pom.xml b/transport/coap/pom.xml index 76655178ae..eef23eae9b 100644 --- a/transport/coap/pom.xml +++ b/transport/coap/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.9.0-SNAPSHOT + 3.9.0-RC transport org.thingsboard.transport diff --git a/transport/http/pom.xml b/transport/http/pom.xml index 7e569ea1f1..d841c56da7 100644 --- a/transport/http/pom.xml +++ b/transport/http/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.9.0-SNAPSHOT + 3.9.0-RC transport org.thingsboard.transport diff --git a/transport/lwm2m/pom.xml b/transport/lwm2m/pom.xml index b5b7867146..cec30fcbc5 100644 --- a/transport/lwm2m/pom.xml +++ b/transport/lwm2m/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.9.0-SNAPSHOT + 3.9.0-RC transport org.thingsboard.transport diff --git a/transport/mqtt/pom.xml b/transport/mqtt/pom.xml index 88009474aa..edf3727320 100644 --- a/transport/mqtt/pom.xml +++ b/transport/mqtt/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.9.0-SNAPSHOT + 3.9.0-RC transport org.thingsboard.transport diff --git a/transport/pom.xml b/transport/pom.xml index 8e7f77be9b..d744f7eb2f 100644 --- a/transport/pom.xml +++ b/transport/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.9.0-SNAPSHOT + 3.9.0-RC thingsboard transport diff --git a/transport/snmp/pom.xml b/transport/snmp/pom.xml index 02fe36f657..dcd08c10af 100644 --- a/transport/snmp/pom.xml +++ b/transport/snmp/pom.xml @@ -21,7 +21,7 @@ org.thingsboard - 3.9.0-SNAPSHOT + 3.9.0-RC transport diff --git a/ui-ngx/pom.xml b/ui-ngx/pom.xml index f16e352d71..1384b1c3e6 100644 --- a/ui-ngx/pom.xml +++ b/ui-ngx/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.9.0-SNAPSHOT + 3.9.0-RC thingsboard org.thingsboard diff --git a/ui-ngx/src/app/modules/home/components/vc/entity-version-create.component.html b/ui-ngx/src/app/modules/home/components/vc/entity-version-create.component.html index 67ef5908e5..ab127e45cd 100644 --- a/ui-ngx/src/app/modules/home/components/vc/entity-version-create.component.html +++ b/ui-ngx/src/app/modules/home/components/vc/entity-version-create.component.html @@ -41,10 +41,10 @@ {{ 'version-control.export-credentials' | translate }} - + {{ 'version-control.export-attributes' | translate }} - + {{ 'version-control.export-relations' | translate }} diff --git a/ui-ngx/src/app/modules/home/components/vc/entity-version-create.component.ts b/ui-ngx/src/app/modules/home/components/vc/entity-version-create.component.ts index 26d45de2c0..7d3e89eda8 100644 --- a/ui-ngx/src/app/modules/home/components/vc/entity-version-create.component.ts +++ b/ui-ngx/src/app/modules/home/components/vc/entity-version-create.component.ts @@ -18,6 +18,7 @@ import { ChangeDetectorRef, Component, Input, OnDestroy, OnInit } from '@angular import { PageComponent } from '@shared/components/page.component'; import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms'; import { + entityTypesWithoutRelatedData, SingleEntityVersionCreateRequest, VersionCreateRequestType, VersionCreationResult @@ -62,6 +63,8 @@ export class EntityVersionCreateComponent extends PageComponent implements OnIni entityTypes = EntityType; + entityTypesWithoutRelatedData = entityTypesWithoutRelatedData; + resultMessage: string; versionCreateResult$: Observable; @@ -108,8 +111,10 @@ export class EntityVersionCreateComponent extends PageComponent implements OnIni branch: this.createVersionFormGroup.get('branch').value, versionName: this.createVersionFormGroup.get('versionName').value, config: { - saveRelations: this.createVersionFormGroup.get('saveRelations').value, - saveAttributes: this.createVersionFormGroup.get('saveAttributes').value, + saveRelations: !entityTypesWithoutRelatedData.has(this.entityId.entityType) + ? this.createVersionFormGroup.get('saveRelations').value : false, + saveAttributes: !entityTypesWithoutRelatedData.has(this.entityId.entityType) + ? this.createVersionFormGroup.get('saveAttributes').value : false, saveCredentials: this.entityId.entityType === EntityType.DEVICE ? this.createVersionFormGroup.get('saveCredentials').value : false }, type: VersionCreateRequestType.SINGLE_ENTITY diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/button/two-segment-button-widget.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/button/two-segment-button-widget.component.html index 10cf016e11..1aac07bd4a 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/button/two-segment-button-widget.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/button/two-segment-button-widget.component.html @@ -15,7 +15,7 @@ limitations under the License. --> -
+
diff --git a/ui-ngx/src/app/modules/home/pages/admin/admin.module.ts b/ui-ngx/src/app/modules/home/pages/admin/admin.module.ts index 704f909809..784aade083 100644 --- a/ui-ngx/src/app/modules/home/pages/admin/admin.module.ts +++ b/ui-ngx/src/app/modules/home/pages/admin/admin.module.ts @@ -27,6 +27,7 @@ import { SmsProviderComponent } from '@home/pages/admin/sms-provider.component'; import { SendTestSmsDialogComponent } from '@home/pages/admin/send-test-sms-dialog.component'; import { HomeSettingsComponent } from '@home/pages/admin/home-settings.component'; import { ResourcesLibraryComponent } from '@home/pages/admin/resource/resources-library.component'; +import { ResourceTabsComponent } from '@home/pages/admin/resource/resource-tabs.component'; import { ResourcesTableHeaderComponent } from '@home/pages/admin/resource/resources-table-header.component'; import { QueueComponent } from '@home/pages/admin/queue/queue.component'; import { RepositoryAdminSettingsComponent } from '@home/pages/admin/repository-admin-settings.component'; @@ -47,6 +48,7 @@ import { NgxFlowModule } from '@flowjs/ngx-flow'; SecuritySettingsComponent, HomeSettingsComponent, ResourcesLibraryComponent, + ResourceTabsComponent, ResourcesTableHeaderComponent, JsResourceComponent, JsLibraryTableHeaderComponent, diff --git a/ui-ngx/src/app/modules/home/pages/admin/resource/js-library-table-config.resolver.ts b/ui-ngx/src/app/modules/home/pages/admin/resource/js-library-table-config.resolver.ts index b0fadd53d9..862adf48d5 100644 --- a/ui-ngx/src/app/modules/home/pages/admin/resource/js-library-table-config.resolver.ts +++ b/ui-ngx/src/app/modules/home/pages/admin/resource/js-library-table-config.resolver.ts @@ -43,6 +43,7 @@ import { EntityAction } from '@home/models/entity/entity-component.models'; import { JsLibraryTableHeaderComponent } from '@home/pages/admin/resource/js-library-table-header.component'; import { JsResourceComponent } from '@home/pages/admin/resource/js-resource.component'; import { switchMap } from 'rxjs/operators'; +import { ResourceTabsComponent } from '@home/pages/admin/resource/resource-tabs.component'; @Injectable() export class JsLibraryTableConfigResolver { @@ -57,6 +58,7 @@ export class JsLibraryTableConfigResolver { this.config.entityType = EntityType.TB_RESOURCE; this.config.entityComponent = JsResourceComponent; + this.config.entityTabsComponent = ResourceTabsComponent; this.config.entityTranslations = { details: 'javascript.javascript-resource-details', add: 'javascript.add', diff --git a/ui-ngx/src/app/modules/home/pages/admin/resource/resource-tabs.component.html b/ui-ngx/src/app/modules/home/pages/admin/resource/resource-tabs.component.html new file mode 100644 index 0000000000..fb608683d8 --- /dev/null +++ b/ui-ngx/src/app/modules/home/pages/admin/resource/resource-tabs.component.html @@ -0,0 +1,27 @@ + + + + + + + diff --git a/ui-ngx/src/app/modules/home/pages/admin/resource/resource-tabs.component.ts b/ui-ngx/src/app/modules/home/pages/admin/resource/resource-tabs.component.ts new file mode 100644 index 0000000000..2cd2f43d62 --- /dev/null +++ b/ui-ngx/src/app/modules/home/pages/admin/resource/resource-tabs.component.ts @@ -0,0 +1,36 @@ +/// +/// Copyright © 2016-2024 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 } from '@angular/core'; +import { EntityTabsComponent } from '@home/components/entity/entity-tabs.component'; +import { Resource } from '@shared/models/resource.models'; +import { Store } from '@ngrx/store'; +import { AppState } from '@core/core.state'; +import { NULL_UUID } from '@shared/models/id/has-uuid'; + +@Component({ + selector: 'tb-resource-tabs', + templateUrl: './resource-tabs.component.html', + styleUrls: [] +}) +export class ResourceTabsComponent extends EntityTabsComponent { + + readonly NULL_UUID = NULL_UUID; + + constructor(protected store: Store) { + super(store); + } +} diff --git a/ui-ngx/src/app/shared/components/json-form/react/json-form-schema-form.tsx b/ui-ngx/src/app/shared/components/json-form/react/json-form-schema-form.tsx index 5ce35ae96f..bbdd90cbe7 100644 --- a/ui-ngx/src/app/shared/components/json-form/react/json-form-schema-form.tsx +++ b/ui-ngx/src/app/shared/components/json-form/react/json-form-schema-form.tsx @@ -131,10 +131,10 @@ class ThingsboardSchemaForm extends React.Component { } if (form.condition) { this.hasConditions = true; - if (!this.conditionFunction) { - this.conditionFunction = new Function('form', 'model', 'index', `return ${form.condition};`); + if (!form.conditionFunction) { + form.conditionFunction = new Function('form', 'model', 'index', `return ${form.condition};`); } - if (this.conditionFunction(form, model, index) === false) { + if (form.conditionFunction(form, model, index) === false) { return null; } } diff --git a/ui-ngx/src/app/shared/components/json-form/react/json-form.models.ts b/ui-ngx/src/app/shared/components/json-form/react/json-form.models.ts index edba015521..ffcf201136 100644 --- a/ui-ngx/src/app/shared/components/json-form/react/json-form.models.ts +++ b/ui-ngx/src/app/shared/components/json-form/react/json-form.models.ts @@ -87,6 +87,7 @@ export interface JsonFormData { required: boolean; default?: any; condition?: string; + conditionFunction?: Function; style?: any; rows?: number; rowsMax?: number; diff --git a/ui-ngx/src/app/shared/models/vc.models.ts b/ui-ngx/src/app/shared/models/vc.models.ts index ba54a297a7..15d41656df 100644 --- a/ui-ngx/src/app/shared/models/vc.models.ts +++ b/ui-ngx/src/app/shared/models/vc.models.ts @@ -15,7 +15,7 @@ /// import { EntityId } from '@shared/models/id/entity-id'; -import { EntityType } from '@shared/models/entity-type.models'; +import { AliasEntityType, EntityType } from '@shared/models/entity-type.models'; import { ExportableEntity } from '@shared/models/base-data'; import { EntityRelation } from '@shared/models/relation.models'; import { Device, DeviceCredentials } from '@shared/models/device.models'; @@ -38,7 +38,7 @@ export const exportableEntityTypes: Array = [ EntityType.NOTIFICATION_RULE ]; -export const entityTypesWithoutRelatedData: Set = new Set([ +export const entityTypesWithoutRelatedData: Set = new Set([ EntityType.NOTIFICATION_TEMPLATE, EntityType.NOTIFICATION_TARGET, EntityType.NOTIFICATION_RULE, @@ -104,8 +104,8 @@ export function createDefaultEntityTypesVersionCreate(): {[entityType: string]: for (const entityType of exportableEntityTypes) { res[entityType] = { syncStrategy: null, - saveAttributes: true, - saveRelations: true, + saveAttributes: !entityTypesWithoutRelatedData.has(entityType), + saveRelations: !entityTypesWithoutRelatedData.has(entityType), saveCredentials: true, allEntities: true, entityIds: [] @@ -151,8 +151,8 @@ export function createDefaultEntityTypesVersionLoad(): {[entityType: string]: En const res: {[entityType: string]: EntityTypeVersionLoadConfig} = {}; for (const entityType of exportableEntityTypes) { res[entityType] = { - loadAttributes: true, - loadRelations: true, + loadAttributes: !entityTypesWithoutRelatedData.has(entityType), + loadRelations: !entityTypesWithoutRelatedData.has(entityType), loadCredentials: true, removeOtherEntities: false, findExistingEntityByName: true