Merge pull request #12688 from AndriiLandiak/widget-type-info-bundles

Add bundles to widget type info
This commit is contained in:
Viacheslav Klimov 2025-02-24 15:12:19 +02:00 committed by GitHub
commit fe45eee0cb
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
17 changed files with 219 additions and 37 deletions

View File

@ -125,6 +125,7 @@ import org.thingsboard.server.common.data.rule.RuleNode;
import org.thingsboard.server.common.data.security.UserCredentials;
import org.thingsboard.server.common.data.util.ThrowingBiFunction;
import org.thingsboard.server.common.data.widget.WidgetTypeDetails;
import org.thingsboard.server.common.data.widget.WidgetTypeInfo;
import org.thingsboard.server.common.data.widget.WidgetsBundle;
import org.thingsboard.server.dao.alarm.AlarmCommentService;
import org.thingsboard.server.dao.asset.AssetProfileService;
@ -759,6 +760,10 @@ public abstract class BaseController {
return checkEntityId(widgetTypeId, widgetTypeService::findWidgetTypeDetailsById, operation);
}
WidgetTypeInfo checkWidgetTypeInfoId(WidgetTypeId widgetTypeId, Operation operation) throws ThingsboardException {
return checkEntityId(widgetTypeId, widgetTypeService::findWidgetTypeInfoById, operation);
}
Dashboard checkDashboardId(DashboardId dashboardId, Operation operation) throws ThingsboardException {
return checkEntityId(dashboardId, dashboardService::findDashboardById, operation);
}

View File

@ -118,7 +118,7 @@ public class WidgetTypeController extends AutoCommitController {
@PathVariable("widgetTypeId") String strWidgetTypeId) throws ThingsboardException {
checkParameter("widgetTypeId", strWidgetTypeId);
WidgetTypeId widgetTypeId = new WidgetTypeId(toUUID(strWidgetTypeId));
return new WidgetTypeInfo(checkWidgetTypeId(widgetTypeId, Operation.READ));
return checkWidgetTypeInfoId(widgetTypeId, Operation.READ);
}
@ApiOperation(value = "Create Or Update Widget Type (saveWidgetType)",

View File

@ -35,6 +35,8 @@ public interface WidgetTypeService extends EntityDaoService {
WidgetTypeDetails findWidgetTypeDetailsById(TenantId tenantId, WidgetTypeId widgetTypeId);
WidgetTypeInfo findWidgetTypeInfoById(TenantId tenantId, WidgetTypeId widgetTypeId);
boolean widgetTypeExistsByTenantIdAndWidgetTypeId(TenantId tenantId, WidgetTypeId widgetTypeId);
WidgetTypeDetails saveWidgetType(WidgetTypeDetails widgetType);

View File

@ -0,0 +1,39 @@
/**
* 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 com.fasterxml.jackson.annotation.JsonProperty;
import lombok.EqualsAndHashCode;
import lombok.Value;
import org.thingsboard.server.common.data.EntityInfo;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.id.EntityIdFactory;
import java.io.Serial;
import java.util.UUID;
@Value
@EqualsAndHashCode(callSuper = true)
public class WidgetBundleInfo extends EntityInfo {
@Serial
private static final long serialVersionUID = 2132305394634509820L;
public WidgetBundleInfo(@JsonProperty("id") UUID uuid, @JsonProperty("name") String name) {
super(EntityIdFactory.getByTypeAndUuid(EntityType.WIDGETS_BUNDLE, uuid), name);
}
}

View File

@ -16,13 +16,21 @@
package org.thingsboard.server.common.data.widget;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.Valid;
import lombok.Data;
import org.thingsboard.server.common.data.id.WidgetTypeId;
import org.thingsboard.server.common.data.validation.NoXss;
import java.io.Serial;
import java.util.Collections;
import java.util.List;
@Data
public class WidgetTypeInfo extends BaseWidgetType {
@Serial
private static final long serialVersionUID = 1343617007959780969L;
@Schema(description = "Base64 encoded widget thumbnail", accessMode = Schema.AccessMode.READ_ONLY)
private String image;
@NoXss
@ -34,6 +42,9 @@ public class WidgetTypeInfo extends BaseWidgetType {
@NoXss
@Schema(description = "Type of the widget (timeseries, latest, control, alarm or static)", accessMode = Schema.AccessMode.READ_ONLY)
private String widgetType;
@Valid
@Schema(description = "Bundles", accessMode = Schema.AccessMode.READ_ONLY)
private List<WidgetBundleInfo> bundles;
public WidgetTypeInfo() {
super();
@ -48,14 +59,23 @@ public class WidgetTypeInfo extends BaseWidgetType {
}
public WidgetTypeInfo(WidgetTypeInfo widgetTypeInfo) {
this(widgetTypeInfo, Collections.emptyList());
}
public WidgetTypeInfo(WidgetTypeInfo widgetTypeInfo, List<WidgetBundleInfo> bundles) {
super(widgetTypeInfo);
this.image = widgetTypeInfo.getImage();
this.description = widgetTypeInfo.getDescription();
this.tags = widgetTypeInfo.getTags();
this.widgetType = widgetTypeInfo.getWidgetType();
this.bundles = bundles;
}
public WidgetTypeInfo(WidgetTypeDetails widgetTypeDetails) {
this(widgetTypeDetails, Collections.emptyList());
}
public WidgetTypeInfo(WidgetTypeDetails widgetTypeDetails, List<WidgetBundleInfo> bundles) {
super(widgetTypeDetails);
this.image = widgetTypeDetails.getImage();
this.description = widgetTypeDetails.getDescription();
@ -65,5 +85,7 @@ public class WidgetTypeInfo extends BaseWidgetType {
} else {
this.widgetType = "";
}
this.bundles = bundles;
}
}

View File

@ -312,6 +312,7 @@ public class ModelConstants {
public static final String WIDGETS_BUNDLE_SCADA_PROPERTY = "scada";
public static final String WIDGETS_BUNDLE_DESCRIPTION = "description";
public static final String WIDGETS_BUNDLE_ORDER = "widgets_bundle_order";
public static final String WIDGET_BUNDLES_PROPERTY = "bundles";
/**
* Widget_type constants.

View File

@ -15,17 +15,22 @@
*/
package org.thingsboard.server.dao.model.sql;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;
import io.hypersistence.utils.hibernate.type.array.StringArrayType;
import jakarta.persistence.Column;
import jakarta.persistence.Convert;
import jakarta.persistence.Entity;
import jakarta.persistence.Table;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.hibernate.annotations.Immutable;
import org.hibernate.annotations.Type;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.common.data.widget.BaseWidgetType;
import org.thingsboard.server.common.data.widget.WidgetTypeInfo;
import org.thingsboard.server.dao.model.ModelConstants;
import org.thingsboard.server.dao.util.mapping.JsonConverter;
import java.util.HashMap;
import java.util.Map;
@ -58,6 +63,10 @@ public class WidgetTypeInfoEntity extends AbstractWidgetTypeEntity<WidgetTypeInf
@Column(name = ModelConstants.WIDGET_TYPE_WIDGET_TYPE_PROPERTY)
private String widgetType;
@Convert(converter = JsonConverter.class)
@Column(name = ModelConstants.WIDGET_BUNDLES_PROPERTY)
private JsonNode bundles;
public WidgetTypeInfoEntity() {
super();
}
@ -70,6 +79,7 @@ public class WidgetTypeInfoEntity extends AbstractWidgetTypeEntity<WidgetTypeInf
widgetTypeInfo.setDescription(description);
widgetTypeInfo.setTags(tags);
widgetTypeInfo.setWidgetType(widgetType);
widgetTypeInfo.setBundles(JacksonUtil.convertValue(bundles, new TypeReference<>() {}));
return widgetTypeInfo;
}

View File

@ -84,6 +84,11 @@ public class JpaWidgetTypeDao extends JpaAbstractDao<WidgetTypeDetailsEntity, Wi
return widgetTypeRepository.existsByTenantIdAndId(tenantId.getId(), widgetTypeId);
}
@Override
public WidgetTypeInfo findWidgetTypeInfoById(TenantId tenantId, UUID widgetTypeId) {
return DaoUtil.getData(widgetTypeInfoRepository.findById(widgetTypeId));
}
@Override
public PageData<WidgetTypeInfo> findSystemWidgetTypes(WidgetTypeFilter widgetTypeFilter, PageLink pageLink) {
boolean deprecatedFilterEnabled = !DeprecatedFilter.ALL.equals(widgetTypeFilter.getDeprecatedFilter());

View File

@ -56,6 +56,8 @@ public interface WidgetTypeDao extends Dao<WidgetTypeDetails>, ExportableEntityD
boolean existsByTenantIdAndId(TenantId tenantId, UUID widgetTypeId);
WidgetTypeInfo findWidgetTypeInfoById(TenantId tenantId, UUID widgetTypeId);
PageData<WidgetTypeInfo> findSystemWidgetTypes(WidgetTypeFilter widgetTypeFilter, PageLink pageLink);
PageData<WidgetTypeInfo> findAllTenantWidgetTypesByTenantId(WidgetTypeFilter widgetTypeFilter, PageLink pageLink);

View File

@ -87,6 +87,13 @@ public class WidgetTypeServiceImpl implements WidgetTypeService {
return widgetTypeDao.findById(tenantId, widgetTypeId.getId());
}
@Override
public WidgetTypeInfo findWidgetTypeInfoById(TenantId tenantId, WidgetTypeId widgetTypeId) {
log.trace("Executing findWidgetTypeInfoById [{}]", widgetTypeId);
Validator.validateId(widgetTypeId, id -> "Incorrect widgetTypeId " + id);
return widgetTypeDao.findWidgetTypeInfoById(tenantId, widgetTypeId.getId());
}
@Override
public boolean widgetTypeExistsByTenantIdAndWidgetTypeId(TenantId tenantId, WidgetTypeId widgetTypeId) {
log.trace("Executing widgetTypeExistsByTenantIdAndWidgetTypeId, tenantId [{}], widgetTypeId [{}]", tenantId, widgetTypeId);

View File

@ -288,8 +288,15 @@ $$;
DROP VIEW IF EXISTS widget_type_info_view CASCADE;
CREATE OR REPLACE VIEW widget_type_info_view AS
SELECT t.*
, COALESCE((t.descriptor::json->>'type')::text, '') as widget_type
SELECT t.*,
COALESCE((t.descriptor::json->>'type')::text, '') as widget_type,
array_to_json(ARRAY(
SELECT json_build_object('id', wb.widgets_bundle_id, 'name', b.title)
FROM widgets_bundle_widget wb
JOIN widgets_bundle b ON wb.widgets_bundle_id = b.id
WHERE wb.widget_type_id = t.id
ORDER BY b.title
)) AS bundles
FROM widget_type t;
CREATE OR REPLACE PROCEDURE cleanup_timeseries_by_ttl(IN null_uuid uuid,

View File

@ -29,6 +29,7 @@ import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.common.data.page.SortOrder;
import org.thingsboard.server.common.data.widget.BaseWidgetType;
import org.thingsboard.server.common.data.widget.DeprecatedFilter;
import org.thingsboard.server.common.data.widget.WidgetBundleInfo;
import org.thingsboard.server.common.data.widget.WidgetType;
import org.thingsboard.server.common.data.widget.WidgetTypeDetails;
import org.thingsboard.server.common.data.widget.WidgetTypeFilter;
@ -49,11 +50,10 @@ 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.assertNotNull;
import static org.junit.Assert.assertTrue;
/**
* Created by Valerii Sosliuk on 4/30/2017.
*/
public class JpaWidgetTypeDaoTest extends AbstractJpaDaoTest {
// given search text should find a widget with tags, when searching by tags
@ -78,7 +78,7 @@ public class JpaWidgetTypeDaoTest extends AbstractJpaDaoTest {
final String BUNDLE_ALIAS = "BUNDLE_ALIAS";
final int WIDGET_TYPE_COUNT = 3;
List<WidgetTypeDetails> widgetTypeList;
List<WidgetTypeInfo> widgetTypeList;
WidgetsBundle widgetsBundle;
@Autowired
@ -107,7 +107,7 @@ public class JpaWidgetTypeDaoTest extends AbstractJpaDaoTest {
widgetTypeList.sort(Comparator.comparing(BaseWidgetType::getName));
}
WidgetTypeDetails createAndSaveWidgetType(TenantId tenantId, int number) {
WidgetTypeInfo createAndSaveWidgetType(TenantId tenantId, int number) {
WidgetTypeDetails widgetType = new WidgetTypeDetails();
widgetType.setTenantId(tenantId);
widgetType.setName("WIDGET_TYPE_" + number);
@ -119,7 +119,10 @@ public class JpaWidgetTypeDaoTest extends AbstractJpaDaoTest {
widgetType.setDescriptor(descriptor);
String[] tags = new String[]{"Tag1_" + number, "Tag2_" + number, "TEST_" + number};
widgetType.setTags(tags);
return widgetTypeDao.save(TenantId.SYS_TENANT_ID, widgetType);
WidgetTypeDetails saved = widgetTypeDao.save(TenantId.SYS_TENANT_ID, widgetType);
List<WidgetBundleInfo> bundles = new ArrayList<>();
bundles.add(new WidgetBundleInfo(widgetsBundle.getUuidId(), widgetsBundle.getName()));
return new WidgetTypeInfo(saved, bundles);
}
WidgetTypeDetails createAndSaveWidgetType(TenantId tenantId, int number, String[] tags) {
@ -139,7 +142,7 @@ public class JpaWidgetTypeDaoTest extends AbstractJpaDaoTest {
@After
public void tearDown() {
widgetsBundleDao.removeById(TenantId.SYS_TENANT_ID, widgetsBundle.getUuidId());
for (WidgetType widgetType : widgetTypeList) {
for (WidgetTypeInfo widgetType : widgetTypeList) {
widgetTypeDao.removeById(TenantId.SYS_TENANT_ID, widgetType.getUuidId());
}
}
@ -160,7 +163,7 @@ public class JpaWidgetTypeDaoTest extends AbstractJpaDaoTest {
.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));
assertEquals(widgetTypeList.get(1), widgetTypes.getData().get(0));
widgetTypes = widgetTypeDao.findSystemWidgetTypes(
WidgetTypeFilter.builder()
@ -170,7 +173,7 @@ public class JpaWidgetTypeDaoTest extends AbstractJpaDaoTest {
.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));
assertEquals(widgetTypeList.get(2), widgetTypes.getData().get(0));
}
@Test
@ -181,7 +184,7 @@ public class JpaWidgetTypeDaoTest extends AbstractJpaDaoTest {
Thread.sleep(2);
var widgetType = saveWidgetType(TenantId.SYS_TENANT_ID, "widgetName");
sameNameList.add(widgetType);
widgetTypeList.add(widgetType);
widgetTypeList.add(new WidgetTypeInfo(widgetType));
}
sameNameList.sort(Comparator.comparing(BaseWidgetType::getName).thenComparing((BaseWidgetType baseWidgetType) -> baseWidgetType.getId().getId()));
List<WidgetTypeInfo> expected = sameNameList.stream().map(WidgetTypeInfo::new).collect(Collectors.toList());
@ -254,12 +257,12 @@ public class JpaWidgetTypeDaoTest extends AbstractJpaDaoTest {
public void testFindTenantWidgetTypesByTenantId() {
UUID tenantId = Uuids.timeBased();
for (int i = 0; i < WIDGET_TYPE_COUNT; i++) {
var widgetType = createAndSaveWidgetType(new TenantId(tenantId), i);
var widgetType = createAndSaveWidgetType(TenantId.fromUUID(tenantId), i);
widgetTypeList.add(widgetType);
}
PageData<WidgetTypeInfo> widgetTypes = widgetTypeDao.findTenantWidgetTypesByTenantId(
WidgetTypeFilter.builder()
.tenantId(new TenantId(tenantId))
.tenantId(TenantId.fromUUID(tenantId))
.fullSearch(true)
.deprecatedFilter(DeprecatedFilter.ALL)
.widgetTypes(null).build(),
@ -363,13 +366,13 @@ public class JpaWidgetTypeDaoTest extends AbstractJpaDaoTest {
PageData<WidgetTypeInfo> widgetTypes = widgetTypeDao.findWidgetTypesInfosByWidgetsBundleId(TenantId.SYS_TENANT_ID.getId(), widgetsBundle.getUuidId(), true, DeprecatedFilter.ALL, Collections.singletonList("latest"),
new PageLink(1024, 0, "TYPE_DESCRIPTION", new SortOrder("createdTime")));
assertEquals(2, widgetTypes.getData().size());
assertEquals(new WidgetTypeInfo(widgetTypeList.get(0)), widgetTypes.getData().get(0));
assertEquals(new WidgetTypeInfo(widgetTypeList.get(2)), widgetTypes.getData().get(1));
assertEquals(widgetTypeList.get(0), widgetTypes.getData().get(0));
assertEquals(widgetTypeList.get(2), widgetTypes.getData().get(1));
widgetTypes = widgetTypeDao.findWidgetTypesInfosByWidgetsBundleId(TenantId.SYS_TENANT_ID.getId(), widgetsBundle.getUuidId(), true, DeprecatedFilter.ALL, Collections.emptyList(),
new PageLink(1024, 0, "hfgfd TEST_0 ghg", new SortOrder("createdTime")));
assertEquals(1, widgetTypes.getData().size());
assertEquals(new WidgetTypeInfo(widgetTypeList.get(0)), widgetTypes.getData().get(0));
assertEquals(widgetTypeList.get(0), widgetTypes.getData().get(0));
}
@Test
@ -410,7 +413,7 @@ public class JpaWidgetTypeDaoTest extends AbstractJpaDaoTest {
@Test
public void testFindByTenantIdAndFqn() {
WidgetType result = widgetTypeList.get(0);
WidgetTypeInfo result = widgetTypeList.get(0);
assertNotNull(result);
WidgetType widgetType = widgetTypeDao.findByTenantIdAndFqn(TenantId.SYS_TENANT_ID.getId(), "FQN_0");
assertEquals(result.getId(), widgetType.getId());
@ -426,7 +429,7 @@ public class JpaWidgetTypeDaoTest extends AbstractJpaDaoTest {
@Test
public void testFindByImageLink() {
TenantId tenantId = new TenantId(UUID.randomUUID());
TenantId tenantId = TenantId.fromUUID(UUID.randomUUID());
WidgetTypeDetails details = createAndSaveWidgetType(tenantId, 0, new String[]{"a"});
details.setDescriptor(JacksonUtil.newObjectNode().put("bg", "/image/tenant/widget.png"));
widgetTypeDao.save(tenantId, details);
@ -437,6 +440,73 @@ public class JpaWidgetTypeDaoTest extends AbstractJpaDaoTest {
widgetTypeDao.removeById(tenantId, details.getUuidId());
}
@Test
public void testFindWidgetTypesWithBundles() {
PageData<WidgetTypeInfo> widgetTypes = widgetTypeDao.findWidgetTypesInfosByWidgetsBundleId(
TenantId.SYS_TENANT_ID.getId(),
widgetsBundle.getUuidId(),
true,
DeprecatedFilter.ALL,
Collections.singletonList("latest"),
new PageLink(1024, 0, "TYPE_DESCRIPTION", new SortOrder("createdTime"))
);
assertEquals(2, widgetTypes.getData().size());
for (var widgetType : widgetTypes.getData()) {
assertFalse("Bundles should not be empty", widgetType.getBundles().isEmpty());
assertEquals(BUNDLE_ALIAS, widgetType.getBundles().get(0).getName());
}
}
@Test
public void testAddWidgetTypeToNewBundleAndVerifyBundles() {
String newBundleTitle = "New Bundle Title";
WidgetsBundle newWidgetsBundle = new WidgetsBundle();
newWidgetsBundle.setAlias("NewBundle");
newWidgetsBundle.setTitle(newBundleTitle);
newWidgetsBundle.setId(new WidgetsBundleId(UUID.randomUUID()));
newWidgetsBundle.setTenantId(TenantId.SYS_TENANT_ID);
newWidgetsBundle = widgetsBundleDao.save(TenantId.SYS_TENANT_ID, newWidgetsBundle);
for (int i = 0; i < widgetTypeList.size(); i++) {
WidgetTypeInfo widgetType = widgetTypeList.get(i);
widgetTypeDao.saveWidgetsBundleWidget(new WidgetsBundleWidget(newWidgetsBundle.getId(), widgetType.getId(), i));
}
PageData<WidgetTypeInfo> widgetTypes = widgetTypeDao.findWidgetTypesInfosByWidgetsBundleId(
TenantId.SYS_TENANT_ID.getId(),
newWidgetsBundle.getUuidId(),
true,
DeprecatedFilter.ALL,
Collections.singletonList("latest"),
new PageLink(1024, 0, "TYPE_DESCRIPTION", new SortOrder("createdTime"))
);
assertEquals(2, widgetTypes.getData().size());
WidgetTypeInfo widgetTypeInfo1 = widgetTypes.getData().get(0);
WidgetTypeInfo widgetTypeInfo2 = widgetTypes.getData().get(1);
assertEquals(2, widgetTypeInfo1.getBundles().size());
assertTrue("Bundles should contain 'BUNDLE_ALIAS'", widgetTypeInfo1.getBundles().stream().anyMatch(bundle -> BUNDLE_ALIAS.equals(bundle.getName())));
assertTrue("Bundles should contain 'New Bundle Title'", widgetTypeInfo1.getBundles().stream().anyMatch(bundle -> newBundleTitle.equals(bundle.getName())));
assertEquals(2, widgetTypeInfo2.getBundles().size());
assertTrue("Bundles should contain 'BUNDLE_ALIAS'", widgetTypeInfo2.getBundles().stream().anyMatch(bundle -> "BUNDLE_ALIAS".equals(bundle.getName())));
assertTrue("Bundles should contain 'New Bundle Title'", widgetTypeInfo2.getBundles().stream().anyMatch(bundle -> newBundleTitle.equals(bundle.getName())));
// cleanup and verify
widgetsBundleDao.removeById(newWidgetsBundle.getTenantId(), newWidgetsBundle.getUuidId());
widgetTypes = widgetTypeDao.findWidgetTypesInfosByWidgetsBundleId(
TenantId.SYS_TENANT_ID.getId(),
newWidgetsBundle.getUuidId(),
true,
DeprecatedFilter.ALL,
Collections.singletonList("latest"),
new PageLink(1024, 0, "TYPE_DESCRIPTION", new SortOrder("createdTime"))
);
widgetTypes.getData().forEach(widgetTypeInfo -> assertEquals(1, widgetTypeInfo.getBundles().size()));
}
private WidgetTypeDetails saveWidgetType(TenantId tenantId, String name) {
WidgetTypeDetails widgetType = new WidgetTypeDetails();
widgetType.setTenantId(tenantId);
@ -447,4 +517,5 @@ public class JpaWidgetTypeDaoTest extends AbstractJpaDaoTest {
widgetType.setDescriptor(descriptor);
return widgetTypeDao.save(TenantId.SYS_TENANT_ID, widgetType);
}
}

View File

@ -192,7 +192,8 @@
(click)="$event.stopPropagation();"></a>
</ng-template>
<ng-template [ngSwitchCase]="'entityChips'">
<tb-entity-chips [entity]="entity" [key]="column.key"></tb-entity-chips>
<tb-entity-chips [entity]="entity" [key]="column.key"
[detailsPagePrefixUrl]="column.entityURL ? column.entityURL(entity) : ''"></tb-entity-chips>
</ng-template>
<ng-template #defaultContent ngSwitchDefault>
<span [innerHTML]="cellContent(entity, column, row)"></span>

View File

@ -18,7 +18,7 @@ import { Component, Input, OnChanges, SimpleChanges } from '@angular/core';
import { BaseData } from '@shared/models/base-data';
import { EntityId } from '@shared/models/id/entity-id';
import { baseDetailsPageByEntityType, EntityType } from '@app/shared/public-api';
import { isEqual, isObject } from '@core/utils';
import { isEqual, isNotEmptyStr, isObject } from '@core/utils';
@Component({
selector: 'tb-entity-chips',
@ -33,6 +33,9 @@ export class EntityChipsComponent implements OnChanges {
@Input()
key: string;
@Input()
detailsPagePrefixUrl: string;
entityDetailsPrefixUrl: string;
subEntities: Array<BaseData<EntityId>> = [];
@ -52,7 +55,9 @@ export class EntityChipsComponent implements OnChanges {
if (isObject(entitiesList) && !Array.isArray(entitiesList)) {
entitiesList = [entitiesList];
}
if (Array.isArray(entitiesList)) {
if (isNotEmptyStr(this.detailsPagePrefixUrl)) {
this.entityDetailsPrefixUrl = this.detailsPagePrefixUrl;
} else if (Array.isArray(entitiesList)) {
if (entitiesList.length) {
this.entityDetailsPrefixUrl = baseDetailsPageByEntityType.get(entitiesList[0].id.entityType as EntityType);
}

View File

@ -144,7 +144,8 @@ export class DateEntityTableColumn<T extends BaseData<HasId>> extends EntityTabl
export class EntityChipsEntityTableColumn<T extends BaseData<HasId>> extends BaseEntityTableColumn<T> {
constructor(public key: string,
public title: string,
public width: string = '0px') {
public width: string = '0px',
public entityURL?: (entity) => string) {
super('entityChips', key, title, width, false);
}
}

View File

@ -20,6 +20,7 @@ import { Router } from '@angular/router';
import {
checkBoxCell,
DateEntityTableColumn,
EntityChipsEntityTableColumn,
EntityTableColumn,
EntityTableConfig
} from '@home/models/entity/entities-table-config.models';
@ -75,7 +76,9 @@ export class WidgetTypesTableConfigResolver {
this.config.columns.push(
new DateEntityTableColumn<WidgetTypeInfo>('createdTime', 'common.created-time', this.datePipe, '150px'),
new EntityTableColumn<WidgetTypeInfo>('name', 'widget.title', '100%'),
new EntityTableColumn<WidgetTypeInfo>('name', 'widget.title', '60%'),
new EntityChipsEntityTableColumn<WidgetTypeInfo>( 'bundles', 'entity.type-widgets-bundles', '40%',
() => '/resources/widgets-library/widgets-bundles'),
new EntityTableColumn<WidgetTypeInfo>('widgetType', 'widget.type', '150px', entity =>
entity?.widgetType ? this.translate.instant(widgetTypesData.get(entity.widgetType).name) : '', undefined, false),
new EntityTableColumn<WidgetTypeInfo>('tenantId', 'widget.system', '60px',

View File

@ -41,7 +41,7 @@ import { isNotEmptyStr, mergeDeepIgnoreArray } from '@core/utils';
import { WidgetConfigComponentData } from '@home/models/widget-component.models';
import { ComponentStyle, Font, TimewindowStyle } from '@shared/models/widget-settings.models';
import { NULL_UUID } from '@shared/models/id/has-uuid';
import { HasTenantId, HasVersion } from '@shared/models/entity.models';
import { EntityInfoData, HasTenantId, HasVersion } from '@shared/models/entity.models';
import { DataKeysCallbacks, DataKeySettingsFunction } from '@home/components/widget/config/data-keys.component.models';
import { WidgetConfigCallbacks } from '@home/components/widget/config/widget-config.component.models';
import { TbFunction } from '@shared/models/js-function.models';
@ -270,6 +270,7 @@ export interface WidgetTypeInfo extends BaseWidgetType {
description: string;
tags: string[];
widgetType: widgetType;
bundles?: EntityInfoData[];
}
export interface WidgetTypeDetails extends WidgetType, ExportableEntity<WidgetTypeId> {