Merge pull request #12688 from AndriiLandiak/widget-type-info-bundles
Add bundles to widget type info
This commit is contained in:
		
						commit
						fe45eee0cb
					
				@ -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);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -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)",
 | 
			
		||||
 | 
			
		||||
@ -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);
 | 
			
		||||
 | 
			
		||||
@ -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);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -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;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -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.
 | 
			
		||||
 | 
			
		||||
@ -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;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -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());
 | 
			
		||||
 | 
			
		||||
@ -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);
 | 
			
		||||
 | 
			
		||||
@ -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);
 | 
			
		||||
 | 
			
		||||
@ -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,
 | 
			
		||||
 | 
			
		||||
@ -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);
 | 
			
		||||
@ -117,9 +117,12 @@ public class JpaWidgetTypeDaoTest extends AbstractJpaDaoTest {
 | 
			
		||||
        var descriptor = JacksonUtil.newObjectNode();
 | 
			
		||||
        descriptor.put("type", number % 2 == 0 ? "latest" : "static");
 | 
			
		||||
        widgetType.setDescriptor(descriptor);
 | 
			
		||||
        String[] tags = new String[]{"Tag1_"+number, "Tag2_"+number, "TEST_"+number};
 | 
			
		||||
        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(),
 | 
			
		||||
@ -360,16 +363,16 @@ public class JpaWidgetTypeDaoTest extends AbstractJpaDaoTest {
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testFindByWidgetTypeInfosByBundleId() {
 | 
			
		||||
        PageData<WidgetTypeInfo> widgetTypes = widgetTypeDao.findWidgetTypesInfosByWidgetsBundleId(TenantId.SYS_TENANT_ID.getId(), widgetsBundle.getUuidId(),true, DeprecatedFilter.ALL, Collections.singletonList("latest"),
 | 
			
		||||
        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,14 +440,82 @@ 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);
 | 
			
		||||
        widgetType.setDescription("WIDGET_TYPE_DESCRIPTION" + StringUtils.randomAlphabetic(7));
 | 
			
		||||
        widgetType.setName(name);
 | 
			
		||||
        var descriptor = JacksonUtil.newObjectNode();
 | 
			
		||||
        descriptor.put("type","static");
 | 
			
		||||
        descriptor.put("type", "static");
 | 
			
		||||
        widgetType.setDescriptor(descriptor);
 | 
			
		||||
        return widgetTypeDao.save(TenantId.SYS_TENANT_ID, widgetType);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -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>
 | 
			
		||||
 | 
			
		||||
@ -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);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@ -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);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -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',
 | 
			
		||||
 | 
			
		||||
@ -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> {
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user