Browse Source

Control visibility and order of dashboard in mobile application. Ability to hide widgets in mobile mode. Fix dashboard state changes processing.

pull/4963/head
Igor Kulikov 5 years ago
parent
commit
e1afbe6667
  1. 5
      application/src/main/data/upgrade/3.2.2/schema_update.sql
  2. 14
      application/src/main/java/org/thingsboard/server/controller/DashboardController.java
  3. 4
      common/dao-api/src/main/java/org/thingsboard/server/dao/dashboard/DashboardService.java
  4. 21
      common/data/src/main/java/org/thingsboard/server/common/data/DashboardInfo.java
  5. 29
      dao/src/main/java/org/thingsboard/server/dao/DaoUtil.java
  6. 19
      dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardInfoDao.java
  7. 17
      dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardServiceImpl.java
  8. 2
      dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java
  9. 10
      dao/src/main/java/org/thingsboard/server/dao/model/sql/DashboardEntity.java
  10. 10
      dao/src/main/java/org/thingsboard/server/dao/model/sql/DashboardInfoEntity.java
  11. 17
      dao/src/main/java/org/thingsboard/server/dao/sql/dashboard/DashboardInfoRepository.java
  12. 35
      dao/src/main/java/org/thingsboard/server/dao/sql/dashboard/JpaDashboardInfoDao.java
  13. 2
      dao/src/main/resources/sql/schema-entities-hsql.sql
  14. 2
      dao/src/main/resources/sql/schema-entities.sql
  15. 62
      dao/src/test/java/org/thingsboard/server/dao/service/BaseDashboardServiceTest.java
  16. 3
      ui-ngx/src/app/core/services/dashboard-utils.service.ts
  17. 1
      ui-ngx/src/app/modules/home/components/dashboard-page/add-widget-dialog.component.ts
  18. 4
      ui-ngx/src/app/modules/home/components/dashboard-page/states/default-state-controller.component.ts
  19. 4
      ui-ngx/src/app/modules/home/components/dashboard-page/states/entity-state-controller.component.ts
  20. 2
      ui-ngx/src/app/modules/home/components/dashboard-page/states/state-controller.component.ts
  21. 3
      ui-ngx/src/app/modules/home/components/widget/widget-config.component.html
  22. 9
      ui-ngx/src/app/modules/home/components/widget/widget-config.component.ts
  23. 21
      ui-ngx/src/app/modules/home/models/dashboard-component.models.ts
  24. 18
      ui-ngx/src/app/modules/home/pages/dashboard/dashboard-form.component.html
  25. 4
      ui-ngx/src/app/modules/home/pages/dashboard/dashboard-form.component.ts
  26. 3
      ui-ngx/src/app/shared/models/dashboard.models.ts
  27. 1
      ui-ngx/src/app/shared/models/widget.models.ts
  28. 4
      ui-ngx/src/assets/locale/locale.constant-en_US.json

5
application/src/main/data/upgrade/3.2.2/schema_update.sql

@ -142,7 +142,9 @@ CREATE TABLE IF NOT EXISTS oauth2_mobile (
); );
ALTER TABLE dashboard ALTER TABLE dashboard
ADD COLUMN IF NOT EXISTS image varchar(1000000); ADD COLUMN IF NOT EXISTS image varchar(1000000),
ADD COLUMN IF NOT EXISTS mobile_hide boolean DEFAULT false,
ADD COLUMN IF NOT EXISTS mobile_order int;
ALTER TABLE device_profile ALTER TABLE device_profile
ADD COLUMN IF NOT EXISTS image varchar(1000000), ADD COLUMN IF NOT EXISTS image varchar(1000000),
@ -210,4 +212,3 @@ CREATE TABLE IF NOT EXISTS rpc (
); );
CREATE INDEX IF NOT EXISTS idx_rpc_tenant_id_device_id ON rpc(tenant_id, device_id); CREATE INDEX IF NOT EXISTS idx_rpc_tenant_id_device_id ON rpc(tenant_id, device_id);

14
application/src/main/java/org/thingsboard/server/controller/DashboardController.java

@ -468,13 +468,18 @@ public class DashboardController extends BaseController {
public PageData<DashboardInfo> getTenantDashboards( public PageData<DashboardInfo> getTenantDashboards(
@RequestParam int pageSize, @RequestParam int pageSize,
@RequestParam int page, @RequestParam int page,
@RequestParam(required = false) Boolean mobile,
@RequestParam(required = false) String textSearch, @RequestParam(required = false) String textSearch,
@RequestParam(required = false) String sortProperty, @RequestParam(required = false) String sortProperty,
@RequestParam(required = false) String sortOrder) throws ThingsboardException { @RequestParam(required = false) String sortOrder) throws ThingsboardException {
try { try {
TenantId tenantId = getCurrentUser().getTenantId(); TenantId tenantId = getCurrentUser().getTenantId();
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder); PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
return checkNotNull(dashboardService.findDashboardsByTenantId(tenantId, pageLink)); if (mobile != null && mobile.booleanValue()) {
return checkNotNull(dashboardService.findMobileDashboardsByTenantId(tenantId, pageLink));
} else {
return checkNotNull(dashboardService.findDashboardsByTenantId(tenantId, pageLink));
}
} catch (Exception e) { } catch (Exception e) {
throw handleException(e); throw handleException(e);
} }
@ -487,6 +492,7 @@ public class DashboardController extends BaseController {
@PathVariable("customerId") String strCustomerId, @PathVariable("customerId") String strCustomerId,
@RequestParam int pageSize, @RequestParam int pageSize,
@RequestParam int page, @RequestParam int page,
@RequestParam(required = false) Boolean mobile,
@RequestParam(required = false) String textSearch, @RequestParam(required = false) String textSearch,
@RequestParam(required = false) String sortProperty, @RequestParam(required = false) String sortProperty,
@RequestParam(required = false) String sortOrder) throws ThingsboardException { @RequestParam(required = false) String sortOrder) throws ThingsboardException {
@ -496,7 +502,11 @@ public class DashboardController extends BaseController {
CustomerId customerId = new CustomerId(toUUID(strCustomerId)); CustomerId customerId = new CustomerId(toUUID(strCustomerId));
checkCustomerId(customerId, Operation.READ); checkCustomerId(customerId, Operation.READ);
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder); PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
return checkNotNull(dashboardService.findDashboardsByTenantIdAndCustomerId(tenantId, customerId, pageLink)); if (mobile != null && mobile.booleanValue()) {
return checkNotNull(dashboardService.findMobileDashboardsByTenantIdAndCustomerId(tenantId, customerId, pageLink));
} else {
return checkNotNull(dashboardService.findDashboardsByTenantIdAndCustomerId(tenantId, customerId, pageLink));
}
} catch (Exception e) { } catch (Exception e) {
throw handleException(e); throw handleException(e);
} }

4
common/dao-api/src/main/java/org/thingsboard/server/dao/dashboard/DashboardService.java

@ -45,10 +45,14 @@ public interface DashboardService {
PageData<DashboardInfo> findDashboardsByTenantId(TenantId tenantId, PageLink pageLink); PageData<DashboardInfo> findDashboardsByTenantId(TenantId tenantId, PageLink pageLink);
PageData<DashboardInfo> findMobileDashboardsByTenantId(TenantId tenantId, PageLink pageLink);
void deleteDashboardsByTenantId(TenantId tenantId); void deleteDashboardsByTenantId(TenantId tenantId);
PageData<DashboardInfo> findDashboardsByTenantIdAndCustomerId(TenantId tenantId, CustomerId customerId, PageLink pageLink); PageData<DashboardInfo> findDashboardsByTenantIdAndCustomerId(TenantId tenantId, CustomerId customerId, PageLink pageLink);
PageData<DashboardInfo> findMobileDashboardsByTenantIdAndCustomerId(TenantId tenantId, CustomerId customerId, PageLink pageLink);
void unassignCustomerDashboards(TenantId tenantId, CustomerId customerId); void unassignCustomerDashboards(TenantId tenantId, CustomerId customerId);
void updateCustomerDashboards(TenantId tenantId, CustomerId customerId); void updateCustomerDashboards(TenantId tenantId, CustomerId customerId);

21
common/data/src/main/java/org/thingsboard/server/common/data/DashboardInfo.java

@ -33,6 +33,8 @@ public class DashboardInfo extends SearchTextBased<DashboardId> implements HasNa
private String image; private String image;
@Valid @Valid
private Set<ShortCustomerInfo> assignedCustomers; private Set<ShortCustomerInfo> assignedCustomers;
private boolean mobileHide;
private Integer mobileOrder;
public DashboardInfo() { public DashboardInfo() {
super(); super();
@ -48,6 +50,8 @@ public class DashboardInfo extends SearchTextBased<DashboardId> implements HasNa
this.title = dashboardInfo.getTitle(); this.title = dashboardInfo.getTitle();
this.image = dashboardInfo.getImage(); this.image = dashboardInfo.getImage();
this.assignedCustomers = dashboardInfo.getAssignedCustomers(); this.assignedCustomers = dashboardInfo.getAssignedCustomers();
this.mobileHide = dashboardInfo.isMobileHide();
this.mobileOrder = dashboardInfo.getMobileOrder();
} }
public TenantId getTenantId() { public TenantId getTenantId() {
@ -82,10 +86,27 @@ public class DashboardInfo extends SearchTextBased<DashboardId> implements HasNa
this.assignedCustomers = assignedCustomers; this.assignedCustomers = assignedCustomers;
} }
public boolean isMobileHide() {
return mobileHide;
}
public void setMobileHide(boolean mobileHide) {
this.mobileHide = mobileHide;
}
public Integer getMobileOrder() {
return mobileOrder;
}
public void setMobileOrder(Integer mobileOrder) {
this.mobileOrder = mobileOrder;
}
public boolean isAssignedToCustomer(CustomerId customerId) { public boolean isAssignedToCustomer(CustomerId customerId) {
return this.assignedCustomers != null && this.assignedCustomers.contains(new ShortCustomerInfo(customerId, null, false)); return this.assignedCustomers != null && this.assignedCustomers.contains(new ShortCustomerInfo(customerId, null, false));
} }
public ShortCustomerInfo getAssignedCustomerInfo(CustomerId customerId) { public ShortCustomerInfo getAssignedCustomerInfo(CustomerId customerId) {
if (this.assignedCustomers != null) { if (this.assignedCustomers != null) {
for (ShortCustomerInfo customerInfo : this.assignedCustomers) { for (ShortCustomerInfo customerInfo : this.assignedCustomers) {

29
dao/src/main/java/org/thingsboard/server/dao/DaoUtil.java

@ -32,6 +32,7 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Optional; import java.util.Optional;
import java.util.UUID; import java.util.UUID;
import java.util.stream.Collectors;
public abstract class DaoUtil { public abstract class DaoUtil {
@ -55,6 +56,14 @@ public abstract class DaoUtil {
return PageRequest.of(pageLink.getPage(), pageLink.getPageSize(), toSort(pageLink.getSortOrder(), columnMap)); return PageRequest.of(pageLink.getPage(), pageLink.getPageSize(), toSort(pageLink.getSortOrder(), columnMap));
} }
public static Pageable toPageable(PageLink pageLink, List<SortOrder> sortOrders) {
return toPageable(pageLink, Collections.emptyMap(), sortOrders);
}
public static Pageable toPageable(PageLink pageLink, Map<String,String> columnMap, List<SortOrder> sortOrders) {
return PageRequest.of(pageLink.getPage(), pageLink.getPageSize(), toSort(sortOrders, columnMap));
}
public static Sort toSort(SortOrder sortOrder) { public static Sort toSort(SortOrder sortOrder) {
return toSort(sortOrder, Collections.emptyMap()); return toSort(sortOrder, Collections.emptyMap());
} }
@ -71,6 +80,26 @@ public abstract class DaoUtil {
} }
} }
public static Sort toSort(List<SortOrder> sortOrders) {
return toSort(sortOrders, Collections.emptyMap());
}
public static Sort toSort(List<SortOrder> sortOrders, Map<String,String> columnMap) {
return toSort(sortOrders, columnMap, Sort.NullHandling.NULLS_LAST);
}
public static Sort toSort(List<SortOrder> sortOrders, Map<String,String> columnMap, Sort.NullHandling nullHandlingHint) {
return Sort.by(sortOrders.stream().map(s -> toSortOrder(s, columnMap, nullHandlingHint)).collect(Collectors.toList()));
}
public static Sort.Order toSortOrder(SortOrder sortOrder, Map<String,String> columnMap, Sort.NullHandling nullHandlingHint) {
String property = sortOrder.getProperty();
if (columnMap.containsKey(property)) {
property = columnMap.get(property);
}
return new Sort.Order(Sort.Direction.fromString(sortOrder.getDirection().name()), property, nullHandlingHint);
}
public static <T> List<T> convertDataList(Collection<? extends ToData<T>> toDataList) { public static <T> List<T> convertDataList(Collection<? extends ToData<T>> toDataList) {
List<T> list = Collections.emptyList(); List<T> list = Collections.emptyList();
if (toDataList != null && !toDataList.isEmpty()) { if (toDataList != null && !toDataList.isEmpty()) {

19
dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardInfoDao.java

@ -36,6 +36,15 @@ public interface DashboardInfoDao extends Dao<DashboardInfo> {
*/ */
PageData<DashboardInfo> findDashboardsByTenantId(UUID tenantId, PageLink pageLink); PageData<DashboardInfo> findDashboardsByTenantId(UUID tenantId, PageLink pageLink);
/**
* Find dashboards not hidden for mobile by tenantId and page link.
*
* @param tenantId the tenantId
* @param pageLink the page link
* @return the list of dashboard objects
*/
PageData<DashboardInfo> findMobileDashboardsByTenantId(UUID tenantId, PageLink pageLink);
/** /**
* Find dashboards by tenantId, customerId and page link. * Find dashboards by tenantId, customerId and page link.
* *
@ -46,6 +55,16 @@ public interface DashboardInfoDao extends Dao<DashboardInfo> {
*/ */
PageData<DashboardInfo> findDashboardsByTenantIdAndCustomerId(UUID tenantId, UUID customerId, PageLink pageLink); PageData<DashboardInfo> findDashboardsByTenantIdAndCustomerId(UUID tenantId, UUID customerId, PageLink pageLink);
/**
* Find dashboards not hidden for mobile by tenantId, customerId and page link.
*
* @param tenantId the tenantId
* @param customerId the customerId
* @param pageLink the page link
* @return the list of dashboard objects
*/
PageData<DashboardInfo> findMobileDashboardsByTenantIdAndCustomerId(UUID tenantId, UUID customerId, PageLink pageLink);
/** /**
* Find dashboards by tenantId, edgeId and page link. * Find dashboards by tenantId, edgeId and page link.
* *

17
dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardServiceImpl.java

@ -186,6 +186,14 @@ public class DashboardServiceImpl extends AbstractEntityService implements Dashb
return dashboardInfoDao.findDashboardsByTenantId(tenantId.getId(), pageLink); return dashboardInfoDao.findDashboardsByTenantId(tenantId.getId(), pageLink);
} }
@Override
public PageData<DashboardInfo> findMobileDashboardsByTenantId(TenantId tenantId, PageLink pageLink) {
log.trace("Executing findMobileDashboardsByTenantId, tenantId [{}], pageLink [{}]", tenantId, pageLink);
Validator.validateId(tenantId, INCORRECT_TENANT_ID + tenantId);
Validator.validatePageLink(pageLink);
return dashboardInfoDao.findMobileDashboardsByTenantId(tenantId.getId(), pageLink);
}
@Override @Override
public void deleteDashboardsByTenantId(TenantId tenantId) { public void deleteDashboardsByTenantId(TenantId tenantId) {
log.trace("Executing deleteDashboardsByTenantId, tenantId [{}]", tenantId); log.trace("Executing deleteDashboardsByTenantId, tenantId [{}]", tenantId);
@ -202,6 +210,15 @@ public class DashboardServiceImpl extends AbstractEntityService implements Dashb
return dashboardInfoDao.findDashboardsByTenantIdAndCustomerId(tenantId.getId(), customerId.getId(), pageLink); return dashboardInfoDao.findDashboardsByTenantIdAndCustomerId(tenantId.getId(), customerId.getId(), pageLink);
} }
@Override
public PageData<DashboardInfo> findMobileDashboardsByTenantIdAndCustomerId(TenantId tenantId, CustomerId customerId, PageLink pageLink) {
log.trace("Executing findMobileDashboardsByTenantIdAndCustomerId, tenantId [{}], customerId [{}], pageLink [{}]", tenantId, customerId, pageLink);
Validator.validateId(tenantId, INCORRECT_TENANT_ID + tenantId);
Validator.validateId(customerId, "Incorrect customerId " + customerId);
Validator.validatePageLink(pageLink);
return dashboardInfoDao.findMobileDashboardsByTenantIdAndCustomerId(tenantId.getId(), customerId.getId(), pageLink);
}
@Override @Override
public void unassignCustomerDashboards(TenantId tenantId, CustomerId customerId) { public void unassignCustomerDashboards(TenantId tenantId, CustomerId customerId) {
log.trace("Executing unassignCustomerDashboards, customerId [{}]", customerId); log.trace("Executing unassignCustomerDashboards, customerId [{}]", customerId);

2
dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java

@ -339,6 +339,8 @@ public class ModelConstants {
public static final String DASHBOARD_IMAGE_PROPERTY = "image"; public static final String DASHBOARD_IMAGE_PROPERTY = "image";
public static final String DASHBOARD_CONFIGURATION_PROPERTY = "configuration"; public static final String DASHBOARD_CONFIGURATION_PROPERTY = "configuration";
public static final String DASHBOARD_ASSIGNED_CUSTOMERS_PROPERTY = "assigned_customers"; public static final String DASHBOARD_ASSIGNED_CUSTOMERS_PROPERTY = "assigned_customers";
public static final String DASHBOARD_MOBILE_HIDE_PROPERTY = "mobile_hide";
public static final String DASHBOARD_MOBILE_ORDER_PROPERTY = "mobile_order";
public static final String DASHBOARD_BY_TENANT_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME = "dashboard_by_tenant_and_search_text"; public static final String DASHBOARD_BY_TENANT_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME = "dashboard_by_tenant_and_search_text";

10
dao/src/main/java/org/thingsboard/server/dao/model/sql/DashboardEntity.java

@ -68,6 +68,12 @@ public final class DashboardEntity extends BaseSqlEntity<Dashboard> implements S
@Column(name = ModelConstants.DASHBOARD_ASSIGNED_CUSTOMERS_PROPERTY) @Column(name = ModelConstants.DASHBOARD_ASSIGNED_CUSTOMERS_PROPERTY)
private String assignedCustomers; private String assignedCustomers;
@Column(name = ModelConstants.DASHBOARD_MOBILE_HIDE_PROPERTY)
private boolean mobileHide;
@Column(name = ModelConstants.DASHBOARD_MOBILE_ORDER_PROPERTY)
private Integer mobileOrder;
@Type(type = "json") @Type(type = "json")
@Column(name = ModelConstants.DASHBOARD_CONFIGURATION_PROPERTY) @Column(name = ModelConstants.DASHBOARD_CONFIGURATION_PROPERTY)
private JsonNode configuration; private JsonNode configuration;
@ -93,6 +99,8 @@ public final class DashboardEntity extends BaseSqlEntity<Dashboard> implements S
log.error("Unable to serialize assigned customers to string!", e); log.error("Unable to serialize assigned customers to string!", e);
} }
} }
this.mobileHide = dashboard.isMobileHide();
this.mobileOrder = dashboard.getMobileOrder();
this.configuration = dashboard.getConfiguration(); this.configuration = dashboard.getConfiguration();
} }
@ -122,6 +130,8 @@ public final class DashboardEntity extends BaseSqlEntity<Dashboard> implements S
log.warn("Unable to parse assigned customers!", e); log.warn("Unable to parse assigned customers!", e);
} }
} }
dashboard.setMobileHide(mobileHide);
dashboard.setMobileOrder(mobileOrder);
dashboard.setConfiguration(configuration); dashboard.setConfiguration(configuration);
return dashboard; return dashboard;
} }

10
dao/src/main/java/org/thingsboard/server/dao/model/sql/DashboardInfoEntity.java

@ -63,6 +63,12 @@ public class DashboardInfoEntity extends BaseSqlEntity<DashboardInfo> implements
@Column(name = ModelConstants.DASHBOARD_ASSIGNED_CUSTOMERS_PROPERTY) @Column(name = ModelConstants.DASHBOARD_ASSIGNED_CUSTOMERS_PROPERTY)
private String assignedCustomers; private String assignedCustomers;
@Column(name = ModelConstants.DASHBOARD_MOBILE_HIDE_PROPERTY)
private boolean mobileHide;
@Column(name = ModelConstants.DASHBOARD_MOBILE_ORDER_PROPERTY)
private Integer mobileOrder;
public DashboardInfoEntity() { public DashboardInfoEntity() {
super(); super();
} }
@ -84,6 +90,8 @@ public class DashboardInfoEntity extends BaseSqlEntity<DashboardInfo> implements
log.error("Unable to serialize assigned customers to string!", e); log.error("Unable to serialize assigned customers to string!", e);
} }
} }
this.mobileHide = dashboardInfo.isMobileHide();
this.mobileOrder = dashboardInfo.getMobileOrder();
} }
@Override @Override
@ -116,6 +124,8 @@ public class DashboardInfoEntity extends BaseSqlEntity<DashboardInfo> implements
log.warn("Unable to parse assigned customers!", e); log.warn("Unable to parse assigned customers!", e);
} }
} }
dashboardInfo.setMobileHide(mobileHide);
dashboardInfo.setMobileOrder(mobileOrder);
return dashboardInfo; return dashboardInfo;
} }

17
dao/src/main/java/org/thingsboard/server/dao/sql/dashboard/DashboardInfoRepository.java

@ -37,6 +37,13 @@ public interface DashboardInfoRepository extends PagingAndSortingRepository<Dash
@Param("searchText") String searchText, @Param("searchText") String searchText,
Pageable pageable); Pageable pageable);
@Query("SELECT di FROM DashboardInfoEntity di WHERE di.tenantId = :tenantId " +
"AND di.mobileHide = false " +
"AND LOWER(di.searchText) LIKE LOWER(CONCAT(:searchText, '%'))")
Page<DashboardInfoEntity> findMobileByTenantId(@Param("tenantId") UUID tenantId,
@Param("searchText") String searchText,
Pageable pageable);
@Query("SELECT di FROM DashboardInfoEntity di, RelationEntity re WHERE di.tenantId = :tenantId " + @Query("SELECT di FROM DashboardInfoEntity di, RelationEntity re WHERE di.tenantId = :tenantId " +
"AND di.id = re.toId AND re.toType = 'DASHBOARD' AND re.relationTypeGroup = 'DASHBOARD' " + "AND di.id = re.toId AND re.toType = 'DASHBOARD' AND re.relationTypeGroup = 'DASHBOARD' " +
"AND re.relationType = 'Contains' AND re.fromId = :customerId AND re.fromType = 'CUSTOMER' " + "AND re.relationType = 'Contains' AND re.fromId = :customerId AND re.fromType = 'CUSTOMER' " +
@ -46,6 +53,16 @@ public interface DashboardInfoRepository extends PagingAndSortingRepository<Dash
@Param("searchText") String searchText, @Param("searchText") String searchText,
Pageable pageable); Pageable pageable);
@Query("SELECT di FROM DashboardInfoEntity di, RelationEntity re WHERE di.tenantId = :tenantId " +
"AND di.mobileHide = false " +
"AND di.id = re.toId AND re.toType = 'DASHBOARD' AND re.relationTypeGroup = 'DASHBOARD' " +
"AND re.relationType = 'Contains' AND re.fromId = :customerId AND re.fromType = 'CUSTOMER' " +
"AND LOWER(di.searchText) LIKE LOWER(CONCAT(:searchText, '%'))")
Page<DashboardInfoEntity> findMobileByTenantIdAndCustomerId(@Param("tenantId") UUID tenantId,
@Param("customerId") UUID customerId,
@Param("searchText") String searchText,
Pageable pageable);
@Query("SELECT di FROM DashboardInfoEntity di, RelationEntity re WHERE di.tenantId = :tenantId " + @Query("SELECT di FROM DashboardInfoEntity di, RelationEntity re WHERE di.tenantId = :tenantId " +
"AND di.id = re.toId AND re.toType = 'DASHBOARD' AND re.relationTypeGroup = 'EDGE' " + "AND di.id = re.toId AND re.toType = 'DASHBOARD' AND re.relationTypeGroup = 'EDGE' " +
"AND re.relationType = 'Contains' AND re.fromId = :edgeId AND re.fromType = 'EDGE' " + "AND re.relationType = 'Contains' AND re.fromId = :edgeId AND re.fromType = 'EDGE' " +

35
dao/src/main/java/org/thingsboard/server/dao/sql/dashboard/JpaDashboardInfoDao.java

@ -22,12 +22,15 @@ import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.DashboardInfo; import org.thingsboard.server.common.data.DashboardInfo;
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.page.SortOrder;
import org.thingsboard.server.dao.DaoUtil; import org.thingsboard.server.dao.DaoUtil;
import org.thingsboard.server.dao.dashboard.DashboardInfoDao; import org.thingsboard.server.dao.dashboard.DashboardInfoDao;
import org.thingsboard.server.dao.model.sql.DashboardInfoEntity; import org.thingsboard.server.dao.model.sql.DashboardInfoEntity;
import org.thingsboard.server.dao.relation.RelationDao; import org.thingsboard.server.dao.relation.RelationDao;
import org.thingsboard.server.dao.sql.JpaAbstractSearchTextDao; import org.thingsboard.server.dao.sql.JpaAbstractSearchTextDao;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects; import java.util.Objects;
import java.util.UUID; import java.util.UUID;
@ -41,9 +44,6 @@ public class JpaDashboardInfoDao extends JpaAbstractSearchTextDao<DashboardInfoE
@Autowired @Autowired
private DashboardInfoRepository dashboardInfoRepository; private DashboardInfoRepository dashboardInfoRepository;
@Autowired
private RelationDao relationDao;
@Override @Override
protected Class<DashboardInfoEntity> getEntityClass() { protected Class<DashboardInfoEntity> getEntityClass() {
return DashboardInfoEntity.class; return DashboardInfoEntity.class;
@ -63,6 +63,20 @@ public class JpaDashboardInfoDao extends JpaAbstractSearchTextDao<DashboardInfoE
DaoUtil.toPageable(pageLink))); DaoUtil.toPageable(pageLink)));
} }
@Override
public PageData<DashboardInfo> findMobileDashboardsByTenantId(UUID tenantId, PageLink pageLink) {
List<SortOrder> sortOrders = new ArrayList<>();
sortOrders.add(new SortOrder("mobileOrder", SortOrder.Direction.ASC));
if (pageLink.getSortOrder() != null) {
sortOrders.add(pageLink.getSortOrder());
}
return DaoUtil.toPageData(dashboardInfoRepository
.findMobileByTenantId(
tenantId,
Objects.toString(pageLink.getTextSearch(), ""),
DaoUtil.toPageable(pageLink, sortOrders)));
}
@Override @Override
public PageData<DashboardInfo> findDashboardsByTenantIdAndCustomerId(UUID tenantId, UUID customerId, PageLink pageLink) { public PageData<DashboardInfo> findDashboardsByTenantIdAndCustomerId(UUID tenantId, UUID customerId, PageLink pageLink) {
return DaoUtil.toPageData(dashboardInfoRepository return DaoUtil.toPageData(dashboardInfoRepository
@ -73,6 +87,21 @@ public class JpaDashboardInfoDao extends JpaAbstractSearchTextDao<DashboardInfoE
DaoUtil.toPageable(pageLink))); DaoUtil.toPageable(pageLink)));
} }
@Override
public PageData<DashboardInfo> findMobileDashboardsByTenantIdAndCustomerId(UUID tenantId, UUID customerId, PageLink pageLink) {
List<SortOrder> sortOrders = new ArrayList<>();
sortOrders.add(new SortOrder("mobileOrder", SortOrder.Direction.ASC));
if (pageLink.getSortOrder() != null) {
sortOrders.add(pageLink.getSortOrder());
}
return DaoUtil.toPageData(dashboardInfoRepository
.findMobileByTenantIdAndCustomerId(
tenantId,
customerId,
Objects.toString(pageLink.getTextSearch(), ""),
DaoUtil.toPageable(pageLink, sortOrders)));
}
@Override @Override
public PageData<DashboardInfo> findDashboardsByTenantIdAndEdgeId(UUID tenantId, UUID edgeId, PageLink pageLink) { public PageData<DashboardInfo> findDashboardsByTenantIdAndEdgeId(UUID tenantId, UUID edgeId, PageLink pageLink) {
log.debug("Try to find dashboards by tenantId [{}], edgeId [{}] and pageLink [{}]", tenantId, edgeId, pageLink); log.debug("Try to find dashboards by tenantId [{}], edgeId [{}] and pageLink [{}]", tenantId, edgeId, pageLink);

2
dao/src/main/resources/sql/schema-entities-hsql.sql

@ -123,6 +123,8 @@ CREATE TABLE IF NOT EXISTS dashboard (
search_text varchar(255), search_text varchar(255),
tenant_id uuid, tenant_id uuid,
title varchar(255), title varchar(255),
mobile_hide boolean DEFAULT false,
mobile_order int,
image varchar(1000000) image varchar(1000000)
); );

2
dao/src/main/resources/sql/schema-entities.sql

@ -138,6 +138,8 @@ CREATE TABLE IF NOT EXISTS dashboard (
search_text varchar(255), search_text varchar(255),
tenant_id uuid, tenant_id uuid,
title varchar(255), title varchar(255),
mobile_hide boolean DEFAULT false,
mobile_order int,
image varchar(1000000) image varchar(1000000)
); );

62
dao/src/test/java/org/thingsboard/server/dao/service/BaseDashboardServiceTest.java

@ -31,12 +31,14 @@ import org.thingsboard.server.common.data.id.EdgeId;
import org.thingsboard.server.common.data.id.TenantId; 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.page.SortOrder;
import org.thingsboard.server.common.data.page.TimePageLink; import org.thingsboard.server.common.data.page.TimePageLink;
import org.thingsboard.server.dao.exception.DataValidationException; import org.thingsboard.server.dao.exception.DataValidationException;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.Comparator;
import java.util.List; import java.util.List;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
@ -204,6 +206,66 @@ public abstract class BaseDashboardServiceTest extends AbstractServiceTest {
tenantService.deleteTenant(tenantId); tenantService.deleteTenant(tenantId);
} }
@Test
public void testFindMobileDashboardsByTenantId() {
Tenant tenant = new Tenant();
tenant.setTitle("Test tenant");
tenant = tenantService.saveTenant(tenant);
TenantId tenantId = tenant.getId();
List<DashboardInfo> mobileDashboards = new ArrayList<>();
for (int i=0;i<165;i++) {
Dashboard dashboard = new Dashboard();
dashboard.setTenantId(tenantId);
dashboard.setTitle("Dashboard"+i);
dashboard.setMobileHide(i % 2 == 0);
if (!dashboard.isMobileHide()) {
dashboard.setMobileOrder(i % 4 == 0 ? (int)(Math.random() * 100) : null);
}
Dashboard savedDashboard = dashboardService.saveDashboard(dashboard);
if (!dashboard.isMobileHide()) {
mobileDashboards.add(new DashboardInfo(savedDashboard));
}
}
List<DashboardInfo> loadedMobileDashboards = new ArrayList<>();
PageLink pageLink = new PageLink(16, 0, null, new SortOrder("createdTime", SortOrder.Direction.ASC));
PageData<DashboardInfo> pageData = null;
do {
pageData = dashboardService.findMobileDashboardsByTenantId(tenantId, pageLink);
loadedMobileDashboards.addAll(pageData.getData());
if (pageData.hasNext()) {
pageLink = pageLink.nextPageLink();
}
} while (pageData.hasNext());
Collections.sort(mobileDashboards, (o1, o2) -> {
Integer order1 = o1.getMobileOrder();
Integer order2 = o2.getMobileOrder();
if (order1 == null && order2 == null) {
return o1.getId().getId().compareTo(o2.getId().getId());
} else if (order1 == null && order2 != null) {
return 1;
} else if (order2 == null) {
return -1;
} else {
return order1 - order2;
}
});
Assert.assertEquals(mobileDashboards, loadedMobileDashboards);
dashboardService.deleteDashboardsByTenantId(tenantId);
pageLink = new PageLink(31);
pageData = dashboardService.findMobileDashboardsByTenantId(tenantId, pageLink);
Assert.assertFalse(pageData.hasNext());
Assert.assertTrue(pageData.getData().isEmpty());
tenantService.deleteTenant(tenantId);
}
@Test @Test
public void testFindDashboardsByTenantIdAndTitle() { public void testFindDashboardsByTenantIdAndTitle() {

3
ui-ngx/src/app/core/services/dashboard-utils.service.ts

@ -389,7 +389,8 @@ export class DashboardUtilsService {
sizeX: originalSize ? originalSize.sizeX : widget.sizeX, sizeX: originalSize ? originalSize.sizeX : widget.sizeX,
sizeY: originalSize ? originalSize.sizeY : widget.sizeY, sizeY: originalSize ? originalSize.sizeY : widget.sizeY,
mobileOrder: widget.config.mobileOrder, mobileOrder: widget.config.mobileOrder,
mobileHeight: widget.config.mobileHeight mobileHeight: widget.config.mobileHeight,
mobileHide: widget.config.mobileHide
}; };
if (isUndefined(originalColumns)) { if (isUndefined(originalColumns)) {
originalColumns = 24; originalColumns = 24;

1
ui-ngx/src/app/modules/home/components/dashboard-page/add-widget-dialog.component.ts

@ -127,6 +127,7 @@ export class AddWidgetDialogComponent extends DialogComponent<AddWidgetDialogCom
this.widget.config = widgetConfig.config; this.widget.config = widgetConfig.config;
this.widget.config.mobileOrder = widgetConfig.layout.mobileOrder; this.widget.config.mobileOrder = widgetConfig.layout.mobileOrder;
this.widget.config.mobileHeight = widgetConfig.layout.mobileHeight; this.widget.config.mobileHeight = widgetConfig.layout.mobileHeight;
this.widget.config.mobileHide = widgetConfig.layout.mobileHide;
this.dialogRef.close(this.widget); this.dialogRef.close(this.widget);
} }
} }

4
ui-ngx/src/app/modules/home/components/dashboard-page/states/default-state-controller.component.ts

@ -23,7 +23,7 @@ import { StateControllerComponent } from './state-controller.component';
import { StatesControllerService } from '@home/components/dashboard-page/states/states-controller.service'; import { StatesControllerService } from '@home/components/dashboard-page/states/states-controller.service';
import { EntityId } from '@app/shared/models/id/entity-id'; import { EntityId } from '@app/shared/models/id/entity-id';
import { UtilsService } from '@core/services/utils.service'; import { UtilsService } from '@core/services/utils.service';
import { base64toObj, objToBase64URI } from '@app/core/utils'; import { base64toObj, objToBase64 } from '@app/core/utils';
import { DashboardUtilsService } from '@core/services/dashboard-utils.service'; import { DashboardUtilsService } from '@core/services/dashboard-utils.service';
import { EntityService } from '@core/http/entity.service'; import { EntityService } from '@core/http/entity.service';
import { MobileService } from '@core/services/mobile.service'; import { MobileService } from '@core/services/mobile.service';
@ -246,7 +246,7 @@ export class DefaultStateControllerComponent extends StateControllerComponent im
private updateLocation() { private updateLocation() {
if (this.stateObject[0].id) { if (this.stateObject[0].id) {
const newState = objToBase64URI(this.stateObject); const newState = objToBase64(this.stateObject);
this.updateStateParam(newState); this.updateStateParam(newState);
} }
} }

4
ui-ngx/src/app/modules/home/components/dashboard-page/states/entity-state-controller.component.ts

@ -23,7 +23,7 @@ import { StateControllerComponent } from './state-controller.component';
import { StatesControllerService } from '@home/components/dashboard-page/states/states-controller.service'; import { StatesControllerService } from '@home/components/dashboard-page/states/states-controller.service';
import { EntityId } from '@app/shared/models/id/entity-id'; import { EntityId } from '@app/shared/models/id/entity-id';
import { UtilsService } from '@core/services/utils.service'; import { UtilsService } from '@core/services/utils.service';
import { base64toObj, insertVariable, isEmpty, objToBase64URI } from '@app/core/utils'; import { base64toObj, insertVariable, isEmpty, objToBase64 } from '@app/core/utils';
import { DashboardUtilsService } from '@core/services/dashboard-utils.service'; import { DashboardUtilsService } from '@core/services/dashboard-utils.service';
import { EntityService } from '@core/http/entity.service'; import { EntityService } from '@core/http/entity.service';
import { EntityType } from '@shared/models/entity-type.models'; import { EntityType } from '@shared/models/entity-type.models';
@ -289,7 +289,7 @@ export class EntityStateControllerComponent extends StateControllerComponent imp
if (this.isDefaultState()) { if (this.isDefaultState()) {
newState = null; newState = null;
} else { } else {
newState = objToBase64URI(this.stateObject); newState = objToBase64(this.stateObject);
} }
this.updateStateParam(newState, !isStateIdChanged); this.updateStateParam(newState, !isStateIdChanged);
} }

2
ui-ngx/src/app/modules/home/components/dashboard-page/states/state-controller.component.ts

@ -129,7 +129,7 @@ export abstract class StateControllerComponent implements IStateControllerCompon
protected updateStateParam(newState: string, replaceCurrentHistoryUrl = false) { protected updateStateParam(newState: string, replaceCurrentHistoryUrl = false) {
this.currentState = newState; this.currentState = newState;
if (this.syncStateWithQueryParam) { if (this.syncStateWithQueryParam) {
const queryParams: Params = {state: this.currentState}; const queryParams: Params = {state: encodeURIComponent(this.currentState)};
this.ngZone.run(() => { this.ngZone.run(() => {
this.router.navigate( this.router.navigate(
[], [],

3
ui-ngx/src/app/modules/home/components/widget/widget-config.component.html

@ -418,6 +418,9 @@
<span translate>widget-config.mobile-mode-settings</span> <span translate>widget-config.mobile-mode-settings</span>
<div fxLayout.xs="column" fxLayoutAlign.xs="center" fxLayout="row" fxLayoutAlign="start center" <div fxLayout.xs="column" fxLayoutAlign.xs="center" fxLayout="row" fxLayoutAlign="start center"
fxLayoutGap="8px"> fxLayoutGap="8px">
<mat-checkbox formControlName="mobileHide">
{{ 'widget-config.mobile-hide' | translate }}
</mat-checkbox>
<mat-form-field fxFlex> <mat-form-field fxFlex>
<mat-label translate>widget-config.order</mat-label> <mat-label translate>widget-config.order</mat-label>
<input matInput formControlName="mobileOrder" type="number" step="1"> <input matInput formControlName="mobileOrder" type="number" step="1">

9
ui-ngx/src/app/modules/home/components/widget/widget-config.component.ts

@ -228,7 +228,8 @@ export class WidgetConfigComponent extends PageComponent implements OnInit, Cont
}); });
this.layoutSettings = this.fb.group({ this.layoutSettings = this.fb.group({
mobileOrder: [null, [Validators.pattern(/^-?[0-9]+$/)]], mobileOrder: [null, [Validators.pattern(/^-?[0-9]+$/)]],
mobileHeight: [null, [Validators.min(1), Validators.max(10), Validators.pattern(/^\d*$/)]] mobileHeight: [null, [Validators.min(1), Validators.max(10), Validators.pattern(/^\d*$/)]],
mobileHide: [false]
}); });
this.actionsSettings = this.fb.group({ this.actionsSettings = this.fb.group({
actionsData: [null, []] actionsData: [null, []]
@ -502,7 +503,8 @@ export class WidgetConfigComponent extends PageComponent implements OnInit, Cont
this.layoutSettings.patchValue( this.layoutSettings.patchValue(
{ {
mobileOrder: layout.mobileOrder, mobileOrder: layout.mobileOrder,
mobileHeight: layout.mobileHeight mobileHeight: layout.mobileHeight,
mobileHide: layout.mobileHide
}, },
{emitEvent: false} {emitEvent: false}
); );
@ -510,7 +512,8 @@ export class WidgetConfigComponent extends PageComponent implements OnInit, Cont
this.layoutSettings.patchValue( this.layoutSettings.patchValue(
{ {
mobileOrder: null, mobileOrder: null,
mobileHeight: null mobileHeight: null,
mobileHide: false
}, },
{emitEvent: false} {emitEvent: false}
); );

21
ui-ngx/src/app/modules/home/models/dashboard-component.models.ts

@ -63,6 +63,7 @@ export interface IDashboardComponent {
dashboardWidgets: DashboardWidgets; dashboardWidgets: DashboardWidgets;
mobileAutofillHeight: boolean; mobileAutofillHeight: boolean;
isMobileSize: boolean; isMobileSize: boolean;
isEdit: boolean;
autofillHeight: boolean; autofillHeight: boolean;
dashboardTimewindow: Timewindow; dashboardTimewindow: Timewindow;
dashboardTimewindowChanged: Observable<Timewindow>; dashboardTimewindowChanged: Observable<Timewindow>;
@ -99,7 +100,14 @@ export class DashboardWidgets implements Iterable<DashboardWidget> {
widgetLayouts: WidgetLayouts; widgetLayouts: WidgetLayouts;
[Symbol.iterator](): Iterator<DashboardWidget> { [Symbol.iterator](): Iterator<DashboardWidget> {
return this.dashboardWidgets[Symbol.iterator](); return this.activeDashboardWidgets[Symbol.iterator]();
}
get activeDashboardWidgets(): Array<DashboardWidget> {
if (this.dashboard.isMobileSize && !this.dashboard.isEdit) {
return this.dashboardWidgets.filter(w => !w.mobileHide);
}
return this.dashboardWidgets;
} }
constructor(private dashboard: IDashboardComponent, constructor(private dashboard: IDashboardComponent,
@ -152,6 +160,7 @@ export class DashboardWidgets implements Iterable<DashboardWidget> {
} }
if (updateRecords.length) { if (updateRecords.length) {
updateRecords.forEach((record) => { updateRecords.forEach((record) => {
let index;
switch (record.operation) { switch (record.operation) {
case 'add': case 'add':
this.dashboardWidgets.push( this.dashboardWidgets.push(
@ -159,7 +168,7 @@ export class DashboardWidgets implements Iterable<DashboardWidget> {
); );
break; break;
case 'remove': case 'remove':
let index = this.dashboardWidgets.findIndex((dashboardWidget) => dashboardWidget.widgetId === record.widgetId); index = this.dashboardWidgets.findIndex((dashboardWidget) => dashboardWidget.widgetId === record.widgetId);
if (index > -1) { if (index > -1) {
this.dashboardWidgets.splice(index, 1); this.dashboardWidgets.splice(index, 1);
} }
@ -261,7 +270,7 @@ export class DashboardWidgets implements Iterable<DashboardWidget> {
private updateRowsAndSort() { private updateRowsAndSort() {
let maxRows = this.dashboard.gridsterOpts.maxRows; let maxRows = this.dashboard.gridsterOpts.maxRows;
this.dashboardWidgets.forEach((dashboardWidget) => { this.activeDashboardWidgets.forEach((dashboardWidget) => {
const bottom = dashboardWidget.y + dashboardWidget.rows; const bottom = dashboardWidget.y + dashboardWidget.rows;
maxRows = Math.max(maxRows, bottom); maxRows = Math.max(maxRows, bottom);
}); });
@ -328,6 +337,10 @@ export class DashboardWidget implements GridsterItem, IDashboardWidget {
private gridsterItemComponentSubject = new Subject<GridsterItemComponentInterface>(); private gridsterItemComponentSubject = new Subject<GridsterItemComponentInterface>();
private gridsterItemComponentValue: GridsterItemComponentInterface; private gridsterItemComponentValue: GridsterItemComponentInterface;
get mobileHide(): boolean {
return this.widgetLayout ? this.widgetLayout.mobileHide === true : false;
}
set gridsterItemComponent(item: GridsterItemComponentInterface) { set gridsterItemComponent(item: GridsterItemComponentInterface) {
this.gridsterItemComponentValue = item; this.gridsterItemComponentValue = item;
this.gridsterItemComponentSubject.next(this.gridsterItemComponentValue); this.gridsterItemComponentSubject.next(this.gridsterItemComponentValue);
@ -423,7 +436,7 @@ export class DashboardWidget implements GridsterItem, IDashboardWidget {
this.showWidgetTitlePanel = this.widgetContext.hideTitlePanel ? false : this.showWidgetTitlePanel = this.widgetContext.hideTitlePanel ? false :
this.showTitle || this.hasTimewindow; this.showTitle || this.hasTimewindow;
this.showWidgetActions = this.widgetContext.hideTitlePanel ? false : true; this.showWidgetActions = !this.widgetContext.hideTitlePanel;
this.customHeaderActions = this.widgetContext.customHeaderActions ? this.widgetContext.customHeaderActions : []; this.customHeaderActions = this.widgetContext.customHeaderActions ? this.widgetContext.customHeaderActions : [];
this.widgetActions = this.widgetContext.widgetActions ? this.widgetContext.widgetActions : []; this.widgetActions = this.widgetContext.widgetActions ? this.widgetContext.widgetActions : [];

18
ui-ngx/src/app/modules/home/pages/dashboard/dashboard-form.component.html

@ -105,17 +105,25 @@
{{ 'dashboard.title-required' | translate }} {{ 'dashboard.title-required' | translate }}
</mat-error> </mat-error>
</mat-form-field> </mat-form-field>
<tb-image-input fxFlex
label="{{'dashboard.image' | translate}}"
maxSizeByte="524288"
formControlName="image">
</tb-image-input>
<div formGroupName="configuration" fxLayout="column"> <div formGroupName="configuration" fxLayout="column">
<mat-form-field class="mat-block"> <mat-form-field class="mat-block">
<mat-label translate>dashboard.description</mat-label> <mat-label translate>dashboard.description</mat-label>
<textarea matInput formControlName="description" rows="2"></textarea> <textarea matInput formControlName="description" rows="2"></textarea>
</mat-form-field> </mat-form-field>
</div> </div>
<div style="padding-bottom: 16px;" translate>dashboard.mobile-app-settings</div>
<tb-image-input fxFlex
label="{{'dashboard.image' | translate}}"
maxSizeByte="524288"
formControlName="image">
</tb-image-input>
<mat-checkbox fxFlex formControlName="mobileHide" style="padding-bottom: 16px; padding-top: 16px;">
{{ 'dashboard.mobile-hide' | translate }}
</mat-checkbox>
<mat-form-field class="mat-block">
<mat-label translate>dashboard.mobile-order</mat-label>
<input matInput formControlName="mobileOrder" type="number" step="1">
</mat-form-field>
</fieldset> </fieldset>
</form> </form>
</div> </div>

4
ui-ngx/src/app/modules/home/pages/dashboard/dashboard-form.component.ts

@ -81,6 +81,8 @@ export class DashboardFormComponent extends EntityComponent<Dashboard> {
{ {
title: [entity ? entity.title : '', [Validators.required]], title: [entity ? entity.title : '', [Validators.required]],
image: [entity ? entity.image : null], image: [entity ? entity.image : null],
mobileHide: [entity ? entity.mobileHide : false],
mobileOrder: [entity ? entity.mobileOrder : null, [Validators.pattern(/^-?[0-9]+$/)]],
configuration: this.fb.group( configuration: this.fb.group(
{ {
description: [entity && entity.configuration ? entity.configuration.description : ''], description: [entity && entity.configuration ? entity.configuration.description : ''],
@ -94,6 +96,8 @@ export class DashboardFormComponent extends EntityComponent<Dashboard> {
this.updateFields(entity); this.updateFields(entity);
this.entityForm.patchValue({title: entity.title}); this.entityForm.patchValue({title: entity.title});
this.entityForm.patchValue({image: entity.image}); this.entityForm.patchValue({image: entity.image});
this.entityForm.patchValue({mobileHide: entity.mobileHide});
this.entityForm.patchValue({mobileOrder: entity.mobileOrder});
this.entityForm.patchValue({configuration: {description: entity.configuration ? entity.configuration.description : ''}}); this.entityForm.patchValue({configuration: {description: entity.configuration ? entity.configuration.description : ''}});
} }

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

@ -28,11 +28,14 @@ export interface DashboardInfo extends BaseData<DashboardId> {
title?: string; title?: string;
image?: string; image?: string;
assignedCustomers?: Array<ShortCustomerInfo>; assignedCustomers?: Array<ShortCustomerInfo>;
mobileHide?: boolean;
mobileOrder?: number;
} }
export interface WidgetLayout { export interface WidgetLayout {
sizeX?: number; sizeX?: number;
sizeY?: number; sizeY?: number;
mobileHide?: boolean;
mobileHeight?: number; mobileHeight?: number;
mobileOrder?: number; mobileOrder?: number;
col?: number; col?: number;

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

@ -484,6 +484,7 @@ export interface WidgetConfig {
showLegend?: boolean; showLegend?: boolean;
legendConfig?: LegendConfig; legendConfig?: LegendConfig;
timewindow?: Timewindow; timewindow?: Timewindow;
mobileHide?: boolean;
mobileHeight?: number; mobileHeight?: number;
mobileOrder?: number; mobileOrder?: number;
color?: string; color?: string;

4
ui-ngx/src/assets/locale/locale.constant-en_US.json

@ -694,6 +694,9 @@
"add-widget": "Add new widget", "add-widget": "Add new widget",
"title": "Title", "title": "Title",
"image": "Dashboard image", "image": "Dashboard image",
"mobile-app-settings": "Mobile application settings",
"mobile-order": "Dashboard order in mobile application",
"mobile-hide": "Hide dashboard in mobile application",
"update-image": "Update dashboard image", "update-image": "Update dashboard image",
"take-screenshot": "Take screenshot", "take-screenshot": "Take screenshot",
"select-widget-title": "Select widget", "select-widget-title": "Select widget",
@ -2970,6 +2973,7 @@
"mobile-mode-settings": "Mobile mode settings", "mobile-mode-settings": "Mobile mode settings",
"order": "Order", "order": "Order",
"height": "Height", "height": "Height",
"mobile-hide": "Hide widget in mobile mode",
"units": "Special symbol to show next to value", "units": "Special symbol to show next to value",
"decimals": "Number of digits after floating point", "decimals": "Number of digits after floating point",
"timewindow": "Timewindow", "timewindow": "Timewindow",

Loading…
Cancel
Save