From 81fa9a6ff2e3b7e65426e9357b968e133e302693 Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Mon, 8 Jul 2024 16:28:40 +0300 Subject: [PATCH] Ability to show SCADA widget bundles/widgets first when adding widget to SCADA layout. --- .../system/widget_bundles/scada_symbols.json | 1 + .../scada_water_system_symbols.json | 1 + .../system/widget_types/scada_symbol.json | 1 + .../controller/WidgetTypeController.java | 21 +++-- .../controller/WidgetsBundleController.java | 1 - .../SystemWidgetTypesEdgeEventFetcher.java | 9 ++- .../SystemWidgetsBundlesEdgeEventFetcher.java | 3 +- .../TenantWidgetTypesEdgeEventFetcher.java | 9 ++- .../service/install/InstallScripts.java | 1 + .../server/dao/widget/WidgetTypeService.java | 7 +- .../common/data/widget/WidgetTypeFilter.java | 34 ++++++++ .../dao/sql/widget/JpaWidgetTypeDao.java | 44 ++++++----- .../sql/widget/WidgetTypeInfoRepository.java | 12 ++- .../sql/widget/WidgetsBundleRepository.java | 2 +- .../server/dao/widget/WidgetTypeDao.java | 7 +- .../dao/widget/WidgetTypeServiceImpl.java | 33 +++++--- .../dao/sql/widget/JpaWidgetTypeDaoTest.java | 77 ++++++++++++++++--- .../sql/widget/JpaWidgetsBundleDaoTest.java | 65 +++++++++++++++- ui-ngx/src/app/core/http/entity.service.ts | 4 +- ui-ngx/src/app/core/http/widget.service.ts | 11 ++- .../dashboard-page.component.html | 1 + .../dashboard-page.component.ts | 2 + .../dashboard-widget-select.component.ts | 10 ++- .../scada/scada-symbol-widget.component.html | 1 + .../scada/scada-symbol-widget.component.scss | 13 ++++ .../scada/scada-symbol-widget.component.ts | 8 +- .../widget/widget-component.service.ts | 1 + .../home/models/widget-component.models.ts | 5 ++ .../pages/widget/widget-editor.component.html | 17 ++-- .../pages/widget/widget-type.component.html | 11 ++- .../pages/widget/widget-type.component.ts | 2 + .../widget/widgets-bundle.component.html | 3 + .../pages/widget/widgets-bundle.component.ts | 2 + ui-ngx/src/app/shared/models/widget.models.ts | 3 +- .../app/shared/models/widgets-bundle.model.ts | 1 + .../assets/locale/locale.constant-en_US.json | 2 + 36 files changed, 342 insertions(+), 83 deletions(-) create mode 100644 common/data/src/main/java/org/thingsboard/server/common/data/widget/WidgetTypeFilter.java diff --git a/application/src/main/data/json/system/widget_bundles/scada_symbols.json b/application/src/main/data/json/system/widget_bundles/scada_symbols.json index 47615e6137..f1fbfbc297 100644 --- a/application/src/main/data/json/system/widget_bundles/scada_symbols.json +++ b/application/src/main/data/json/system/widget_bundles/scada_symbols.json @@ -2,6 +2,7 @@ "widgetsBundle": { "alias": "scada_symbols", "title": "SCADA symbols", + "scada": true, "image": null, "description": "Bundle with SCADA symbols", "order": 9200, diff --git a/application/src/main/data/json/system/widget_bundles/scada_water_system_symbols.json b/application/src/main/data/json/system/widget_bundles/scada_water_system_symbols.json index 58667e457b..3f644523de 100644 --- a/application/src/main/data/json/system/widget_bundles/scada_water_system_symbols.json +++ b/application/src/main/data/json/system/widget_bundles/scada_water_system_symbols.json @@ -2,6 +2,7 @@ "widgetsBundle": { "alias": "scada_water_system_symbols", "title": "SCADA water system symbols", + "scada": true, "image": null, "description": "Bundle with SCADA symbols for water system", "order": 9300, diff --git a/application/src/main/data/json/system/widget_types/scada_symbol.json b/application/src/main/data/json/system/widget_types/scada_symbol.json index 5a40c26ffa..15c12e1b81 100644 --- a/application/src/main/data/json/system/widget_types/scada_symbol.json +++ b/application/src/main/data/json/system/widget_types/scada_symbol.json @@ -2,6 +2,7 @@ "fqn": "scada_symbol", "name": "SCADA symbol", "deprecated": false, + "scada": true, "image": null, "description": "", "descriptor": { diff --git a/application/src/main/java/org/thingsboard/server/controller/WidgetTypeController.java b/application/src/main/java/org/thingsboard/server/controller/WidgetTypeController.java index 4c48dbd434..6fb3bfc86f 100644 --- a/application/src/main/java/org/thingsboard/server/controller/WidgetTypeController.java +++ b/application/src/main/java/org/thingsboard/server/controller/WidgetTypeController.java @@ -42,8 +42,10 @@ import org.thingsboard.server.common.data.security.Authority; import org.thingsboard.server.common.data.widget.DeprecatedFilter; import org.thingsboard.server.common.data.widget.WidgetType; import org.thingsboard.server.common.data.widget.WidgetTypeDetails; +import org.thingsboard.server.common.data.widget.WidgetTypeFilter; import org.thingsboard.server.common.data.widget.WidgetTypeInfo; import org.thingsboard.server.common.data.widget.WidgetsBundle; +import org.thingsboard.server.common.data.widget.WidgetsBundleFilter; import org.thingsboard.server.config.annotations.ApiOperation; import org.thingsboard.server.dao.model.ModelConstants; import org.thingsboard.server.dao.resource.ImageService; @@ -84,6 +86,7 @@ public class WidgetTypeController extends AutoCommitController { private static final String WIDGET_TYPE_INFO_DESCRIPTION = "Widget Type Info is a lightweight object that represents Widget Type but does not contain the heavyweight widget descriptor JSON"; private static final String TENANT_ONLY_PARAM_DESCRIPTION = "Optional boolean parameter indicating whether only tenant widget types should be returned"; private static final String FULL_SEARCH_PARAM_DESCRIPTION = "Optional boolean parameter indicating whether search widgets by description not only by name"; + private static final String SCADA_FIRST_PARAM_DESCRIPTION = "Optional boolean parameter indicating whether to fetch SCADA symbol widgets first"; private static final String DEPRECATED_FILTER_PARAM_DESCRIPTION = "Optional string parameter indicating whether to include deprecated widgets"; private static final String UPDATE_EXISTING_BY_FQN_PARAM_DESCRIPTION = "Optional boolean parameter indicating whether to update existing widget type by FQN if present instead of creating new one"; private static final String WIDGET_TYPE_ARRAY_DESCRIPTION = "A list of string values separated by comma ',' representing one of the widget type value"; @@ -187,18 +190,26 @@ public class WidgetTypeController extends AutoCommitController { @Parameter(description = DEPRECATED_FILTER_PARAM_DESCRIPTION, schema = @Schema(allowableValues = {"ALL", "ACTUAL", "DEPRECATED"})) @RequestParam(required = false) String deprecatedFilter, @Parameter(description = WIDGET_TYPE_ARRAY_DESCRIPTION, array = @ArraySchema(schema = @Schema(type = "string", allowableValues = {"timeseries", "latest", "control", "alarm", "static"}))) - @RequestParam(required = false) String[] widgetTypeList) throws ThingsboardException { + @RequestParam(required = false) String[] widgetTypeList, + @Parameter(description = SCADA_FIRST_PARAM_DESCRIPTION) + @RequestParam(required = false) Boolean scadaFirst) throws ThingsboardException { PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder); List widgetTypes = widgetTypeList != null ? Arrays.asList(widgetTypeList) : Collections.emptyList(); - boolean fullSearchBool = fullSearch != null && fullSearch; DeprecatedFilter widgetTypeDeprecatedFilter = StringUtils.isNotEmpty(deprecatedFilter) ? DeprecatedFilter.valueOf(deprecatedFilter) : DeprecatedFilter.ALL; + WidgetTypeFilter widgetTypeFilter = WidgetTypeFilter.builder() + .tenantId(getTenantId()) + .widgetTypes(widgetTypes) + .deprecatedFilter(widgetTypeDeprecatedFilter) + .fullSearch(fullSearch != null && fullSearch) + .scadaFirst(scadaFirst != null && scadaFirst) + .build(); if (Authority.SYS_ADMIN.equals(getCurrentUser().getAuthority())) { - return checkNotNull(widgetTypeService.findSystemWidgetTypesByPageLink(getTenantId(), fullSearchBool, widgetTypeDeprecatedFilter, widgetTypes, pageLink)); + return checkNotNull(widgetTypeService.findSystemWidgetTypesByPageLink(widgetTypeFilter, pageLink)); } else { if (tenantOnly != null && tenantOnly) { - return checkNotNull(widgetTypeService.findTenantWidgetTypesByTenantIdAndPageLink(getTenantId(), fullSearchBool, widgetTypeDeprecatedFilter, widgetTypes, pageLink)); + return checkNotNull(widgetTypeService.findTenantWidgetTypesByTenantIdAndPageLink(widgetTypeFilter, pageLink)); } else { - return checkNotNull(widgetTypeService.findAllTenantWidgetTypesByTenantIdAndPageLink(getTenantId(), fullSearchBool, widgetTypeDeprecatedFilter, widgetTypes, pageLink)); + return checkNotNull(widgetTypeService.findAllTenantWidgetTypesByTenantIdAndPageLink(widgetTypeFilter, pageLink)); } } } diff --git a/application/src/main/java/org/thingsboard/server/controller/WidgetsBundleController.java b/application/src/main/java/org/thingsboard/server/controller/WidgetsBundleController.java index 7289efa7d0..2da97dba58 100644 --- a/application/src/main/java/org/thingsboard/server/controller/WidgetsBundleController.java +++ b/application/src/main/java/org/thingsboard/server/controller/WidgetsBundleController.java @@ -212,7 +212,6 @@ public class WidgetsBundleController extends BaseController { if (Authority.SYS_ADMIN.equals(getCurrentUser().getAuthority())) { return checkNotNull(widgetsBundleService.findSystemWidgetsBundlesByPageLink(widgetsBundleFilter, pageLink)); } else { - TenantId tenantId = getCurrentUser().getTenantId(); if (tenantOnly != null && tenantOnly) { return checkNotNull(widgetsBundleService.findTenantWidgetsBundlesByTenantIdAndPageLink(widgetsBundleFilter, pageLink)); } else { diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/SystemWidgetTypesEdgeEventFetcher.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/SystemWidgetTypesEdgeEventFetcher.java index 7e957fd0fe..2cf47c6abd 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/SystemWidgetTypesEdgeEventFetcher.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/SystemWidgetTypesEdgeEventFetcher.java @@ -20,6 +20,7 @@ import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.widget.DeprecatedFilter; +import org.thingsboard.server.common.data.widget.WidgetTypeFilter; import org.thingsboard.server.common.data.widget.WidgetTypeInfo; import org.thingsboard.server.dao.widget.WidgetTypeService; @@ -32,6 +33,12 @@ public class SystemWidgetTypesEdgeEventFetcher extends BaseWidgetTypesEdgeEventF @Override protected PageData findWidgetTypes(TenantId tenantId, PageLink pageLink) { - return widgetTypeService.findSystemWidgetTypesByPageLink(tenantId, false, DeprecatedFilter.ALL, null, pageLink); + return widgetTypeService.findSystemWidgetTypesByPageLink( + WidgetTypeFilter.builder() + .tenantId(tenantId) + .fullSearch(false) + .deprecatedFilter(DeprecatedFilter.ALL) + .widgetTypes(null).build(), + pageLink); } } diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/SystemWidgetsBundlesEdgeEventFetcher.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/SystemWidgetsBundlesEdgeEventFetcher.java index 5ec2af5fb2..1e6a345db7 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/SystemWidgetsBundlesEdgeEventFetcher.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/SystemWidgetsBundlesEdgeEventFetcher.java @@ -20,6 +20,7 @@ import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.widget.WidgetsBundle; +import org.thingsboard.server.common.data.widget.WidgetsBundleFilter; import org.thingsboard.server.dao.widget.WidgetsBundleService; @Slf4j @@ -31,6 +32,6 @@ public class SystemWidgetsBundlesEdgeEventFetcher extends BaseWidgetsBundlesEdge @Override protected PageData findWidgetsBundles(TenantId tenantId, PageLink pageLink) { - return widgetsBundleService.findSystemWidgetsBundlesByPageLink(tenantId, false, pageLink); + return widgetsBundleService.findSystemWidgetsBundlesByPageLink(WidgetsBundleFilter.fromTenantId(tenantId), pageLink); } } diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/TenantWidgetTypesEdgeEventFetcher.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/TenantWidgetTypesEdgeEventFetcher.java index c2a971a0c0..62fac80fbf 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/TenantWidgetTypesEdgeEventFetcher.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/TenantWidgetTypesEdgeEventFetcher.java @@ -20,6 +20,7 @@ import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.widget.DeprecatedFilter; +import org.thingsboard.server.common.data.widget.WidgetTypeFilter; import org.thingsboard.server.common.data.widget.WidgetTypeInfo; import org.thingsboard.server.dao.widget.WidgetTypeService; @@ -31,6 +32,12 @@ public class TenantWidgetTypesEdgeEventFetcher extends BaseWidgetTypesEdgeEventF } @Override protected PageData findWidgetTypes(TenantId tenantId, PageLink pageLink) { - return widgetTypeService.findTenantWidgetTypesByTenantIdAndPageLink(tenantId, false, DeprecatedFilter.ALL, null, pageLink); + return widgetTypeService.findTenantWidgetTypesByTenantIdAndPageLink( + WidgetTypeFilter.builder() + .tenantId(tenantId) + .fullSearch(false) + .deprecatedFilter(DeprecatedFilter.ALL) + .widgetTypes(null).build(), + pageLink); } } diff --git a/application/src/main/java/org/thingsboard/server/service/install/InstallScripts.java b/application/src/main/java/org/thingsboard/server/service/install/InstallScripts.java index 6a5f3b67e0..7f76ce860f 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/InstallScripts.java +++ b/application/src/main/java/org/thingsboard/server/service/install/InstallScripts.java @@ -364,6 +364,7 @@ public class InstallScripts { scadaSymbolWidget.setImage(symbolUrl); scadaSymbolWidget.setDescription(metadata.getDescription()); scadaSymbolWidget.setTags(metadata.getSearchTags()); + scadaSymbolWidget.setScada(true); ObjectNode defaultConfig = null; if (descriptor.has("defaultConfig")) { defaultConfig = JacksonUtil.fromString(descriptor.get("defaultConfig").asText(), ObjectNode.class); diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/widget/WidgetTypeService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/widget/WidgetTypeService.java index 8effa18c7c..39a5210849 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/widget/WidgetTypeService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/widget/WidgetTypeService.java @@ -23,6 +23,7 @@ import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.widget.DeprecatedFilter; import org.thingsboard.server.common.data.widget.WidgetType; import org.thingsboard.server.common.data.widget.WidgetTypeDetails; +import org.thingsboard.server.common.data.widget.WidgetTypeFilter; import org.thingsboard.server.common.data.widget.WidgetTypeInfo; import org.thingsboard.server.dao.entity.EntityDaoService; @@ -40,11 +41,11 @@ public interface WidgetTypeService extends EntityDaoService { void deleteWidgetType(TenantId tenantId, WidgetTypeId widgetTypeId); - PageData findSystemWidgetTypesByPageLink(TenantId tenantId, boolean fullSearch, DeprecatedFilter deprecatedFilter, List widgetTypes, PageLink pageLink); + PageData findSystemWidgetTypesByPageLink(WidgetTypeFilter widgetTypeFilter, PageLink pageLink); - PageData findAllTenantWidgetTypesByTenantIdAndPageLink(TenantId tenantId, boolean fullSearch, DeprecatedFilter deprecatedFilter, List widgetTypes, PageLink pageLink); + PageData findAllTenantWidgetTypesByTenantIdAndPageLink(WidgetTypeFilter widgetTypeFilter, PageLink pageLink); - PageData findTenantWidgetTypesByTenantIdAndPageLink(TenantId tenantId, boolean fullSearch, DeprecatedFilter deprecatedFilter, List widgetTypes, PageLink pageLink); + PageData findTenantWidgetTypesByTenantIdAndPageLink(WidgetTypeFilter widgetTypeFilter, PageLink pageLink); List findWidgetTypesByWidgetsBundleId(TenantId tenantId, WidgetsBundleId widgetsBundleId); diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/widget/WidgetTypeFilter.java b/common/data/src/main/java/org/thingsboard/server/common/data/widget/WidgetTypeFilter.java new file mode 100644 index 0000000000..e8d1601b64 --- /dev/null +++ b/common/data/src/main/java/org/thingsboard/server/common/data/widget/WidgetTypeFilter.java @@ -0,0 +1,34 @@ +/** + * 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. + */ +package org.thingsboard.server.common.data.widget; + +import lombok.Builder; +import lombok.Data; +import org.thingsboard.server.common.data.id.TenantId; + +import java.util.List; + +@Data +@Builder +public class WidgetTypeFilter { + + private TenantId tenantId; + private boolean fullSearch; + private boolean scadaFirst; + DeprecatedFilter deprecatedFilter; + List widgetTypes; + +} diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/widget/JpaWidgetTypeDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/widget/JpaWidgetTypeDao.java index 27c5ae6ca2..6fb4bcb85d 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/widget/JpaWidgetTypeDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/widget/JpaWidgetTypeDao.java @@ -26,6 +26,7 @@ import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.widget.DeprecatedFilter; import org.thingsboard.server.common.data.widget.WidgetType; import org.thingsboard.server.common.data.widget.WidgetTypeDetails; +import org.thingsboard.server.common.data.widget.WidgetTypeFilter; import org.thingsboard.server.common.data.widget.WidgetTypeInfo; import org.thingsboard.server.common.data.widget.WidgetsBundleWidget; import org.thingsboard.server.dao.DaoUtil; @@ -84,57 +85,60 @@ public class JpaWidgetTypeDao extends JpaAbstractDao findSystemWidgetTypes(TenantId tenantId, boolean fullSearch, DeprecatedFilter deprecatedFilter, List widgetTypes, PageLink pageLink) { - boolean deprecatedFilterEnabled = !DeprecatedFilter.ALL.equals(deprecatedFilter); - boolean deprecatedFilterBool = DeprecatedFilter.DEPRECATED.equals(deprecatedFilter); - boolean widgetTypesEmpty = widgetTypes == null || widgetTypes.isEmpty(); + public PageData findSystemWidgetTypes(WidgetTypeFilter widgetTypeFilter, PageLink pageLink) { + boolean deprecatedFilterEnabled = !DeprecatedFilter.ALL.equals(widgetTypeFilter.getDeprecatedFilter()); + boolean deprecatedFilterBool = DeprecatedFilter.DEPRECATED.equals(widgetTypeFilter.getDeprecatedFilter()); + boolean widgetTypesEmpty = widgetTypeFilter.getWidgetTypes() == null || widgetTypeFilter.getWidgetTypes().isEmpty(); return DaoUtil.toPageData( widgetTypeInfoRepository .findSystemWidgetTypes( NULL_UUID, pageLink.getTextSearch(), - fullSearch, + widgetTypeFilter.isFullSearch(), deprecatedFilterEnabled, deprecatedFilterBool, widgetTypesEmpty, - widgetTypes == null ? Collections.emptyList() : widgetTypes, + widgetTypeFilter.getWidgetTypes() == null ? Collections.emptyList() : widgetTypeFilter.getWidgetTypes(), + widgetTypeFilter.isScadaFirst(), DaoUtil.toPageable(pageLink, WidgetTypeInfoEntity.SEARCH_COLUMNS_MAP))); } @Override - public PageData findAllTenantWidgetTypesByTenantId(UUID tenantId, boolean fullSearch, DeprecatedFilter deprecatedFilter, List widgetTypes, PageLink pageLink) { - boolean deprecatedFilterEnabled = !DeprecatedFilter.ALL.equals(deprecatedFilter); - boolean deprecatedFilterBool = DeprecatedFilter.DEPRECATED.equals(deprecatedFilter); - boolean widgetTypesEmpty = widgetTypes == null || widgetTypes.isEmpty(); + public PageData findAllTenantWidgetTypesByTenantId(WidgetTypeFilter widgetTypeFilter, PageLink pageLink) { + boolean deprecatedFilterEnabled = !DeprecatedFilter.ALL.equals(widgetTypeFilter.getDeprecatedFilter()); + boolean deprecatedFilterBool = DeprecatedFilter.DEPRECATED.equals(widgetTypeFilter.getDeprecatedFilter()); + boolean widgetTypesEmpty = widgetTypeFilter.getWidgetTypes() == null || widgetTypeFilter.getWidgetTypes().isEmpty(); return DaoUtil.toPageData( widgetTypeInfoRepository .findAllTenantWidgetTypesByTenantId( - tenantId, + widgetTypeFilter.getTenantId().getId(), NULL_UUID, pageLink.getTextSearch(), - fullSearch, + widgetTypeFilter.isFullSearch(), deprecatedFilterEnabled, deprecatedFilterBool, widgetTypesEmpty, - widgetTypes == null ? Collections.emptyList() : widgetTypes, + widgetTypeFilter.getWidgetTypes() == null ? Collections.emptyList() : widgetTypeFilter.getWidgetTypes(), + widgetTypeFilter.isScadaFirst(), DaoUtil.toPageable(pageLink, WidgetTypeInfoEntity.SEARCH_COLUMNS_MAP))); } @Override - public PageData findTenantWidgetTypesByTenantId(UUID tenantId, boolean fullSearch, DeprecatedFilter deprecatedFilter, List widgetTypes, PageLink pageLink) { - boolean deprecatedFilterEnabled = !DeprecatedFilter.ALL.equals(deprecatedFilter); - boolean deprecatedFilterBool = DeprecatedFilter.DEPRECATED.equals(deprecatedFilter); - boolean widgetTypesEmpty = widgetTypes == null || widgetTypes.isEmpty(); + public PageData findTenantWidgetTypesByTenantId(WidgetTypeFilter widgetTypeFilter, PageLink pageLink) { + boolean deprecatedFilterEnabled = !DeprecatedFilter.ALL.equals(widgetTypeFilter.getDeprecatedFilter()); + boolean deprecatedFilterBool = DeprecatedFilter.DEPRECATED.equals(widgetTypeFilter.getDeprecatedFilter()); + boolean widgetTypesEmpty = widgetTypeFilter.getWidgetTypes() == null || widgetTypeFilter.getWidgetTypes().isEmpty(); return DaoUtil.toPageData( widgetTypeInfoRepository .findTenantWidgetTypesByTenantId( - tenantId, + widgetTypeFilter.getTenantId().getId(), pageLink.getTextSearch(), - fullSearch, + widgetTypeFilter.isFullSearch(), deprecatedFilterEnabled, deprecatedFilterBool, widgetTypesEmpty, - widgetTypes == null ? Collections.emptyList() : widgetTypes, + widgetTypeFilter.getWidgetTypes() == null ? Collections.emptyList() : widgetTypeFilter.getWidgetTypes(), + widgetTypeFilter.isScadaFirst(), DaoUtil.toPageable(pageLink, WidgetTypeInfoEntity.SEARCH_COLUMNS_MAP))); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/widget/WidgetTypeInfoRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/widget/WidgetTypeInfoRepository.java index 85079bb7a8..4b85fcb7dc 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/widget/WidgetTypeInfoRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/widget/WidgetTypeInfoRepository.java @@ -41,7 +41,8 @@ public interface WidgetTypeInfoRepository extends JpaRepository widgetTypes, + @Param("scadaFirst") boolean scadaFirst, Pageable pageable); @Query(nativeQuery = true, @@ -80,7 +82,8 @@ public interface WidgetTypeInfoRepository extends JpaRepository widgetTypes, + @Param("scadaFirst") boolean scadaFirst, Pageable pageable); @Query(nativeQuery = true, @@ -120,7 +124,8 @@ public interface WidgetTypeInfoRepository extends JpaRepository widgetTypes, + @Param("scadaFirst") boolean scadaFirst, Pageable pageable); @Query("SELECT wti FROM WidgetTypeInfoEntity wti, WidgetsBundleWidgetEntity wbw " + diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/widget/WidgetsBundleRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/widget/WidgetsBundleRepository.java index 54ca67527c..1b4cafe404 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/widget/WidgetsBundleRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/widget/WidgetsBundleRepository.java @@ -107,7 +107,7 @@ public interface WidgetsBundleRepository extends JpaRepository, ExportableEntityD boolean existsByTenantIdAndId(TenantId tenantId, UUID widgetTypeId); - PageData findSystemWidgetTypes(TenantId tenantId, boolean fullSearch, DeprecatedFilter deprecatedFilter, List widgetTypes, PageLink pageLink); + PageData findSystemWidgetTypes(WidgetTypeFilter widgetTypeFilter, PageLink pageLink); - PageData findAllTenantWidgetTypesByTenantId(UUID tenantId, boolean fullSearch, DeprecatedFilter deprecatedFilter, List widgetTypes, PageLink pageLink); + PageData findAllTenantWidgetTypesByTenantId(WidgetTypeFilter widgetTypeFilter, PageLink pageLink); - PageData findTenantWidgetTypesByTenantId(UUID tenantId, boolean fullSearch, DeprecatedFilter deprecatedFilter, List widgetTypes, PageLink pageLink); + PageData findTenantWidgetTypesByTenantId(WidgetTypeFilter widgetTypeFilter, PageLink pageLink); /** * Find widget types by widgetsBundleId. 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 33c9442363..3e2fe0bf35 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 @@ -30,6 +30,7 @@ import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.widget.DeprecatedFilter; import org.thingsboard.server.common.data.widget.WidgetType; import org.thingsboard.server.common.data.widget.WidgetTypeDetails; +import org.thingsboard.server.common.data.widget.WidgetTypeFilter; import org.thingsboard.server.common.data.widget.WidgetTypeInfo; import org.thingsboard.server.common.data.widget.WidgetsBundleWidget; import org.thingsboard.server.dao.entity.AbstractCachedEntityService; @@ -121,28 +122,30 @@ public class WidgetTypeServiceImpl implements WidgetTypeService { } @Override - public PageData findSystemWidgetTypesByPageLink(TenantId tenantId, boolean fullSearch, DeprecatedFilter deprecatedFilter, List widgetTypes, PageLink pageLink) { - log.trace("Executing findSystemWidgetTypesByPageLink, fullSearch [{}], deprecatedFilter [{}], widgetTypes [{}], pageLink [{}]", fullSearch, deprecatedFilter, widgetTypes, pageLink); + public PageData findSystemWidgetTypesByPageLink(WidgetTypeFilter widgetTypeFilter, PageLink pageLink) { + log.trace("Executing findSystemWidgetTypesByPageLink, pageLink [{}]", pageLink); Validator.validatePageLink(pageLink); - return widgetTypeDao.findSystemWidgetTypes(tenantId, fullSearch, deprecatedFilter, widgetTypes, pageLink); + return widgetTypeDao.findSystemWidgetTypes(widgetTypeFilter, pageLink); } @Override - public PageData findAllTenantWidgetTypesByTenantIdAndPageLink(TenantId tenantId, boolean fullSearch, DeprecatedFilter deprecatedFilter, List widgetTypes, PageLink pageLink) { - log.trace("Executing findAllTenantWidgetTypesByTenantIdAndPageLink, tenantId [{}], fullSearch [{}], deprecatedFilter [{}], widgetTypes [{}], pageLink [{}]", - tenantId, fullSearch, deprecatedFilter, widgetTypes, pageLink); + public PageData findAllTenantWidgetTypesByTenantIdAndPageLink(WidgetTypeFilter widgetTypeFilter, PageLink pageLink) { + TenantId tenantId = widgetTypeFilter.getTenantId(); + log.trace("Executing findAllTenantWidgetTypesByTenantIdAndPageLink, tenantId [{}], pageLink [{}]", + tenantId, pageLink); Validator.validateId(tenantId, id -> INCORRECT_TENANT_ID + id); Validator.validatePageLink(pageLink); - return widgetTypeDao.findAllTenantWidgetTypesByTenantId(tenantId.getId(), fullSearch, deprecatedFilter, widgetTypes, pageLink); + return widgetTypeDao.findAllTenantWidgetTypesByTenantId(widgetTypeFilter, pageLink); } @Override - public PageData findTenantWidgetTypesByTenantIdAndPageLink(TenantId tenantId, boolean fullSearch, DeprecatedFilter deprecatedFilter, List widgetTypes, PageLink pageLink) { - log.trace("Executing findTenantWidgetTypesByTenantIdAndPageLink, tenantId [{}], fullSearch [{}], deprecatedFilter [{}], widgetTypes [{}], pageLink [{}]", - tenantId, fullSearch, deprecatedFilter, widgetTypes, pageLink); + public PageData findTenantWidgetTypesByTenantIdAndPageLink(WidgetTypeFilter widgetTypeFilter, PageLink pageLink) { + TenantId tenantId = widgetTypeFilter.getTenantId(); + log.trace("Executing findTenantWidgetTypesByTenantIdAndPageLink, tenantId [{}], pageLink [{}]", + tenantId, pageLink); Validator.validateId(tenantId, id -> INCORRECT_TENANT_ID + id); Validator.validatePageLink(pageLink); - return widgetTypeDao.findTenantWidgetTypesByTenantId(tenantId.getId(), fullSearch, deprecatedFilter, widgetTypes, pageLink); + return widgetTypeDao.findTenantWidgetTypesByTenantId(widgetTypeFilter, pageLink); } @Override @@ -260,7 +263,13 @@ public class WidgetTypeServiceImpl implements WidgetTypeService { @Override protected PageData findEntities(TenantId tenantId, TenantId id, PageLink pageLink) { - return widgetTypeDao.findTenantWidgetTypesByTenantId(id.getId(), false, DeprecatedFilter.ALL, null, pageLink); + return widgetTypeDao.findTenantWidgetTypesByTenantId( + WidgetTypeFilter.builder() + .tenantId(id) + .fullSearch(false) + .deprecatedFilter(DeprecatedFilter.ALL) + .widgetTypes(null).build(), + pageLink); } @Override diff --git a/dao/src/test/java/org/thingsboard/server/dao/sql/widget/JpaWidgetTypeDaoTest.java b/dao/src/test/java/org/thingsboard/server/dao/sql/widget/JpaWidgetTypeDaoTest.java index e8f3bba9db..8010eab4cd 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/sql/widget/JpaWidgetTypeDaoTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/sql/widget/JpaWidgetTypeDaoTest.java @@ -31,6 +31,7 @@ import org.thingsboard.server.common.data.widget.BaseWidgetType; import org.thingsboard.server.common.data.widget.DeprecatedFilter; import org.thingsboard.server.common.data.widget.WidgetType; import org.thingsboard.server.common.data.widget.WidgetTypeDetails; +import org.thingsboard.server.common.data.widget.WidgetTypeFilter; import org.thingsboard.server.common.data.widget.WidgetTypeInfo; import org.thingsboard.server.common.data.widget.WidgetsBundle; import org.thingsboard.server.common.data.widget.WidgetsBundleWidget; @@ -151,12 +152,22 @@ public class JpaWidgetTypeDaoTest extends AbstractJpaDaoTest { @Test public void testFindSystemWidgetTypes() { - PageData widgetTypes = widgetTypeDao.findSystemWidgetTypes(TenantId.SYS_TENANT_ID, true, DeprecatedFilter.ALL, Collections.singletonList("static"), + PageData widgetTypes = widgetTypeDao.findSystemWidgetTypes( + WidgetTypeFilter.builder() + .tenantId(TenantId.SYS_TENANT_ID) + .fullSearch(true) + .deprecatedFilter(DeprecatedFilter.ALL) + .widgetTypes(Collections.singletonList("static")).build(), new PageLink(1024, 0, "TYPE_DESCRIPTION", new SortOrder("createdTime"))); assertEquals(1, widgetTypes.getData().size()); assertEquals(new WidgetTypeInfo(widgetTypeList.get(1)), widgetTypes.getData().get(0)); - widgetTypes = widgetTypeDao.findSystemWidgetTypes(TenantId.SYS_TENANT_ID, true, DeprecatedFilter.ALL, Collections.emptyList(), + widgetTypes = widgetTypeDao.findSystemWidgetTypes( + WidgetTypeFilter.builder() + .tenantId(TenantId.SYS_TENANT_ID) + .fullSearch(true) + .deprecatedFilter(DeprecatedFilter.ALL) + .widgetTypes(Collections.emptyList()).build(), new PageLink(1024, 0, "hfgfd tag2_2 ghg", new SortOrder("createdTime"))); assertEquals(1, widgetTypes.getData().size()); assertEquals(new WidgetTypeInfo(widgetTypeList.get(2)), widgetTypes.getData().get(0)); @@ -175,12 +186,21 @@ public class JpaWidgetTypeDaoTest extends AbstractJpaDaoTest { sameNameList.sort(Comparator.comparing(BaseWidgetType::getName).thenComparing((BaseWidgetType baseWidgetType) -> baseWidgetType.getId().getId())); List expected = sameNameList.stream().map(WidgetTypeInfo::new).collect(Collectors.toList()); - PageData widgetTypesFirstPage = widgetTypeDao.findSystemWidgetTypes(TenantId.SYS_TENANT_ID, true, DeprecatedFilter.ALL, Collections.singletonList("static"), + PageData widgetTypesFirstPage = widgetTypeDao.findSystemWidgetTypes( + WidgetTypeFilter.builder() + .tenantId(TenantId.SYS_TENANT_ID) + .fullSearch(true) + .deprecatedFilter(DeprecatedFilter.ALL) + .widgetTypes(Collections.singletonList("static")).build(), new PageLink(10, 0, null, new SortOrder("name"))); assertEquals(10, widgetTypesFirstPage.getData().size()); assertThat(widgetTypesFirstPage.getData()).containsExactlyElementsOf(expected.subList(0, 10)); - PageData widgetTypesSecondPage = widgetTypeDao.findSystemWidgetTypes(TenantId.SYS_TENANT_ID, true, DeprecatedFilter.ALL, Collections.singletonList("static"), + PageData widgetTypesSecondPage = widgetTypeDao.findSystemWidgetTypes(WidgetTypeFilter.builder() + .tenantId(TenantId.SYS_TENANT_ID) + .fullSearch(true) + .deprecatedFilter(DeprecatedFilter.ALL) + .widgetTypes(Collections.singletonList("static")).build(), new PageLink(10, 1, null, new SortOrder("name"))); assertEquals(10, widgetTypesSecondPage.getData().size()); assertThat(widgetTypesSecondPage.getData()).containsExactlyElementsOf(expected.subList(10, 20)); @@ -195,7 +215,12 @@ public class JpaWidgetTypeDaoTest extends AbstractJpaDaoTest { WidgetTypeDetails savedWidgetType = createAndSaveWidgetType(TenantId.SYS_TENANT_ID, WIDGET_TYPE_COUNT + 1, tags); PageData widgetTypes = widgetTypeDao.findSystemWidgetTypes( - TenantId.SYS_TENANT_ID, true, DeprecatedFilter.ALL, null, new PageLink(10, 0, searchText) + WidgetTypeFilter.builder() + .tenantId(TenantId.SYS_TENANT_ID) + .fullSearch(true) + .deprecatedFilter(DeprecatedFilter.ALL) + .widgetTypes(null).build(), + new PageLink(10, 0, searchText) ); assertThat(widgetTypes.getData()).hasSize(1); @@ -211,7 +236,12 @@ public class JpaWidgetTypeDaoTest extends AbstractJpaDaoTest { WidgetTypeDetails savedWidgetType = createAndSaveWidgetType(TenantId.SYS_TENANT_ID, WIDGET_TYPE_COUNT + 1, tags); PageData widgetTypes = widgetTypeDao.findSystemWidgetTypes( - TenantId.SYS_TENANT_ID, true, DeprecatedFilter.ALL, null, new PageLink(10, 0, searchText) + WidgetTypeFilter.builder() + .tenantId(TenantId.SYS_TENANT_ID) + .fullSearch(true) + .deprecatedFilter(DeprecatedFilter.ALL) + .widgetTypes(null).build(), + new PageLink(10, 0, searchText) ); assertThat(widgetTypes.getData()).hasSize(0); @@ -227,7 +257,12 @@ public class JpaWidgetTypeDaoTest extends AbstractJpaDaoTest { var widgetType = createAndSaveWidgetType(new TenantId(tenantId), i); widgetTypeList.add(widgetType); } - PageData widgetTypes = widgetTypeDao.findTenantWidgetTypesByTenantId(tenantId, true, DeprecatedFilter.ALL, null, + PageData widgetTypes = widgetTypeDao.findTenantWidgetTypesByTenantId( + WidgetTypeFilter.builder() + .tenantId(new TenantId(tenantId)) + .fullSearch(true) + .deprecatedFilter(DeprecatedFilter.ALL) + .widgetTypes(null).build(), new PageLink(10, 0, "", new SortOrder("createdTime"))); assertEquals(WIDGET_TYPE_COUNT, widgetTypes.getData().size()); assertEquals(new WidgetTypeInfo(widgetTypeList.get(3)), widgetTypes.getData().get(0)); @@ -244,7 +279,12 @@ public class JpaWidgetTypeDaoTest extends AbstractJpaDaoTest { WidgetTypeDetails savedWidgetType = createAndSaveWidgetType(TenantId.SYS_TENANT_ID, WIDGET_TYPE_COUNT + 1, tags); PageData widgetTypes = widgetTypeDao.findTenantWidgetTypesByTenantId( - TenantId.SYS_TENANT_ID.getId(), true, DeprecatedFilter.ALL, null, new PageLink(10, 0, searchText) + WidgetTypeFilter.builder() + .tenantId(TenantId.SYS_TENANT_ID) + .fullSearch(true) + .deprecatedFilter(DeprecatedFilter.ALL) + .widgetTypes(null).build(), + new PageLink(10, 0, searchText) ); assertThat(widgetTypes.getData()).hasSize(1); @@ -260,7 +300,12 @@ public class JpaWidgetTypeDaoTest extends AbstractJpaDaoTest { WidgetTypeDetails savedWidgetType = createAndSaveWidgetType(TenantId.SYS_TENANT_ID, WIDGET_TYPE_COUNT + 1, tags); PageData widgetTypes = widgetTypeDao.findTenantWidgetTypesByTenantId( - TenantId.SYS_TENANT_ID.getId(), true, DeprecatedFilter.ALL, null, new PageLink(10, 0, searchText) + WidgetTypeFilter.builder() + .tenantId(TenantId.SYS_TENANT_ID) + .fullSearch(true) + .deprecatedFilter(DeprecatedFilter.ALL) + .widgetTypes(null).build(), + new PageLink(10, 0, searchText) ); assertThat(widgetTypes.getData()).hasSize(0); @@ -278,7 +323,12 @@ public class JpaWidgetTypeDaoTest extends AbstractJpaDaoTest { WidgetTypeDetails savedWidgetType = createAndSaveWidgetType(TenantId.SYS_TENANT_ID, WIDGET_TYPE_COUNT + 1, tags); PageData widgetTypes = widgetTypeDao.findAllTenantWidgetTypesByTenantId( - TenantId.SYS_TENANT_ID.getId(), true, DeprecatedFilter.ALL, null, new PageLink(10, 0, searchText) + WidgetTypeFilter.builder() + .tenantId(TenantId.SYS_TENANT_ID) + .fullSearch(true) + .deprecatedFilter(DeprecatedFilter.ALL) + .widgetTypes(null).build(), + new PageLink(10, 0, searchText) ); assertThat(widgetTypes.getData()).hasSize(1); @@ -294,7 +344,12 @@ public class JpaWidgetTypeDaoTest extends AbstractJpaDaoTest { WidgetTypeDetails savedWidgetType = createAndSaveWidgetType(TenantId.SYS_TENANT_ID, WIDGET_TYPE_COUNT + 1, tags); PageData widgetTypes = widgetTypeDao.findAllTenantWidgetTypesByTenantId( - TenantId.SYS_TENANT_ID.getId(), true, DeprecatedFilter.ALL, null, new PageLink(10, 0, searchText) + WidgetTypeFilter.builder() + .tenantId(TenantId.SYS_TENANT_ID) + .fullSearch(true) + .deprecatedFilter(DeprecatedFilter.ALL) + .widgetTypes(null).build(), + new PageLink(10, 0, searchText) ); assertThat(widgetTypes.getData()).hasSize(0); diff --git a/dao/src/test/java/org/thingsboard/server/dao/sql/widget/JpaWidgetsBundleDaoTest.java b/dao/src/test/java/org/thingsboard/server/dao/sql/widget/JpaWidgetsBundleDaoTest.java index ae68b7457f..5ec50189c4 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/sql/widget/JpaWidgetsBundleDaoTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/sql/widget/JpaWidgetsBundleDaoTest.java @@ -43,6 +43,8 @@ import java.util.stream.Collectors; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; public class JpaWidgetsBundleDaoTest extends AbstractJpaDaoTest { @@ -311,6 +313,52 @@ public class JpaWidgetsBundleDaoTest extends AbstractJpaDaoTest { assertEquals(widgetsBundle3, widgetsBundles5.getData().get(0)); } + @Test + public void testFindAllWidgetsBundlesByTenantIdFullSearchScadaFirst() { + UUID tenantId1 = Uuids.timeBased(); + UUID tenantId2 = Uuids.timeBased(); + for (int i = 0; i < 10; i++) { + createWidgetBundles(5, tenantId1, "WB1_" + i + "_"); + createWidgetBundles(2, tenantId1, "WB1_SCADA_" + i + "_", true); + createWidgetBundles(3, tenantId2, "WB2_" + i + "_"); + createWidgetBundles(3, tenantId2, "WB2_SCADA_" + i + "_", true); + createSystemWidgetBundles(2, "WB_SYS_" + i + "_"); + createSystemWidgetBundles(1, "WB_SYS_SCADA_" + i + "_", true); + } + widgetsBundles = widgetsBundleDao.find(TenantId.SYS_TENANT_ID).stream().sorted(Comparator.comparing(WidgetsBundle::getTitle)).collect(Collectors.toList());; + assertEquals(160, widgetsBundles.size()); + + PageLink pageLink = new PageLink(50, 0, "WB", new SortOrder("title")); + PageData widgetsBundles1 = + widgetsBundleDao.findAllTenantWidgetsBundlesByTenantId( + WidgetsBundleFilter.builder().tenantId(TenantId.fromUUID(tenantId1)).fullSearch(true).scadaFirst(true).build(), pageLink); + + for (int i =0; i < 30; i++) { + var widgetsBundle = widgetsBundles1.getData().get(i); + assertTrue(widgetsBundle.isScada()); + } + + for (int i = 30; i < 50; i++) { + var widgetsBundle = widgetsBundles1.getData().get(i); + assertFalse(widgetsBundle.isScada()); + } + + pageLink = new PageLink(50, 0, "WB", new SortOrder("title")); + PageData widgetsBundles2 = + widgetsBundleDao.findAllTenantWidgetsBundlesByTenantId( + WidgetsBundleFilter.builder().tenantId(TenantId.fromUUID(tenantId2)).fullSearch(true).scadaFirst(true).build(), pageLink); + + for (int i =0; i < 40; i++) { + var widgetsBundle = widgetsBundles2.getData().get(i); + assertTrue(widgetsBundle.isScada()); + } + + for (int i = 40; i < 50; i++) { + var widgetsBundle = widgetsBundles2.getData().get(i); + assertFalse(widgetsBundle.isScada()); + } + } + @Test public void testTagsSearchInFindAllWidgetsBundlesByTenantId() { for (var entry : SHOULD_FIND_SEARCH_TO_TAGS_MAP.entrySet()) { @@ -397,14 +445,22 @@ public class JpaWidgetsBundleDaoTest extends AbstractJpaDaoTest { } private void createWidgetBundles(int count, UUID tenantId, String prefix) { + createWidgetBundles(count, tenantId, prefix, false); + } + + private void createWidgetBundles(int count, UUID tenantId, String prefix, boolean scada) { for (int i = 0; i < count; i++) { - createWidgetsBundle(TenantId.fromUUID(tenantId), prefix + i, prefix + i, null); + createWidgetsBundle(TenantId.fromUUID(tenantId), prefix + i, prefix + i, null, scada); } } private void createSystemWidgetBundles(int count, String prefix) { + createSystemWidgetBundles(count, prefix, false); + } + + private void createSystemWidgetBundles(int count, String prefix, boolean scada) { for (int i = 0; i < count; i++) { - createWidgetsBundle(TenantId.SYS_TENANT_ID, prefix + i, prefix + i, null); + createWidgetsBundle(TenantId.SYS_TENANT_ID, prefix + i, prefix + i, null, scada); } } @@ -413,12 +469,17 @@ public class JpaWidgetsBundleDaoTest extends AbstractJpaDaoTest { } private WidgetsBundle createWidgetsBundle(TenantId tenantId, String alias, String title, Integer order) { + return createWidgetsBundle(tenantId, alias, title, order, false); + } + + private WidgetsBundle createWidgetsBundle(TenantId tenantId, String alias, String title, Integer order, boolean scada) { WidgetsBundle widgetsBundle = new WidgetsBundle(); widgetsBundle.setAlias(alias); widgetsBundle.setTitle(title); widgetsBundle.setTenantId(tenantId); widgetsBundle.setId(new WidgetsBundleId(Uuids.timeBased())); widgetsBundle.setOrder(order); + widgetsBundle.setScada(scada); return widgetsBundleDao.save(TenantId.SYS_TENANT_ID, widgetsBundle); } diff --git a/ui-ngx/src/app/core/http/entity.service.ts b/ui-ngx/src/app/core/http/entity.service.ts index b5b2b0e796..7446d67601 100644 --- a/ui-ngx/src/app/core/http/entity.service.ts +++ b/ui-ngx/src/app/core/http/entity.service.ts @@ -427,11 +427,11 @@ export class EntityService { break; case EntityType.WIDGETS_BUNDLE: pageLink.sortOrder.property = 'title'; - entitiesObservable = this.widgetService.getWidgetBundles(pageLink, false, true, config); + entitiesObservable = this.widgetService.getWidgetBundles(pageLink, false, true, false, config); break; case EntityType.WIDGET_TYPE: pageLink.sortOrder.property = 'name'; - entitiesObservable = this.widgetService.getWidgetTypes(pageLink, true, false, DeprecatedFilter.ALL, null, config); + entitiesObservable = this.widgetService.getWidgetTypes(pageLink, true, false, false, DeprecatedFilter.ALL, null, config); break; case EntityType.NOTIFICATION_TARGET: pageLink.sortOrder.property = 'name'; diff --git a/ui-ngx/src/app/core/http/widget.service.ts b/ui-ngx/src/app/core/http/widget.service.ts index 6f455189a7..b172b61a1d 100644 --- a/ui-ngx/src/app/core/http/widget.service.ts +++ b/ui-ngx/src/app/core/http/widget.service.ts @@ -86,9 +86,9 @@ export class WidgetService { } public getWidgetBundles(pageLink: PageLink, fullSearch = false, - tenantOnly = false, config?: RequestConfig): Observable> { + tenantOnly = false, scadaFirst = false, config?: RequestConfig): Observable> { return this.http.get>( - `/api/widgetsBundles${pageLink.toQuery()}&tenantOnly=${tenantOnly}&fullSearch=${fullSearch}`, + `/api/widgetsBundles${pageLink.toQuery()}&tenantOnly=${tenantOnly}&fullSearch=${fullSearch}&scadaFirst=${scadaFirst}`, defaultHttpOptionsFromConfig(config) ); } @@ -240,10 +240,13 @@ export class WidgetService { } public getWidgetTypes(pageLink: PageLink, tenantOnly = false, - fullSearch = false, deprecatedFilter = DeprecatedFilter.ALL, widgetTypes: Array = null, + fullSearch = false, scadaFirst = false, + deprecatedFilter = DeprecatedFilter.ALL, + widgetTypes: Array = null, config?: RequestConfig): Observable> { let url = - `/api/widgetTypes${pageLink.toQuery()}&tenantOnly=${tenantOnly}&fullSearch=${fullSearch}&deprecatedFilter=${deprecatedFilter}`; + `/api/widgetTypes${pageLink.toQuery()}&tenantOnly=${tenantOnly}&fullSearch=${fullSearch} + &scadaFirst=${scadaFirst}&deprecatedFilter=${deprecatedFilter}`; if (widgetTypes && widgetTypes.length) { url += `&widgetTypeList=${widgetTypes.join(',')}`; } diff --git a/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.html b/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.html index e923036571..a77247b9da 100644 --- a/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.html +++ b/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.html @@ -442,6 +442,7 @@ *ngIf="isAddingWidget" [aliasController]="dashboardCtx.aliasController" [filterWidgetTypes]="filterWidgetTypes" + [scadaFirst]="layouts.main.layoutCtx.gridSettings.layoutType === LayoutType.scada" (widgetSelected)="addWidgetFromType($event)"> diff --git a/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.ts b/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.ts index ff2d6eab59..76a4fdbb99 100644 --- a/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.ts +++ b/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.ts @@ -166,6 +166,8 @@ import { }) export class DashboardPageComponent extends PageComponent implements IDashboardController, HasDirtyFlag, OnInit, AfterViewInit, OnDestroy { + LayoutType = LayoutType; + private forcePristine = false; get isDirty(): boolean { diff --git a/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-widget-select.component.ts b/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-widget-select.component.ts index eae54c657f..63b09ee344 100644 --- a/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-widget-select.component.ts +++ b/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-widget-select.component.ts @@ -33,6 +33,7 @@ import { PageLink } from '@shared/models/page/page-link'; import { Direction } from '@shared/models/page/sort-order'; import { GridEntitiesFetchFunction, ScrollGridColumns } from '@shared/components/grid/scroll-grid-datasource'; import { ItemSizeStrategy } from '@shared/components/grid/scroll-grid.component'; +import { coerceBoolean } from '@shared/decorators/coercion'; type selectWidgetMode = 'bundles' | 'allWidgets'; @@ -69,6 +70,10 @@ export class DashboardWidgetSelectComponent implements OnInit { @Input() aliasController: IAliasController; + @Input() + @coerceBoolean() + scadaFirst = false; + @Input() set search(search: string) { this.searchSubject.next(search); @@ -170,7 +175,7 @@ export class DashboardWidgetSelectComponent implements OnInit { property: 'title', direction: Direction.ASC }); - return this.widgetsService.getWidgetBundles(pageLink, true); + return this.widgetsService.getWidgetBundles(pageLink, true, false, this.scadaFirst); }; this.allWidgetsFetchFunction = (pageSize, page, filter) => { @@ -178,7 +183,8 @@ export class DashboardWidgetSelectComponent implements OnInit { property: 'name', direction: Direction.ASC }); - return this.widgetsService.getWidgetTypes(pageLink, false, true, filter.deprecatedFilter, filter.filter); + return this.widgetsService.getWidgetTypes(pageLink, false, true, this.scadaFirst, + filter.deprecatedFilter, filter.filter); }; this.widgetsFetchFunction = (pageSize, page, filter) => { diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/scada/scada-symbol-widget.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/scada/scada-symbol-widget.component.html index 55921d0e0b..da2b80c7ce 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/scada/scada-symbol-widget.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/scada/scada-symbol-widget.component.html @@ -23,6 +23,7 @@
+
scada.no-symbol-selected
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/scada/scada-symbol-widget.component.scss b/ui-ngx/src/app/modules/home/components/widget/lib/scada/scada-symbol-widget.component.scss index 5d512f6ef7..c926e0a4b0 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/scada/scada-symbol-widget.component.scss +++ b/ui-ngx/src/app/modules/home/components/widget/lib/scada/scada-symbol-widget.component.scss @@ -46,5 +46,18 @@ align-items: center; justify-content: center; } + .tb-no-scada-symbol { + position: absolute; + inset: 0; + display: flex; + align-items: center; + justify-content: center; + text-align: center; + color: rgba(0, 0, 0, 0.87); + font-size: 16px; + font-style: normal; + font-weight: 400; + line-height: 16px; + } } } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/scada/scada-symbol-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/scada/scada-symbol-widget.component.ts index 2f5136bf2a..6db0d202c7 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/scada/scada-symbol-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/scada/scada-symbol-widget.component.ts @@ -69,6 +69,7 @@ export class ScadaSymbolWidgetComponent implements OnInit, AfterViewInit, OnDest loading$ = this.loadingSubject.asObservable().pipe(share()); scadaSymbolObject: ScadaSymbolObject; + noScadaSymbol = false; constructor(public widgetComponent: WidgetComponent, protected imagePipe: ImagePipe, @@ -89,9 +90,9 @@ export class ScadaSymbolWidgetComponent implements OnInit, AfterViewInit, OnDest this.scadaSymbolContent$ = of(this.settings.scadaSymbolContent); } else if (this.settings.scadaSymbolUrl) { this.scadaSymbolContent$ = this.imageService.getImageString(this.settings.scadaSymbolUrl) - .pipe(catchError(() => of(''))); + .pipe(catchError(() => of('empty'))); } else { - this.scadaSymbolContent$ = of(''); + this.scadaSymbolContent$ = of('empty'); } } @@ -133,6 +134,9 @@ export class ScadaSymbolWidgetComponent implements OnInit, AfterViewInit, OnDest this.ctx.isPreview || (isDefinedAndNotNull(this.settings.simulated) ? this.settings.simulated : false); if (content.startsWith(' ({ widgetName: widgetTypeEntity.name, fullFqn: fullWidgetTypeFqn(widgetTypeEntity), deprecated: widgetTypeEntity.deprecated, + scada: widgetTypeEntity.scada, type: widgetTypeEntity.descriptor.type, sizeX: widgetTypeEntity.descriptor.sizeX, sizeY: widgetTypeEntity.descriptor.sizeY, @@ -685,6 +689,7 @@ export const toWidgetType = (widgetInfo: WidgetInfo, id: WidgetTypeId, tenantId: fqn: widgetTypeFqn(widgetInfo.fullFqn), name: widgetInfo.widgetName, deprecated: widgetInfo.deprecated, + scada: widgetInfo.scada, descriptor }; }; diff --git a/ui-ngx/src/app/modules/home/pages/widget/widget-editor.component.html b/ui-ngx/src/app/modules/home/pages/widget/widget-editor.component.html index 11329df694..19f306fad8 100644 --- a/ui-ngx/src/app/modules/home/pages/widget/widget-editor.component.html +++ b/ui-ngx/src/app/modules/home/pages/widget/widget-editor.component.html @@ -257,11 +257,18 @@ [(ngModel)]="widget.tags" (ngModelChange)="isDirty = true"> - - {{ 'widget.deprecated' | translate }} - +
+ + {{ 'widget.scada' | translate }} + + + {{ 'widget.deprecated' | translate }} + +
widget.settings-form-selector - - {{ 'widget.deprecated' | translate }} - +
+ + {{ 'widget.scada' | translate }} + + + {{ 'widget.deprecated' | translate }} + +
diff --git a/ui-ngx/src/app/modules/home/pages/widget/widget-type.component.ts b/ui-ngx/src/app/modules/home/pages/widget/widget-type.component.ts index 79dbab63cf..b442fb7482 100644 --- a/ui-ngx/src/app/modules/home/pages/widget/widget-type.component.ts +++ b/ui-ngx/src/app/modules/home/pages/widget/widget-type.component.ts @@ -53,6 +53,7 @@ export class WidgetTypeComponent extends EntityComponent { image: [entity ? entity.image : ''], description: [entity ? entity.description : '', Validators.maxLength(1024)], tags: [entity ? entity.tags : []], + scada: [entity ? entity.scada : false], deprecated: [entity ? entity.deprecated : false] } ); @@ -64,6 +65,7 @@ export class WidgetTypeComponent extends EntityComponent { image: entity.image, description: entity.description, tags: entity.tags, + scada: entity.scada, deprecated: entity.deprecated }); } diff --git a/ui-ngx/src/app/modules/home/pages/widget/widgets-bundle.component.html b/ui-ngx/src/app/modules/home/pages/widget/widgets-bundle.component.html index 5e3e4fe6ab..f95d085688 100644 --- a/ui-ngx/src/app/modules/home/pages/widget/widgets-bundle.component.html +++ b/ui-ngx/src/app/modules/home/pages/widget/widgets-bundle.component.html @@ -63,6 +63,9 @@ {{descriptionInput.value?.length || 0}}/1024
+ + {{ 'widgets-bundle.scada' | translate }} + widgets-bundle.order diff --git a/ui-ngx/src/app/modules/home/pages/widget/widgets-bundle.component.ts b/ui-ngx/src/app/modules/home/pages/widget/widgets-bundle.component.ts index 845ece44f0..ca0912ea11 100644 --- a/ui-ngx/src/app/modules/home/pages/widget/widgets-bundle.component.ts +++ b/ui-ngx/src/app/modules/home/pages/widget/widgets-bundle.component.ts @@ -51,6 +51,7 @@ export class WidgetsBundleComponent extends EntityComponent { title: [entity ? entity.title : '', [Validators.required, Validators.maxLength(255)]], image: [entity ? entity.image : ''], description: [entity ? entity.description : '', Validators.maxLength(1024)], + scada: [entity ? entity.scada : false], order: [entity ? entity.order : null] } ); @@ -61,6 +62,7 @@ export class WidgetsBundleComponent extends EntityComponent { title: entity.title, image: entity.image, description: entity.description, + scada: entity.scada, order: entity.order }); } diff --git a/ui-ngx/src/app/shared/models/widget.models.ts b/ui-ngx/src/app/shared/models/widget.models.ts index 3646f3cdc5..e46e579f52 100644 --- a/ui-ngx/src/app/shared/models/widget.models.ts +++ b/ui-ngx/src/app/shared/models/widget.models.ts @@ -204,6 +204,7 @@ export interface BaseWidgetType extends BaseData, HasTenantId { fqn: string; name: string; deprecated: boolean; + scada: boolean; } export const fullWidgetTypeFqn = (type: BaseWidgetType): string => @@ -361,7 +362,7 @@ export interface DataKey extends KeyInfo { _hash?: number; } -export type CellClickColumnInfo = Pick +export type CellClickColumnInfo = Pick; export enum DataKeyConfigMode { general = 'general', diff --git a/ui-ngx/src/app/shared/models/widgets-bundle.model.ts b/ui-ngx/src/app/shared/models/widgets-bundle.model.ts index 9a6dbb5700..f2bca32a8f 100644 --- a/ui-ngx/src/app/shared/models/widgets-bundle.model.ts +++ b/ui-ngx/src/app/shared/models/widgets-bundle.model.ts @@ -24,6 +24,7 @@ export interface WidgetsBundle extends BaseData, HasTenantId, E alias: string; title: string; image: string; + scada: boolean; description: string; order: number; } diff --git a/ui-ngx/src/assets/locale/locale.constant-en_US.json b/ui-ngx/src/assets/locale/locale.constant-en_US.json index 966923bb87..ba472cfbb9 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -5493,6 +5493,7 @@ "latest-data-key-settings-form-selector": "Latest data key settings form selector", "all": "All", "actual": "Actual", + "scada": "SCADA symbol", "deprecated": "Deprecated", "has-basic-mode": "Has basic mode", "basic-mode-form-selector": "Basic mode form selector", @@ -5601,6 +5602,7 @@ "title-max-length": "Title should be less than 256", "description": "Description", "image-preview": "Image preview", + "scada": "SCADA widgets bundle", "order": "Order", "add-widgets-bundle-text": "Add new widgets bundle", "no-widgets-bundles-text": "No widgets bundles found",