Browse Source

Ability to show SCADA widget bundles/widgets first when adding widget to SCADA layout.

pull/11391/head
Igor Kulikov 2 years ago
parent
commit
81fa9a6ff2
  1. 1
      application/src/main/data/json/system/widget_bundles/scada_symbols.json
  2. 1
      application/src/main/data/json/system/widget_bundles/scada_water_system_symbols.json
  3. 1
      application/src/main/data/json/system/widget_types/scada_symbol.json
  4. 21
      application/src/main/java/org/thingsboard/server/controller/WidgetTypeController.java
  5. 1
      application/src/main/java/org/thingsboard/server/controller/WidgetsBundleController.java
  6. 9
      application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/SystemWidgetTypesEdgeEventFetcher.java
  7. 3
      application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/SystemWidgetsBundlesEdgeEventFetcher.java
  8. 9
      application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/TenantWidgetTypesEdgeEventFetcher.java
  9. 1
      application/src/main/java/org/thingsboard/server/service/install/InstallScripts.java
  10. 7
      common/dao-api/src/main/java/org/thingsboard/server/dao/widget/WidgetTypeService.java
  11. 34
      common/data/src/main/java/org/thingsboard/server/common/data/widget/WidgetTypeFilter.java
  12. 44
      dao/src/main/java/org/thingsboard/server/dao/sql/widget/JpaWidgetTypeDao.java
  13. 12
      dao/src/main/java/org/thingsboard/server/dao/sql/widget/WidgetTypeInfoRepository.java
  14. 2
      dao/src/main/java/org/thingsboard/server/dao/sql/widget/WidgetsBundleRepository.java
  15. 7
      dao/src/main/java/org/thingsboard/server/dao/widget/WidgetTypeDao.java
  16. 33
      dao/src/main/java/org/thingsboard/server/dao/widget/WidgetTypeServiceImpl.java
  17. 77
      dao/src/test/java/org/thingsboard/server/dao/sql/widget/JpaWidgetTypeDaoTest.java
  18. 65
      dao/src/test/java/org/thingsboard/server/dao/sql/widget/JpaWidgetsBundleDaoTest.java
  19. 4
      ui-ngx/src/app/core/http/entity.service.ts
  20. 11
      ui-ngx/src/app/core/http/widget.service.ts
  21. 1
      ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.html
  22. 2
      ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.ts
  23. 10
      ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-widget-select.component.ts
  24. 1
      ui-ngx/src/app/modules/home/components/widget/lib/scada/scada-symbol-widget.component.html
  25. 13
      ui-ngx/src/app/modules/home/components/widget/lib/scada/scada-symbol-widget.component.scss
  26. 8
      ui-ngx/src/app/modules/home/components/widget/lib/scada/scada-symbol-widget.component.ts
  27. 1
      ui-ngx/src/app/modules/home/components/widget/widget-component.service.ts
  28. 5
      ui-ngx/src/app/modules/home/models/widget-component.models.ts
  29. 17
      ui-ngx/src/app/modules/home/pages/widget/widget-editor.component.html
  30. 11
      ui-ngx/src/app/modules/home/pages/widget/widget-type.component.html
  31. 2
      ui-ngx/src/app/modules/home/pages/widget/widget-type.component.ts
  32. 3
      ui-ngx/src/app/modules/home/pages/widget/widgets-bundle.component.html
  33. 2
      ui-ngx/src/app/modules/home/pages/widget/widgets-bundle.component.ts
  34. 3
      ui-ngx/src/app/shared/models/widget.models.ts
  35. 1
      ui-ngx/src/app/shared/models/widgets-bundle.model.ts
  36. 2
      ui-ngx/src/assets/locale/locale.constant-en_US.json

1
application/src/main/data/json/system/widget_bundles/scada_symbols.json

@ -2,6 +2,7 @@
"widgetsBundle": { "widgetsBundle": {
"alias": "scada_symbols", "alias": "scada_symbols",
"title": "SCADA symbols", "title": "SCADA symbols",
"scada": true,
"image": null, "image": null,
"description": "Bundle with SCADA symbols", "description": "Bundle with SCADA symbols",
"order": 9200, "order": 9200,

1
application/src/main/data/json/system/widget_bundles/scada_water_system_symbols.json

@ -2,6 +2,7 @@
"widgetsBundle": { "widgetsBundle": {
"alias": "scada_water_system_symbols", "alias": "scada_water_system_symbols",
"title": "SCADA water system symbols", "title": "SCADA water system symbols",
"scada": true,
"image": null, "image": null,
"description": "Bundle with SCADA symbols for water system", "description": "Bundle with SCADA symbols for water system",
"order": 9300, "order": 9300,

1
application/src/main/data/json/system/widget_types/scada_symbol.json

@ -2,6 +2,7 @@
"fqn": "scada_symbol", "fqn": "scada_symbol",
"name": "SCADA symbol", "name": "SCADA symbol",
"deprecated": false, "deprecated": false,
"scada": true,
"image": null, "image": null,
"description": "", "description": "",
"descriptor": { "descriptor": {

21
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.DeprecatedFilter;
import org.thingsboard.server.common.data.widget.WidgetType; import org.thingsboard.server.common.data.widget.WidgetType;
import org.thingsboard.server.common.data.widget.WidgetTypeDetails; 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.WidgetTypeInfo;
import org.thingsboard.server.common.data.widget.WidgetsBundle; 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.config.annotations.ApiOperation;
import org.thingsboard.server.dao.model.ModelConstants; import org.thingsboard.server.dao.model.ModelConstants;
import org.thingsboard.server.dao.resource.ImageService; 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 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 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 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 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 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"; 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"})) @Parameter(description = DEPRECATED_FILTER_PARAM_DESCRIPTION, schema = @Schema(allowableValues = {"ALL", "ACTUAL", "DEPRECATED"}))
@RequestParam(required = false) String deprecatedFilter, @RequestParam(required = false) String deprecatedFilter,
@Parameter(description = WIDGET_TYPE_ARRAY_DESCRIPTION, array = @ArraySchema(schema = @Schema(type = "string", allowableValues = {"timeseries", "latest", "control", "alarm", "static"}))) @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); PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
List<String> widgetTypes = widgetTypeList != null ? Arrays.asList(widgetTypeList) : Collections.emptyList(); List<String> widgetTypes = widgetTypeList != null ? Arrays.asList(widgetTypeList) : Collections.emptyList();
boolean fullSearchBool = fullSearch != null && fullSearch;
DeprecatedFilter widgetTypeDeprecatedFilter = StringUtils.isNotEmpty(deprecatedFilter) ? DeprecatedFilter.valueOf(deprecatedFilter) : DeprecatedFilter.ALL; 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())) { if (Authority.SYS_ADMIN.equals(getCurrentUser().getAuthority())) {
return checkNotNull(widgetTypeService.findSystemWidgetTypesByPageLink(getTenantId(), fullSearchBool, widgetTypeDeprecatedFilter, widgetTypes, pageLink)); return checkNotNull(widgetTypeService.findSystemWidgetTypesByPageLink(widgetTypeFilter, pageLink));
} else { } else {
if (tenantOnly != null && tenantOnly) { if (tenantOnly != null && tenantOnly) {
return checkNotNull(widgetTypeService.findTenantWidgetTypesByTenantIdAndPageLink(getTenantId(), fullSearchBool, widgetTypeDeprecatedFilter, widgetTypes, pageLink)); return checkNotNull(widgetTypeService.findTenantWidgetTypesByTenantIdAndPageLink(widgetTypeFilter, pageLink));
} else { } else {
return checkNotNull(widgetTypeService.findAllTenantWidgetTypesByTenantIdAndPageLink(getTenantId(), fullSearchBool, widgetTypeDeprecatedFilter, widgetTypes, pageLink)); return checkNotNull(widgetTypeService.findAllTenantWidgetTypesByTenantIdAndPageLink(widgetTypeFilter, pageLink));
} }
} }
} }

1
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())) { if (Authority.SYS_ADMIN.equals(getCurrentUser().getAuthority())) {
return checkNotNull(widgetsBundleService.findSystemWidgetsBundlesByPageLink(widgetsBundleFilter, pageLink)); return checkNotNull(widgetsBundleService.findSystemWidgetsBundlesByPageLink(widgetsBundleFilter, pageLink));
} else { } else {
TenantId tenantId = getCurrentUser().getTenantId();
if (tenantOnly != null && tenantOnly) { if (tenantOnly != null && tenantOnly) {
return checkNotNull(widgetsBundleService.findTenantWidgetsBundlesByTenantIdAndPageLink(widgetsBundleFilter, pageLink)); return checkNotNull(widgetsBundleService.findTenantWidgetsBundlesByTenantIdAndPageLink(widgetsBundleFilter, pageLink));
} else { } else {

9
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.PageData;
import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.common.data.widget.DeprecatedFilter; 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.common.data.widget.WidgetTypeInfo;
import org.thingsboard.server.dao.widget.WidgetTypeService; import org.thingsboard.server.dao.widget.WidgetTypeService;
@ -32,6 +33,12 @@ public class SystemWidgetTypesEdgeEventFetcher extends BaseWidgetTypesEdgeEventF
@Override @Override
protected PageData<WidgetTypeInfo> findWidgetTypes(TenantId tenantId, PageLink pageLink) { protected PageData<WidgetTypeInfo> 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);
} }
} }

3
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.PageData;
import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.common.data.widget.WidgetsBundle; import org.thingsboard.server.common.data.widget.WidgetsBundle;
import org.thingsboard.server.common.data.widget.WidgetsBundleFilter;
import org.thingsboard.server.dao.widget.WidgetsBundleService; import org.thingsboard.server.dao.widget.WidgetsBundleService;
@Slf4j @Slf4j
@ -31,6 +32,6 @@ public class SystemWidgetsBundlesEdgeEventFetcher extends BaseWidgetsBundlesEdge
@Override @Override
protected PageData<WidgetsBundle> findWidgetsBundles(TenantId tenantId, PageLink pageLink) { protected PageData<WidgetsBundle> findWidgetsBundles(TenantId tenantId, PageLink pageLink) {
return widgetsBundleService.findSystemWidgetsBundlesByPageLink(tenantId, false, pageLink); return widgetsBundleService.findSystemWidgetsBundlesByPageLink(WidgetsBundleFilter.fromTenantId(tenantId), pageLink);
} }
} }

9
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.PageData;
import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.common.data.widget.DeprecatedFilter; 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.common.data.widget.WidgetTypeInfo;
import org.thingsboard.server.dao.widget.WidgetTypeService; import org.thingsboard.server.dao.widget.WidgetTypeService;
@ -31,6 +32,12 @@ public class TenantWidgetTypesEdgeEventFetcher extends BaseWidgetTypesEdgeEventF
} }
@Override @Override
protected PageData<WidgetTypeInfo> findWidgetTypes(TenantId tenantId, PageLink pageLink) { protected PageData<WidgetTypeInfo> 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);
} }
} }

1
application/src/main/java/org/thingsboard/server/service/install/InstallScripts.java

@ -364,6 +364,7 @@ public class InstallScripts {
scadaSymbolWidget.setImage(symbolUrl); scadaSymbolWidget.setImage(symbolUrl);
scadaSymbolWidget.setDescription(metadata.getDescription()); scadaSymbolWidget.setDescription(metadata.getDescription());
scadaSymbolWidget.setTags(metadata.getSearchTags()); scadaSymbolWidget.setTags(metadata.getSearchTags());
scadaSymbolWidget.setScada(true);
ObjectNode defaultConfig = null; ObjectNode defaultConfig = null;
if (descriptor.has("defaultConfig")) { if (descriptor.has("defaultConfig")) {
defaultConfig = JacksonUtil.fromString(descriptor.get("defaultConfig").asText(), ObjectNode.class); defaultConfig = JacksonUtil.fromString(descriptor.get("defaultConfig").asText(), ObjectNode.class);

7
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.DeprecatedFilter;
import org.thingsboard.server.common.data.widget.WidgetType; import org.thingsboard.server.common.data.widget.WidgetType;
import org.thingsboard.server.common.data.widget.WidgetTypeDetails; 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.WidgetTypeInfo;
import org.thingsboard.server.dao.entity.EntityDaoService; import org.thingsboard.server.dao.entity.EntityDaoService;
@ -40,11 +41,11 @@ public interface WidgetTypeService extends EntityDaoService {
void deleteWidgetType(TenantId tenantId, WidgetTypeId widgetTypeId); void deleteWidgetType(TenantId tenantId, WidgetTypeId widgetTypeId);
PageData<WidgetTypeInfo> findSystemWidgetTypesByPageLink(TenantId tenantId, boolean fullSearch, DeprecatedFilter deprecatedFilter, List<String> widgetTypes, PageLink pageLink); PageData<WidgetTypeInfo> findSystemWidgetTypesByPageLink(WidgetTypeFilter widgetTypeFilter, PageLink pageLink);
PageData<WidgetTypeInfo> findAllTenantWidgetTypesByTenantIdAndPageLink(TenantId tenantId, boolean fullSearch, DeprecatedFilter deprecatedFilter, List<String> widgetTypes, PageLink pageLink); PageData<WidgetTypeInfo> findAllTenantWidgetTypesByTenantIdAndPageLink(WidgetTypeFilter widgetTypeFilter, PageLink pageLink);
PageData<WidgetTypeInfo> findTenantWidgetTypesByTenantIdAndPageLink(TenantId tenantId, boolean fullSearch, DeprecatedFilter deprecatedFilter, List<String> widgetTypes, PageLink pageLink); PageData<WidgetTypeInfo> findTenantWidgetTypesByTenantIdAndPageLink(WidgetTypeFilter widgetTypeFilter, PageLink pageLink);
List<WidgetType> findWidgetTypesByWidgetsBundleId(TenantId tenantId, WidgetsBundleId widgetsBundleId); List<WidgetType> findWidgetTypesByWidgetsBundleId(TenantId tenantId, WidgetsBundleId widgetsBundleId);

34
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<String> widgetTypes;
}

44
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.DeprecatedFilter;
import org.thingsboard.server.common.data.widget.WidgetType; import org.thingsboard.server.common.data.widget.WidgetType;
import org.thingsboard.server.common.data.widget.WidgetTypeDetails; 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.WidgetTypeInfo;
import org.thingsboard.server.common.data.widget.WidgetsBundleWidget; import org.thingsboard.server.common.data.widget.WidgetsBundleWidget;
import org.thingsboard.server.dao.DaoUtil; import org.thingsboard.server.dao.DaoUtil;
@ -84,57 +85,60 @@ public class JpaWidgetTypeDao extends JpaAbstractDao<WidgetTypeDetailsEntity, Wi
} }
@Override @Override
public PageData<WidgetTypeInfo> findSystemWidgetTypes(TenantId tenantId, boolean fullSearch, DeprecatedFilter deprecatedFilter, List<String> widgetTypes, PageLink pageLink) { public PageData<WidgetTypeInfo> findSystemWidgetTypes(WidgetTypeFilter widgetTypeFilter, PageLink pageLink) {
boolean deprecatedFilterEnabled = !DeprecatedFilter.ALL.equals(deprecatedFilter); boolean deprecatedFilterEnabled = !DeprecatedFilter.ALL.equals(widgetTypeFilter.getDeprecatedFilter());
boolean deprecatedFilterBool = DeprecatedFilter.DEPRECATED.equals(deprecatedFilter); boolean deprecatedFilterBool = DeprecatedFilter.DEPRECATED.equals(widgetTypeFilter.getDeprecatedFilter());
boolean widgetTypesEmpty = widgetTypes == null || widgetTypes.isEmpty(); boolean widgetTypesEmpty = widgetTypeFilter.getWidgetTypes() == null || widgetTypeFilter.getWidgetTypes().isEmpty();
return DaoUtil.toPageData( return DaoUtil.toPageData(
widgetTypeInfoRepository widgetTypeInfoRepository
.findSystemWidgetTypes( .findSystemWidgetTypes(
NULL_UUID, NULL_UUID,
pageLink.getTextSearch(), pageLink.getTextSearch(),
fullSearch, widgetTypeFilter.isFullSearch(),
deprecatedFilterEnabled, deprecatedFilterEnabled,
deprecatedFilterBool, deprecatedFilterBool,
widgetTypesEmpty, widgetTypesEmpty,
widgetTypes == null ? Collections.emptyList() : widgetTypes, widgetTypeFilter.getWidgetTypes() == null ? Collections.emptyList() : widgetTypeFilter.getWidgetTypes(),
widgetTypeFilter.isScadaFirst(),
DaoUtil.toPageable(pageLink, WidgetTypeInfoEntity.SEARCH_COLUMNS_MAP))); DaoUtil.toPageable(pageLink, WidgetTypeInfoEntity.SEARCH_COLUMNS_MAP)));
} }
@Override @Override
public PageData<WidgetTypeInfo> findAllTenantWidgetTypesByTenantId(UUID tenantId, boolean fullSearch, DeprecatedFilter deprecatedFilter, List<String> widgetTypes, PageLink pageLink) { public PageData<WidgetTypeInfo> findAllTenantWidgetTypesByTenantId(WidgetTypeFilter widgetTypeFilter, PageLink pageLink) {
boolean deprecatedFilterEnabled = !DeprecatedFilter.ALL.equals(deprecatedFilter); boolean deprecatedFilterEnabled = !DeprecatedFilter.ALL.equals(widgetTypeFilter.getDeprecatedFilter());
boolean deprecatedFilterBool = DeprecatedFilter.DEPRECATED.equals(deprecatedFilter); boolean deprecatedFilterBool = DeprecatedFilter.DEPRECATED.equals(widgetTypeFilter.getDeprecatedFilter());
boolean widgetTypesEmpty = widgetTypes == null || widgetTypes.isEmpty(); boolean widgetTypesEmpty = widgetTypeFilter.getWidgetTypes() == null || widgetTypeFilter.getWidgetTypes().isEmpty();
return DaoUtil.toPageData( return DaoUtil.toPageData(
widgetTypeInfoRepository widgetTypeInfoRepository
.findAllTenantWidgetTypesByTenantId( .findAllTenantWidgetTypesByTenantId(
tenantId, widgetTypeFilter.getTenantId().getId(),
NULL_UUID, NULL_UUID,
pageLink.getTextSearch(), pageLink.getTextSearch(),
fullSearch, widgetTypeFilter.isFullSearch(),
deprecatedFilterEnabled, deprecatedFilterEnabled,
deprecatedFilterBool, deprecatedFilterBool,
widgetTypesEmpty, widgetTypesEmpty,
widgetTypes == null ? Collections.emptyList() : widgetTypes, widgetTypeFilter.getWidgetTypes() == null ? Collections.emptyList() : widgetTypeFilter.getWidgetTypes(),
widgetTypeFilter.isScadaFirst(),
DaoUtil.toPageable(pageLink, WidgetTypeInfoEntity.SEARCH_COLUMNS_MAP))); DaoUtil.toPageable(pageLink, WidgetTypeInfoEntity.SEARCH_COLUMNS_MAP)));
} }
@Override @Override
public PageData<WidgetTypeInfo> findTenantWidgetTypesByTenantId(UUID tenantId, boolean fullSearch, DeprecatedFilter deprecatedFilter, List<String> widgetTypes, PageLink pageLink) { public PageData<WidgetTypeInfo> findTenantWidgetTypesByTenantId(WidgetTypeFilter widgetTypeFilter, PageLink pageLink) {
boolean deprecatedFilterEnabled = !DeprecatedFilter.ALL.equals(deprecatedFilter); boolean deprecatedFilterEnabled = !DeprecatedFilter.ALL.equals(widgetTypeFilter.getDeprecatedFilter());
boolean deprecatedFilterBool = DeprecatedFilter.DEPRECATED.equals(deprecatedFilter); boolean deprecatedFilterBool = DeprecatedFilter.DEPRECATED.equals(widgetTypeFilter.getDeprecatedFilter());
boolean widgetTypesEmpty = widgetTypes == null || widgetTypes.isEmpty(); boolean widgetTypesEmpty = widgetTypeFilter.getWidgetTypes() == null || widgetTypeFilter.getWidgetTypes().isEmpty();
return DaoUtil.toPageData( return DaoUtil.toPageData(
widgetTypeInfoRepository widgetTypeInfoRepository
.findTenantWidgetTypesByTenantId( .findTenantWidgetTypesByTenantId(
tenantId, widgetTypeFilter.getTenantId().getId(),
pageLink.getTextSearch(), pageLink.getTextSearch(),
fullSearch, widgetTypeFilter.isFullSearch(),
deprecatedFilterEnabled, deprecatedFilterEnabled,
deprecatedFilterBool, deprecatedFilterBool,
widgetTypesEmpty, widgetTypesEmpty,
widgetTypes == null ? Collections.emptyList() : widgetTypes, widgetTypeFilter.getWidgetTypes() == null ? Collections.emptyList() : widgetTypeFilter.getWidgetTypes(),
widgetTypeFilter.isScadaFirst(),
DaoUtil.toPageable(pageLink, WidgetTypeInfoEntity.SEARCH_COLUMNS_MAP))); DaoUtil.toPageable(pageLink, WidgetTypeInfoEntity.SEARCH_COLUMNS_MAP)));
} }

12
dao/src/main/java/org/thingsboard/server/dao/sql/widget/WidgetTypeInfoRepository.java

@ -41,7 +41,8 @@ public interface WidgetTypeInfoRepository extends JpaRepository<WidgetTypeInfoEn
"OR :searchText ILIKE currentTag || ' %' " + "OR :searchText ILIKE currentTag || ' %' " +
"OR :searchText ILIKE '% ' || currentTag " + "OR :searchText ILIKE '% ' || currentTag " +
"OR :searchText ILIKE '% ' || currentTag || ' %')" + "OR :searchText ILIKE '% ' || currentTag || ' %')" +
"))))", ")))) " +
"ORDER BY CASE WHEN :scadaFirst then wti.scada END DESC",
countQuery = "SELECT count(*) FROM widget_type_info_view wti WHERE wti.tenant_id = :systemTenantId " + countQuery = "SELECT count(*) FROM widget_type_info_view wti WHERE wti.tenant_id = :systemTenantId " +
"AND ((:deprecatedFilterEnabled) IS FALSE OR wti.deprecated = :deprecatedFilter) " + "AND ((:deprecatedFilterEnabled) IS FALSE OR wti.deprecated = :deprecatedFilter) " +
"AND ((:widgetTypesEmpty) IS TRUE OR wti.widget_type IN (:widgetTypes)) " + "AND ((:widgetTypesEmpty) IS TRUE OR wti.widget_type IN (:widgetTypes)) " +
@ -64,6 +65,7 @@ public interface WidgetTypeInfoRepository extends JpaRepository<WidgetTypeInfoEn
@Param("deprecatedFilter") boolean deprecatedFilter, @Param("deprecatedFilter") boolean deprecatedFilter,
@Param("widgetTypesEmpty") boolean widgetTypesEmpty, @Param("widgetTypesEmpty") boolean widgetTypesEmpty,
@Param("widgetTypes") List<String> widgetTypes, @Param("widgetTypes") List<String> widgetTypes,
@Param("scadaFirst") boolean scadaFirst,
Pageable pageable); Pageable pageable);
@Query(nativeQuery = true, @Query(nativeQuery = true,
@ -80,7 +82,8 @@ public interface WidgetTypeInfoRepository extends JpaRepository<WidgetTypeInfoEn
"OR :searchText ILIKE currentTag || ' %' " + "OR :searchText ILIKE currentTag || ' %' " +
"OR :searchText ILIKE '% ' || currentTag " + "OR :searchText ILIKE '% ' || currentTag " +
"OR :searchText ILIKE '% ' || currentTag || ' %')" + "OR :searchText ILIKE '% ' || currentTag || ' %')" +
"))))", ")))) " +
"ORDER BY CASE WHEN :scadaFirst then wti.scada END DESC",
countQuery = "SELECT count(*) FROM widget_type_info_view wti WHERE wti.tenant_id IN (:tenantId, :nullTenantId) " + countQuery = "SELECT count(*) FROM widget_type_info_view wti WHERE wti.tenant_id IN (:tenantId, :nullTenantId) " +
"AND ((:deprecatedFilterEnabled) IS FALSE OR wti.deprecated = :deprecatedFilter) " + "AND ((:deprecatedFilterEnabled) IS FALSE OR wti.deprecated = :deprecatedFilter) " +
"AND ((:widgetTypesEmpty) IS TRUE OR wti.widget_type IN (:widgetTypes)) " + "AND ((:widgetTypesEmpty) IS TRUE OR wti.widget_type IN (:widgetTypes)) " +
@ -104,6 +107,7 @@ public interface WidgetTypeInfoRepository extends JpaRepository<WidgetTypeInfoEn
@Param("deprecatedFilter") boolean deprecatedFilter, @Param("deprecatedFilter") boolean deprecatedFilter,
@Param("widgetTypesEmpty") boolean widgetTypesEmpty, @Param("widgetTypesEmpty") boolean widgetTypesEmpty,
@Param("widgetTypes") List<String> widgetTypes, @Param("widgetTypes") List<String> widgetTypes,
@Param("scadaFirst") boolean scadaFirst,
Pageable pageable); Pageable pageable);
@Query(nativeQuery = true, @Query(nativeQuery = true,
@ -120,7 +124,8 @@ public interface WidgetTypeInfoRepository extends JpaRepository<WidgetTypeInfoEn
"OR :searchText ILIKE currentTag || ' %' " + "OR :searchText ILIKE currentTag || ' %' " +
"OR :searchText ILIKE '% ' || currentTag " + "OR :searchText ILIKE '% ' || currentTag " +
"OR :searchText ILIKE '% ' || currentTag || ' %')" + "OR :searchText ILIKE '% ' || currentTag || ' %')" +
"))))", ")))) " +
"ORDER BY CASE WHEN :scadaFirst then wti.scada END DESC",
countQuery = "SELECT count(*) FROM widget_type_info_view wti WHERE wti.tenant_id = :tenantId " + countQuery = "SELECT count(*) FROM widget_type_info_view wti WHERE wti.tenant_id = :tenantId " +
"AND ((:deprecatedFilterEnabled) IS FALSE OR wti.deprecated = :deprecatedFilter) " + "AND ((:deprecatedFilterEnabled) IS FALSE OR wti.deprecated = :deprecatedFilter) " +
"AND ((:widgetTypesEmpty) IS TRUE OR wti.widget_type IN (:widgetTypes)) " + "AND ((:widgetTypesEmpty) IS TRUE OR wti.widget_type IN (:widgetTypes)) " +
@ -143,6 +148,7 @@ public interface WidgetTypeInfoRepository extends JpaRepository<WidgetTypeInfoEn
@Param("deprecatedFilter") boolean deprecatedFilter, @Param("deprecatedFilter") boolean deprecatedFilter,
@Param("widgetTypesEmpty") boolean widgetTypesEmpty, @Param("widgetTypesEmpty") boolean widgetTypesEmpty,
@Param("widgetTypes") List<String> widgetTypes, @Param("widgetTypes") List<String> widgetTypes,
@Param("scadaFirst") boolean scadaFirst,
Pageable pageable); Pageable pageable);
@Query("SELECT wti FROM WidgetTypeInfoEntity wti, WidgetsBundleWidgetEntity wbw " + @Query("SELECT wti FROM WidgetTypeInfoEntity wti, WidgetsBundleWidgetEntity wbw " +

2
dao/src/main/java/org/thingsboard/server/dao/sql/widget/WidgetsBundleRepository.java

@ -107,7 +107,7 @@ public interface WidgetsBundleRepository extends JpaRepository<WidgetsBundleEnti
"OR :textSearch ILIKE '% ' || currentTag " + "OR :textSearch ILIKE '% ' || currentTag " +
"OR :textSearch ILIKE '% ' || currentTag || ' %')" + "OR :textSearch ILIKE '% ' || currentTag || ' %')" +
")))) " + ")))) " +
"ORDER BY CASE WHEN :scadaFirst then wb.scada END ASC, wb.widgets_bundle_order ASC NULLS LAST", "ORDER BY CASE WHEN :scadaFirst then wb.scada END DESC, wb.widgets_bundle_order ASC NULLS LAST",
countQuery = "SELECT count(*) FROM widgets_bundle wb WHERE wb.tenant_id IN (:tenantIds) " + countQuery = "SELECT count(*) FROM widgets_bundle wb WHERE wb.tenant_id IN (:tenantIds) " +
"AND (:textSearch IS NULL OR wb.title ILIKE CONCAT('%', :textSearch, '%') " + "AND (:textSearch IS NULL OR wb.title ILIKE CONCAT('%', :textSearch, '%') " +
"OR wb.description ILIKE CONCAT('%', :textSearch, '%') " + "OR wb.description ILIKE CONCAT('%', :textSearch, '%') " +

7
dao/src/main/java/org/thingsboard/server/dao/widget/WidgetTypeDao.java

@ -22,6 +22,7 @@ import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.common.data.widget.DeprecatedFilter; import org.thingsboard.server.common.data.widget.DeprecatedFilter;
import org.thingsboard.server.common.data.widget.WidgetType; import org.thingsboard.server.common.data.widget.WidgetType;
import org.thingsboard.server.common.data.widget.WidgetTypeDetails; 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.WidgetTypeInfo;
import org.thingsboard.server.common.data.widget.WidgetsBundleWidget; import org.thingsboard.server.common.data.widget.WidgetsBundleWidget;
import org.thingsboard.server.dao.Dao; import org.thingsboard.server.dao.Dao;
@ -55,11 +56,11 @@ public interface WidgetTypeDao extends Dao<WidgetTypeDetails>, ExportableEntityD
boolean existsByTenantIdAndId(TenantId tenantId, UUID widgetTypeId); boolean existsByTenantIdAndId(TenantId tenantId, UUID widgetTypeId);
PageData<WidgetTypeInfo> findSystemWidgetTypes(TenantId tenantId, boolean fullSearch, DeprecatedFilter deprecatedFilter, List<String> widgetTypes, PageLink pageLink); PageData<WidgetTypeInfo> findSystemWidgetTypes(WidgetTypeFilter widgetTypeFilter, PageLink pageLink);
PageData<WidgetTypeInfo> findAllTenantWidgetTypesByTenantId(UUID tenantId, boolean fullSearch, DeprecatedFilter deprecatedFilter, List<String> widgetTypes, PageLink pageLink); PageData<WidgetTypeInfo> findAllTenantWidgetTypesByTenantId(WidgetTypeFilter widgetTypeFilter, PageLink pageLink);
PageData<WidgetTypeInfo> findTenantWidgetTypesByTenantId(UUID tenantId, boolean fullSearch, DeprecatedFilter deprecatedFilter, List<String> widgetTypes, PageLink pageLink); PageData<WidgetTypeInfo> findTenantWidgetTypesByTenantId(WidgetTypeFilter widgetTypeFilter, PageLink pageLink);
/** /**
* Find widget types by widgetsBundleId. * Find widget types by widgetsBundleId.

33
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.DeprecatedFilter;
import org.thingsboard.server.common.data.widget.WidgetType; import org.thingsboard.server.common.data.widget.WidgetType;
import org.thingsboard.server.common.data.widget.WidgetTypeDetails; 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.WidgetTypeInfo;
import org.thingsboard.server.common.data.widget.WidgetsBundleWidget; import org.thingsboard.server.common.data.widget.WidgetsBundleWidget;
import org.thingsboard.server.dao.entity.AbstractCachedEntityService; import org.thingsboard.server.dao.entity.AbstractCachedEntityService;
@ -121,28 +122,30 @@ public class WidgetTypeServiceImpl implements WidgetTypeService {
} }
@Override @Override
public PageData<WidgetTypeInfo> findSystemWidgetTypesByPageLink(TenantId tenantId, boolean fullSearch, DeprecatedFilter deprecatedFilter, List<String> widgetTypes, PageLink pageLink) { public PageData<WidgetTypeInfo> findSystemWidgetTypesByPageLink(WidgetTypeFilter widgetTypeFilter, PageLink pageLink) {
log.trace("Executing findSystemWidgetTypesByPageLink, fullSearch [{}], deprecatedFilter [{}], widgetTypes [{}], pageLink [{}]", fullSearch, deprecatedFilter, widgetTypes, pageLink); log.trace("Executing findSystemWidgetTypesByPageLink, pageLink [{}]", pageLink);
Validator.validatePageLink(pageLink); Validator.validatePageLink(pageLink);
return widgetTypeDao.findSystemWidgetTypes(tenantId, fullSearch, deprecatedFilter, widgetTypes, pageLink); return widgetTypeDao.findSystemWidgetTypes(widgetTypeFilter, pageLink);
} }
@Override @Override
public PageData<WidgetTypeInfo> findAllTenantWidgetTypesByTenantIdAndPageLink(TenantId tenantId, boolean fullSearch, DeprecatedFilter deprecatedFilter, List<String> widgetTypes, PageLink pageLink) { public PageData<WidgetTypeInfo> findAllTenantWidgetTypesByTenantIdAndPageLink(WidgetTypeFilter widgetTypeFilter, PageLink pageLink) {
log.trace("Executing findAllTenantWidgetTypesByTenantIdAndPageLink, tenantId [{}], fullSearch [{}], deprecatedFilter [{}], widgetTypes [{}], pageLink [{}]", TenantId tenantId = widgetTypeFilter.getTenantId();
tenantId, fullSearch, deprecatedFilter, widgetTypes, pageLink); log.trace("Executing findAllTenantWidgetTypesByTenantIdAndPageLink, tenantId [{}], pageLink [{}]",
tenantId, pageLink);
Validator.validateId(tenantId, id -> INCORRECT_TENANT_ID + id); Validator.validateId(tenantId, id -> INCORRECT_TENANT_ID + id);
Validator.validatePageLink(pageLink); Validator.validatePageLink(pageLink);
return widgetTypeDao.findAllTenantWidgetTypesByTenantId(tenantId.getId(), fullSearch, deprecatedFilter, widgetTypes, pageLink); return widgetTypeDao.findAllTenantWidgetTypesByTenantId(widgetTypeFilter, pageLink);
} }
@Override @Override
public PageData<WidgetTypeInfo> findTenantWidgetTypesByTenantIdAndPageLink(TenantId tenantId, boolean fullSearch, DeprecatedFilter deprecatedFilter, List<String> widgetTypes, PageLink pageLink) { public PageData<WidgetTypeInfo> findTenantWidgetTypesByTenantIdAndPageLink(WidgetTypeFilter widgetTypeFilter, PageLink pageLink) {
log.trace("Executing findTenantWidgetTypesByTenantIdAndPageLink, tenantId [{}], fullSearch [{}], deprecatedFilter [{}], widgetTypes [{}], pageLink [{}]", TenantId tenantId = widgetTypeFilter.getTenantId();
tenantId, fullSearch, deprecatedFilter, widgetTypes, pageLink); log.trace("Executing findTenantWidgetTypesByTenantIdAndPageLink, tenantId [{}], pageLink [{}]",
tenantId, pageLink);
Validator.validateId(tenantId, id -> INCORRECT_TENANT_ID + id); Validator.validateId(tenantId, id -> INCORRECT_TENANT_ID + id);
Validator.validatePageLink(pageLink); Validator.validatePageLink(pageLink);
return widgetTypeDao.findTenantWidgetTypesByTenantId(tenantId.getId(), fullSearch, deprecatedFilter, widgetTypes, pageLink); return widgetTypeDao.findTenantWidgetTypesByTenantId(widgetTypeFilter, pageLink);
} }
@Override @Override
@ -260,7 +263,13 @@ public class WidgetTypeServiceImpl implements WidgetTypeService {
@Override @Override
protected PageData<WidgetTypeInfo> findEntities(TenantId tenantId, TenantId id, PageLink pageLink) { protected PageData<WidgetTypeInfo> 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 @Override

77
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.DeprecatedFilter;
import org.thingsboard.server.common.data.widget.WidgetType; import org.thingsboard.server.common.data.widget.WidgetType;
import org.thingsboard.server.common.data.widget.WidgetTypeDetails; 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.WidgetTypeInfo;
import org.thingsboard.server.common.data.widget.WidgetsBundle; import org.thingsboard.server.common.data.widget.WidgetsBundle;
import org.thingsboard.server.common.data.widget.WidgetsBundleWidget; import org.thingsboard.server.common.data.widget.WidgetsBundleWidget;
@ -151,12 +152,22 @@ public class JpaWidgetTypeDaoTest extends AbstractJpaDaoTest {
@Test @Test
public void testFindSystemWidgetTypes() { public void testFindSystemWidgetTypes() {
PageData<WidgetTypeInfo> widgetTypes = widgetTypeDao.findSystemWidgetTypes(TenantId.SYS_TENANT_ID, true, DeprecatedFilter.ALL, Collections.singletonList("static"), PageData<WidgetTypeInfo> 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"))); new PageLink(1024, 0, "TYPE_DESCRIPTION", new SortOrder("createdTime")));
assertEquals(1, widgetTypes.getData().size()); assertEquals(1, widgetTypes.getData().size());
assertEquals(new WidgetTypeInfo(widgetTypeList.get(1)), widgetTypes.getData().get(0)); 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"))); new PageLink(1024, 0, "hfgfd tag2_2 ghg", new SortOrder("createdTime")));
assertEquals(1, widgetTypes.getData().size()); assertEquals(1, widgetTypes.getData().size());
assertEquals(new WidgetTypeInfo(widgetTypeList.get(2)), widgetTypes.getData().get(0)); 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())); sameNameList.sort(Comparator.comparing(BaseWidgetType::getName).thenComparing((BaseWidgetType baseWidgetType) -> baseWidgetType.getId().getId()));
List<WidgetTypeInfo> expected = sameNameList.stream().map(WidgetTypeInfo::new).collect(Collectors.toList()); List<WidgetTypeInfo> expected = sameNameList.stream().map(WidgetTypeInfo::new).collect(Collectors.toList());
PageData<WidgetTypeInfo> widgetTypesFirstPage = widgetTypeDao.findSystemWidgetTypes(TenantId.SYS_TENANT_ID, true, DeprecatedFilter.ALL, Collections.singletonList("static"), PageData<WidgetTypeInfo> 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"))); new PageLink(10, 0, null, new SortOrder("name")));
assertEquals(10, widgetTypesFirstPage.getData().size()); assertEquals(10, widgetTypesFirstPage.getData().size());
assertThat(widgetTypesFirstPage.getData()).containsExactlyElementsOf(expected.subList(0, 10)); assertThat(widgetTypesFirstPage.getData()).containsExactlyElementsOf(expected.subList(0, 10));
PageData<WidgetTypeInfo> widgetTypesSecondPage = widgetTypeDao.findSystemWidgetTypes(TenantId.SYS_TENANT_ID, true, DeprecatedFilter.ALL, Collections.singletonList("static"), PageData<WidgetTypeInfo> 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"))); new PageLink(10, 1, null, new SortOrder("name")));
assertEquals(10, widgetTypesSecondPage.getData().size()); assertEquals(10, widgetTypesSecondPage.getData().size());
assertThat(widgetTypesSecondPage.getData()).containsExactlyElementsOf(expected.subList(10, 20)); 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); WidgetTypeDetails savedWidgetType = createAndSaveWidgetType(TenantId.SYS_TENANT_ID, WIDGET_TYPE_COUNT + 1, tags);
PageData<WidgetTypeInfo> widgetTypes = widgetTypeDao.findSystemWidgetTypes( PageData<WidgetTypeInfo> 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); 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); WidgetTypeDetails savedWidgetType = createAndSaveWidgetType(TenantId.SYS_TENANT_ID, WIDGET_TYPE_COUNT + 1, tags);
PageData<WidgetTypeInfo> widgetTypes = widgetTypeDao.findSystemWidgetTypes( PageData<WidgetTypeInfo> 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); assertThat(widgetTypes.getData()).hasSize(0);
@ -227,7 +257,12 @@ public class JpaWidgetTypeDaoTest extends AbstractJpaDaoTest {
var widgetType = createAndSaveWidgetType(new TenantId(tenantId), i); var widgetType = createAndSaveWidgetType(new TenantId(tenantId), i);
widgetTypeList.add(widgetType); widgetTypeList.add(widgetType);
} }
PageData<WidgetTypeInfo> widgetTypes = widgetTypeDao.findTenantWidgetTypesByTenantId(tenantId, true, DeprecatedFilter.ALL, null, PageData<WidgetTypeInfo> widgetTypes = widgetTypeDao.findTenantWidgetTypesByTenantId(
WidgetTypeFilter.builder()
.tenantId(new TenantId(tenantId))
.fullSearch(true)
.deprecatedFilter(DeprecatedFilter.ALL)
.widgetTypes(null).build(),
new PageLink(10, 0, "", new SortOrder("createdTime"))); new PageLink(10, 0, "", new SortOrder("createdTime")));
assertEquals(WIDGET_TYPE_COUNT, widgetTypes.getData().size()); assertEquals(WIDGET_TYPE_COUNT, widgetTypes.getData().size());
assertEquals(new WidgetTypeInfo(widgetTypeList.get(3)), widgetTypes.getData().get(0)); 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); WidgetTypeDetails savedWidgetType = createAndSaveWidgetType(TenantId.SYS_TENANT_ID, WIDGET_TYPE_COUNT + 1, tags);
PageData<WidgetTypeInfo> widgetTypes = widgetTypeDao.findTenantWidgetTypesByTenantId( PageData<WidgetTypeInfo> 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); 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); WidgetTypeDetails savedWidgetType = createAndSaveWidgetType(TenantId.SYS_TENANT_ID, WIDGET_TYPE_COUNT + 1, tags);
PageData<WidgetTypeInfo> widgetTypes = widgetTypeDao.findTenantWidgetTypesByTenantId( PageData<WidgetTypeInfo> 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); 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); WidgetTypeDetails savedWidgetType = createAndSaveWidgetType(TenantId.SYS_TENANT_ID, WIDGET_TYPE_COUNT + 1, tags);
PageData<WidgetTypeInfo> widgetTypes = widgetTypeDao.findAllTenantWidgetTypesByTenantId( PageData<WidgetTypeInfo> 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); 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); WidgetTypeDetails savedWidgetType = createAndSaveWidgetType(TenantId.SYS_TENANT_ID, WIDGET_TYPE_COUNT + 1, tags);
PageData<WidgetTypeInfo> widgetTypes = widgetTypeDao.findAllTenantWidgetTypesByTenantId( PageData<WidgetTypeInfo> 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); assertThat(widgetTypes.getData()).hasSize(0);

65
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.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
public class JpaWidgetsBundleDaoTest extends AbstractJpaDaoTest { public class JpaWidgetsBundleDaoTest extends AbstractJpaDaoTest {
@ -311,6 +313,52 @@ public class JpaWidgetsBundleDaoTest extends AbstractJpaDaoTest {
assertEquals(widgetsBundle3, widgetsBundles5.getData().get(0)); 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<WidgetsBundle> 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<WidgetsBundle> 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 @Test
public void testTagsSearchInFindAllWidgetsBundlesByTenantId() { public void testTagsSearchInFindAllWidgetsBundlesByTenantId() {
for (var entry : SHOULD_FIND_SEARCH_TO_TAGS_MAP.entrySet()) { 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) { 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++) { 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) { 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++) { 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) { 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 widgetsBundle = new WidgetsBundle();
widgetsBundle.setAlias(alias); widgetsBundle.setAlias(alias);
widgetsBundle.setTitle(title); widgetsBundle.setTitle(title);
widgetsBundle.setTenantId(tenantId); widgetsBundle.setTenantId(tenantId);
widgetsBundle.setId(new WidgetsBundleId(Uuids.timeBased())); widgetsBundle.setId(new WidgetsBundleId(Uuids.timeBased()));
widgetsBundle.setOrder(order); widgetsBundle.setOrder(order);
widgetsBundle.setScada(scada);
return widgetsBundleDao.save(TenantId.SYS_TENANT_ID, widgetsBundle); return widgetsBundleDao.save(TenantId.SYS_TENANT_ID, widgetsBundle);
} }

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

@ -427,11 +427,11 @@ export class EntityService {
break; break;
case EntityType.WIDGETS_BUNDLE: case EntityType.WIDGETS_BUNDLE:
pageLink.sortOrder.property = 'title'; pageLink.sortOrder.property = 'title';
entitiesObservable = this.widgetService.getWidgetBundles(pageLink, false, true, config); entitiesObservable = this.widgetService.getWidgetBundles(pageLink, false, true, false, config);
break; break;
case EntityType.WIDGET_TYPE: case EntityType.WIDGET_TYPE:
pageLink.sortOrder.property = 'name'; 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; break;
case EntityType.NOTIFICATION_TARGET: case EntityType.NOTIFICATION_TARGET:
pageLink.sortOrder.property = 'name'; pageLink.sortOrder.property = 'name';

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

@ -86,9 +86,9 @@ export class WidgetService {
} }
public getWidgetBundles(pageLink: PageLink, fullSearch = false, public getWidgetBundles(pageLink: PageLink, fullSearch = false,
tenantOnly = false, config?: RequestConfig): Observable<PageData<WidgetsBundle>> { tenantOnly = false, scadaFirst = false, config?: RequestConfig): Observable<PageData<WidgetsBundle>> {
return this.http.get<PageData<WidgetsBundle>>( return this.http.get<PageData<WidgetsBundle>>(
`/api/widgetsBundles${pageLink.toQuery()}&tenantOnly=${tenantOnly}&fullSearch=${fullSearch}`, `/api/widgetsBundles${pageLink.toQuery()}&tenantOnly=${tenantOnly}&fullSearch=${fullSearch}&scadaFirst=${scadaFirst}`,
defaultHttpOptionsFromConfig(config) defaultHttpOptionsFromConfig(config)
); );
} }
@ -240,10 +240,13 @@ export class WidgetService {
} }
public getWidgetTypes(pageLink: PageLink, tenantOnly = false, public getWidgetTypes(pageLink: PageLink, tenantOnly = false,
fullSearch = false, deprecatedFilter = DeprecatedFilter.ALL, widgetTypes: Array<widgetType> = null, fullSearch = false, scadaFirst = false,
deprecatedFilter = DeprecatedFilter.ALL,
widgetTypes: Array<widgetType> = null,
config?: RequestConfig): Observable<PageData<WidgetTypeInfo>> { config?: RequestConfig): Observable<PageData<WidgetTypeInfo>> {
let url = 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) { if (widgetTypes && widgetTypes.length) {
url += `&widgetTypeList=${widgetTypes.join(',')}`; url += `&widgetTypeList=${widgetTypes.join(',')}`;
} }

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

@ -442,6 +442,7 @@
*ngIf="isAddingWidget" *ngIf="isAddingWidget"
[aliasController]="dashboardCtx.aliasController" [aliasController]="dashboardCtx.aliasController"
[filterWidgetTypes]="filterWidgetTypes" [filterWidgetTypes]="filterWidgetTypes"
[scadaFirst]="layouts.main.layoutCtx.gridSettings.layoutType === LayoutType.scada"
(widgetSelected)="addWidgetFromType($event)"> (widgetSelected)="addWidgetFromType($event)">
</tb-dashboard-widget-select> </tb-dashboard-widget-select>
</tb-details-panel> </tb-details-panel>

2
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 { export class DashboardPageComponent extends PageComponent implements IDashboardController, HasDirtyFlag, OnInit, AfterViewInit, OnDestroy {
LayoutType = LayoutType;
private forcePristine = false; private forcePristine = false;
get isDirty(): boolean { get isDirty(): boolean {

10
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 { Direction } from '@shared/models/page/sort-order';
import { GridEntitiesFetchFunction, ScrollGridColumns } from '@shared/components/grid/scroll-grid-datasource'; import { GridEntitiesFetchFunction, ScrollGridColumns } from '@shared/components/grid/scroll-grid-datasource';
import { ItemSizeStrategy } from '@shared/components/grid/scroll-grid.component'; import { ItemSizeStrategy } from '@shared/components/grid/scroll-grid.component';
import { coerceBoolean } from '@shared/decorators/coercion';
type selectWidgetMode = 'bundles' | 'allWidgets'; type selectWidgetMode = 'bundles' | 'allWidgets';
@ -69,6 +70,10 @@ export class DashboardWidgetSelectComponent implements OnInit {
@Input() @Input()
aliasController: IAliasController; aliasController: IAliasController;
@Input()
@coerceBoolean()
scadaFirst = false;
@Input() @Input()
set search(search: string) { set search(search: string) {
this.searchSubject.next(search); this.searchSubject.next(search);
@ -170,7 +175,7 @@ export class DashboardWidgetSelectComponent implements OnInit {
property: 'title', property: 'title',
direction: Direction.ASC direction: Direction.ASC
}); });
return this.widgetsService.getWidgetBundles(pageLink, true); return this.widgetsService.getWidgetBundles(pageLink, true, false, this.scadaFirst);
}; };
this.allWidgetsFetchFunction = (pageSize, page, filter) => { this.allWidgetsFetchFunction = (pageSize, page, filter) => {
@ -178,7 +183,8 @@ export class DashboardWidgetSelectComponent implements OnInit {
property: 'name', property: 'name',
direction: Direction.ASC 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) => { this.widgetsFetchFunction = (pageSize, page, filter) => {

1
ui-ngx/src/app/modules/home/components/widget/lib/scada/scada-symbol-widget.component.html

@ -23,6 +23,7 @@
<div class="tb-scada-symbol-content"> <div class="tb-scada-symbol-content">
<div #scadaSymbolShape class="tb-scada-symbol-shape"> <div #scadaSymbolShape class="tb-scada-symbol-shape">
</div> </div>
<div *ngIf="noScadaSymbol" class="tb-no-scada-symbol" translate>scada.no-symbol-selected</div>
</div> </div>
<mat-progress-bar class="tb-action-widget-progress" style="height: 4px;" color="accent" mode="indeterminate" *ngIf="loading$ | async"></mat-progress-bar> <mat-progress-bar class="tb-action-widget-progress" style="height: 4px;" color="accent" mode="indeterminate" *ngIf="loading$ | async"></mat-progress-bar>
</div> </div>

13
ui-ngx/src/app/modules/home/components/widget/lib/scada/scada-symbol-widget.component.scss

@ -46,5 +46,18 @@
align-items: center; align-items: center;
justify-content: 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;
}
} }
} }

8
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()); loading$ = this.loadingSubject.asObservable().pipe(share());
scadaSymbolObject: ScadaSymbolObject; scadaSymbolObject: ScadaSymbolObject;
noScadaSymbol = false;
constructor(public widgetComponent: WidgetComponent, constructor(public widgetComponent: WidgetComponent,
protected imagePipe: ImagePipe, protected imagePipe: ImagePipe,
@ -89,9 +90,9 @@ export class ScadaSymbolWidgetComponent implements OnInit, AfterViewInit, OnDest
this.scadaSymbolContent$ = of(this.settings.scadaSymbolContent); this.scadaSymbolContent$ = of(this.settings.scadaSymbolContent);
} else if (this.settings.scadaSymbolUrl) { } else if (this.settings.scadaSymbolUrl) {
this.scadaSymbolContent$ = this.imageService.getImageString(this.settings.scadaSymbolUrl) this.scadaSymbolContent$ = this.imageService.getImageString(this.settings.scadaSymbolUrl)
.pipe(catchError(() => of('<svg></svg>'))); .pipe(catchError(() => of('empty')));
} else { } else {
this.scadaSymbolContent$ = of('<svg></svg>'); 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); this.ctx.isPreview || (isDefinedAndNotNull(this.settings.simulated) ? this.settings.simulated : false);
if (content.startsWith('<parsererror')) { if (content.startsWith('<parsererror')) {
rootElement.innerHTML = content; rootElement.innerHTML = content;
} else if (content === 'empty') {
this.noScadaSymbol = true;
this.cd.markForCheck();
} else { } else {
this.scadaSymbolObject = new ScadaSymbolObject(rootElement, this.ctx, content, this.scadaSymbolObject = new ScadaSymbolObject(rootElement, this.ctx, content,
this.settings.scadaSymbolObjectSettings, this, simulated); this.settings.scadaSymbolObjectSettings, this, simulated);

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

@ -96,6 +96,7 @@ export class WidgetComponentService {
widgetName: this.utils.editWidgetInfo.widgetName, widgetName: this.utils.editWidgetInfo.widgetName,
fullFqn: 'system.customWidget', fullFqn: 'system.customWidget',
deprecated: false, deprecated: false,
scada: false,
type: this.utils.editWidgetInfo.type, type: this.utils.editWidgetInfo.type,
sizeX: this.utils.editWidgetInfo.sizeX, sizeX: this.utils.editWidgetInfo.sizeX,
sizeY: this.utils.editWidgetInfo.sizeY, sizeY: this.utils.editWidgetInfo.sizeY,

5
ui-ngx/src/app/modules/home/models/widget-component.models.ts

@ -531,6 +531,7 @@ export interface WidgetInfo extends WidgetTypeDescriptor, WidgetControllerDescri
widgetName: string; widgetName: string;
fullFqn: string; fullFqn: string;
deprecated: boolean; deprecated: boolean;
scada: boolean;
typeSettingsSchema?: string | any; typeSettingsSchema?: string | any;
typeDataKeySettingsSchema?: string | any; typeDataKeySettingsSchema?: string | any;
typeLatestDataKeySettingsSchema?: string | any; typeLatestDataKeySettingsSchema?: string | any;
@ -565,6 +566,7 @@ export const MissingWidgetType: WidgetInfo = {
widgetName: 'Widget type not found', widgetName: 'Widget type not found',
fullFqn: 'undefined', fullFqn: 'undefined',
deprecated: false, deprecated: false,
scada: false,
sizeX: 8, sizeX: 8,
sizeY: 6, sizeY: 6,
resources: [], resources: [],
@ -590,6 +592,7 @@ export const ErrorWidgetType: WidgetInfo = {
widgetName: 'Error loading widget', widgetName: 'Error loading widget',
fullFqn: 'error', fullFqn: 'error',
deprecated: false, deprecated: false,
scada: false,
sizeX: 8, sizeX: 8,
sizeY: 6, sizeY: 6,
resources: [], resources: [],
@ -632,6 +635,7 @@ export const toWidgetInfo = (widgetTypeEntity: WidgetType): WidgetInfo => ({
widgetName: widgetTypeEntity.name, widgetName: widgetTypeEntity.name,
fullFqn: fullWidgetTypeFqn(widgetTypeEntity), fullFqn: fullWidgetTypeFqn(widgetTypeEntity),
deprecated: widgetTypeEntity.deprecated, deprecated: widgetTypeEntity.deprecated,
scada: widgetTypeEntity.scada,
type: widgetTypeEntity.descriptor.type, type: widgetTypeEntity.descriptor.type,
sizeX: widgetTypeEntity.descriptor.sizeX, sizeX: widgetTypeEntity.descriptor.sizeX,
sizeY: widgetTypeEntity.descriptor.sizeY, sizeY: widgetTypeEntity.descriptor.sizeY,
@ -685,6 +689,7 @@ export const toWidgetType = (widgetInfo: WidgetInfo, id: WidgetTypeId, tenantId:
fqn: widgetTypeFqn(widgetInfo.fullFqn), fqn: widgetTypeFqn(widgetInfo.fullFqn),
name: widgetInfo.widgetName, name: widgetInfo.widgetName,
deprecated: widgetInfo.deprecated, deprecated: widgetInfo.deprecated,
scada: widgetInfo.scada,
descriptor descriptor
}; };
}; };

17
ui-ngx/src/app/modules/home/pages/widget/widget-editor.component.html

@ -257,11 +257,18 @@
[(ngModel)]="widget.tags" [(ngModel)]="widget.tags"
(ngModelChange)="isDirty = true"> (ngModelChange)="isDirty = true">
</tb-string-items-list> </tb-string-items-list>
<mat-slide-toggle class="mat-block" style="padding-bottom: 16px;" <div fxLayout="column" fxLayoutGap="16px" style="padding-bottom: 16px;">
[(ngModel)]="widget.deprecated" <mat-slide-toggle class="mat-block"
(ngModelChange)="isDirty = true"> [(ngModel)]="widget.scada"
{{ 'widget.deprecated' | translate }} (ngModelChange)="isDirty = true">
</mat-slide-toggle> {{ 'widget.scada' | translate }}
</mat-slide-toggle>
<mat-slide-toggle class="mat-block"
[(ngModel)]="widget.deprecated"
(ngModelChange)="isDirty = true">
{{ 'widget.deprecated' | translate }}
</mat-slide-toggle>
</div>
<mat-form-field class="mat-block"> <mat-form-field class="mat-block">
<mat-label translate>widget.settings-form-selector</mat-label> <mat-label translate>widget.settings-form-selector</mat-label>
<input matInput <input matInput

11
ui-ngx/src/app/modules/home/pages/widget/widget-type.component.html

@ -67,9 +67,14 @@
label="{{ 'widget.tags' | translate }}" label="{{ 'widget.tags' | translate }}"
formControlName="tags"> formControlName="tags">
</tb-string-items-list> </tb-string-items-list>
<mat-slide-toggle formControlName="deprecated"> <div fxLayout="column" fxLayoutGap="16px">
{{ 'widget.deprecated' | translate }} <mat-slide-toggle formControlName="scada">
</mat-slide-toggle> {{ 'widget.scada' | translate }}
</mat-slide-toggle>
<mat-slide-toggle formControlName="deprecated">
{{ 'widget.deprecated' | translate }}
</mat-slide-toggle>
</div>
</fieldset> </fieldset>
</form> </form>
</div> </div>

2
ui-ngx/src/app/modules/home/pages/widget/widget-type.component.ts

@ -53,6 +53,7 @@ export class WidgetTypeComponent extends EntityComponent<WidgetTypeDetails> {
image: [entity ? entity.image : ''], image: [entity ? entity.image : ''],
description: [entity ? entity.description : '', Validators.maxLength(1024)], description: [entity ? entity.description : '', Validators.maxLength(1024)],
tags: [entity ? entity.tags : []], tags: [entity ? entity.tags : []],
scada: [entity ? entity.scada : false],
deprecated: [entity ? entity.deprecated : false] deprecated: [entity ? entity.deprecated : false]
} }
); );
@ -64,6 +65,7 @@ export class WidgetTypeComponent extends EntityComponent<WidgetTypeDetails> {
image: entity.image, image: entity.image,
description: entity.description, description: entity.description,
tags: entity.tags, tags: entity.tags,
scada: entity.scada,
deprecated: entity.deprecated deprecated: entity.deprecated
}); });
} }

3
ui-ngx/src/app/modules/home/pages/widget/widgets-bundle.component.html

@ -63,6 +63,9 @@
<textarea matInput formControlName="description" rows="2" maxlength="1024" #descriptionInput></textarea> <textarea matInput formControlName="description" rows="2" maxlength="1024" #descriptionInput></textarea>
<mat-hint align="end">{{descriptionInput.value?.length || 0}}/1024</mat-hint> <mat-hint align="end">{{descriptionInput.value?.length || 0}}/1024</mat-hint>
</mat-form-field> </mat-form-field>
<mat-slide-toggle formControlName="scada" style="padding-bottom: 16px;">
{{ 'widgets-bundle.scada' | translate }}
</mat-slide-toggle>
<mat-form-field class="mat-block"> <mat-form-field class="mat-block">
<mat-label translate>widgets-bundle.order</mat-label> <mat-label translate>widgets-bundle.order</mat-label>
<input matInput type="number" step="1" formControlName="order"> <input matInput type="number" step="1" formControlName="order">

2
ui-ngx/src/app/modules/home/pages/widget/widgets-bundle.component.ts

@ -51,6 +51,7 @@ export class WidgetsBundleComponent extends EntityComponent<WidgetsBundle> {
title: [entity ? entity.title : '', [Validators.required, Validators.maxLength(255)]], title: [entity ? entity.title : '', [Validators.required, Validators.maxLength(255)]],
image: [entity ? entity.image : ''], image: [entity ? entity.image : ''],
description: [entity ? entity.description : '', Validators.maxLength(1024)], description: [entity ? entity.description : '', Validators.maxLength(1024)],
scada: [entity ? entity.scada : false],
order: [entity ? entity.order : null] order: [entity ? entity.order : null]
} }
); );
@ -61,6 +62,7 @@ export class WidgetsBundleComponent extends EntityComponent<WidgetsBundle> {
title: entity.title, title: entity.title,
image: entity.image, image: entity.image,
description: entity.description, description: entity.description,
scada: entity.scada,
order: entity.order order: entity.order
}); });
} }

3
ui-ngx/src/app/shared/models/widget.models.ts

@ -204,6 +204,7 @@ export interface BaseWidgetType extends BaseData<WidgetTypeId>, HasTenantId {
fqn: string; fqn: string;
name: string; name: string;
deprecated: boolean; deprecated: boolean;
scada: boolean;
} }
export const fullWidgetTypeFqn = (type: BaseWidgetType): string => export const fullWidgetTypeFqn = (type: BaseWidgetType): string =>
@ -361,7 +362,7 @@ export interface DataKey extends KeyInfo {
_hash?: number; _hash?: number;
} }
export type CellClickColumnInfo = Pick<DataKey, 'name' | 'label'> export type CellClickColumnInfo = Pick<DataKey, 'name' | 'label'>;
export enum DataKeyConfigMode { export enum DataKeyConfigMode {
general = 'general', general = 'general',

1
ui-ngx/src/app/shared/models/widgets-bundle.model.ts

@ -24,6 +24,7 @@ export interface WidgetsBundle extends BaseData<WidgetsBundleId>, HasTenantId, E
alias: string; alias: string;
title: string; title: string;
image: string; image: string;
scada: boolean;
description: string; description: string;
order: number; order: number;
} }

2
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", "latest-data-key-settings-form-selector": "Latest data key settings form selector",
"all": "All", "all": "All",
"actual": "Actual", "actual": "Actual",
"scada": "SCADA symbol",
"deprecated": "Deprecated", "deprecated": "Deprecated",
"has-basic-mode": "Has basic mode", "has-basic-mode": "Has basic mode",
"basic-mode-form-selector": "Basic mode form selector", "basic-mode-form-selector": "Basic mode form selector",
@ -5601,6 +5602,7 @@
"title-max-length": "Title should be less than 256", "title-max-length": "Title should be less than 256",
"description": "Description", "description": "Description",
"image-preview": "Image preview", "image-preview": "Image preview",
"scada": "SCADA widgets bundle",
"order": "Order", "order": "Order",
"add-widgets-bundle-text": "Add new widgets bundle", "add-widgets-bundle-text": "Add new widgets bundle",
"no-widgets-bundles-text": "No widgets bundles found", "no-widgets-bundles-text": "No widgets bundles found",

Loading…
Cancel
Save