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
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
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);

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

@ -468,13 +468,18 @@ public class DashboardController extends BaseController {
public PageData<DashboardInfo> getTenantDashboards(
@RequestParam int pageSize,
@RequestParam int page,
@RequestParam(required = false) Boolean mobile,
@RequestParam(required = false) String textSearch,
@RequestParam(required = false) String sortProperty,
@RequestParam(required = false) String sortOrder) throws ThingsboardException {
try {
TenantId tenantId = getCurrentUser().getTenantId();
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) {
throw handleException(e);
}
@ -487,6 +492,7 @@ public class DashboardController extends BaseController {
@PathVariable("customerId") String strCustomerId,
@RequestParam int pageSize,
@RequestParam int page,
@RequestParam(required = false) Boolean mobile,
@RequestParam(required = false) String textSearch,
@RequestParam(required = false) String sortProperty,
@RequestParam(required = false) String sortOrder) throws ThingsboardException {
@ -496,7 +502,11 @@ public class DashboardController extends BaseController {
CustomerId customerId = new CustomerId(toUUID(strCustomerId));
checkCustomerId(customerId, Operation.READ);
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) {
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> findMobileDashboardsByTenantId(TenantId tenantId, PageLink pageLink);
void deleteDashboardsByTenantId(TenantId tenantId);
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 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;
@Valid
private Set<ShortCustomerInfo> assignedCustomers;
private boolean mobileHide;
private Integer mobileOrder;
public DashboardInfo() {
super();
@ -48,6 +50,8 @@ public class DashboardInfo extends SearchTextBased<DashboardId> implements HasNa
this.title = dashboardInfo.getTitle();
this.image = dashboardInfo.getImage();
this.assignedCustomers = dashboardInfo.getAssignedCustomers();
this.mobileHide = dashboardInfo.isMobileHide();
this.mobileOrder = dashboardInfo.getMobileOrder();
}
public TenantId getTenantId() {
@ -82,10 +86,27 @@ public class DashboardInfo extends SearchTextBased<DashboardId> implements HasNa
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) {
return this.assignedCustomers != null && this.assignedCustomers.contains(new ShortCustomerInfo(customerId, null, false));
}
public ShortCustomerInfo getAssignedCustomerInfo(CustomerId customerId) {
if (this.assignedCustomers != null) {
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.Optional;
import java.util.UUID;
import java.util.stream.Collectors;
public abstract class DaoUtil {
@ -55,6 +56,14 @@ public abstract class DaoUtil {
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) {
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) {
List<T> list = Collections.emptyList();
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);
/**
* 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.
*
@ -46,6 +55,16 @@ public interface DashboardInfoDao extends Dao<DashboardInfo> {
*/
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.
*

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);
}
@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
public void 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);
}
@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
public void unassignCustomerDashboards(TenantId tenantId, 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_CONFIGURATION_PROPERTY = "configuration";
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";

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)
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")
@Column(name = ModelConstants.DASHBOARD_CONFIGURATION_PROPERTY)
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);
}
}
this.mobileHide = dashboard.isMobileHide();
this.mobileOrder = dashboard.getMobileOrder();
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);
}
}
dashboard.setMobileHide(mobileHide);
dashboard.setMobileOrder(mobileOrder);
dashboard.setConfiguration(configuration);
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)
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() {
super();
}
@ -84,6 +90,8 @@ public class DashboardInfoEntity extends BaseSqlEntity<DashboardInfo> implements
log.error("Unable to serialize assigned customers to string!", e);
}
}
this.mobileHide = dashboardInfo.isMobileHide();
this.mobileOrder = dashboardInfo.getMobileOrder();
}
@Override
@ -116,6 +124,8 @@ public class DashboardInfoEntity extends BaseSqlEntity<DashboardInfo> implements
log.warn("Unable to parse assigned customers!", e);
}
}
dashboardInfo.setMobileHide(mobileHide);
dashboardInfo.setMobileOrder(mobileOrder);
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,
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 " +
"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' " +
@ -46,6 +53,16 @@ public interface DashboardInfoRepository extends PagingAndSortingRepository<Dash
@Param("searchText") String searchText,
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 " +
"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' " +

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.page.PageData;
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.dashboard.DashboardInfoDao;
import org.thingsboard.server.dao.model.sql.DashboardInfoEntity;
import org.thingsboard.server.dao.relation.RelationDao;
import org.thingsboard.server.dao.sql.JpaAbstractSearchTextDao;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.UUID;
@ -41,9 +44,6 @@ public class JpaDashboardInfoDao extends JpaAbstractSearchTextDao<DashboardInfoE
@Autowired
private DashboardInfoRepository dashboardInfoRepository;
@Autowired
private RelationDao relationDao;
@Override
protected Class<DashboardInfoEntity> getEntityClass() {
return DashboardInfoEntity.class;
@ -63,6 +63,20 @@ public class JpaDashboardInfoDao extends JpaAbstractSearchTextDao<DashboardInfoE
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
public PageData<DashboardInfo> findDashboardsByTenantIdAndCustomerId(UUID tenantId, UUID customerId, PageLink pageLink) {
return DaoUtil.toPageData(dashboardInfoRepository
@ -73,6 +87,21 @@ public class JpaDashboardInfoDao extends JpaAbstractSearchTextDao<DashboardInfoE
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
public PageData<DashboardInfo> findDashboardsByTenantIdAndEdgeId(UUID tenantId, UUID edgeId, PageLink 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),
tenant_id uuid,
title varchar(255),
mobile_hide boolean DEFAULT false,
mobile_order int,
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),
tenant_id uuid,
title varchar(255),
mobile_hide boolean DEFAULT false,
mobile_order int,
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.page.PageData;
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.dao.exception.DataValidationException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.concurrent.ExecutionException;
@ -204,6 +206,66 @@ public abstract class BaseDashboardServiceTest extends AbstractServiceTest {
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
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,
sizeY: originalSize ? originalSize.sizeY : widget.sizeY,
mobileOrder: widget.config.mobileOrder,
mobileHeight: widget.config.mobileHeight
mobileHeight: widget.config.mobileHeight,
mobileHide: widget.config.mobileHide
};
if (isUndefined(originalColumns)) {
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.mobileOrder = widgetConfig.layout.mobileOrder;
this.widget.config.mobileHeight = widgetConfig.layout.mobileHeight;
this.widget.config.mobileHide = widgetConfig.layout.mobileHide;
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 { EntityId } from '@app/shared/models/id/entity-id';
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 { EntityService } from '@core/http/entity.service';
import { MobileService } from '@core/services/mobile.service';
@ -246,7 +246,7 @@ export class DefaultStateControllerComponent extends StateControllerComponent im
private updateLocation() {
if (this.stateObject[0].id) {
const newState = objToBase64URI(this.stateObject);
const newState = objToBase64(this.stateObject);
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 { EntityId } from '@app/shared/models/id/entity-id';
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 { EntityService } from '@core/http/entity.service';
import { EntityType } from '@shared/models/entity-type.models';
@ -289,7 +289,7 @@ export class EntityStateControllerComponent extends StateControllerComponent imp
if (this.isDefaultState()) {
newState = null;
} else {
newState = objToBase64URI(this.stateObject);
newState = objToBase64(this.stateObject);
}
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) {
this.currentState = newState;
if (this.syncStateWithQueryParam) {
const queryParams: Params = {state: this.currentState};
const queryParams: Params = {state: encodeURIComponent(this.currentState)};
this.ngZone.run(() => {
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>
<div fxLayout.xs="column" fxLayoutAlign.xs="center" fxLayout="row" fxLayoutAlign="start center"
fxLayoutGap="8px">
<mat-checkbox formControlName="mobileHide">
{{ 'widget-config.mobile-hide' | translate }}
</mat-checkbox>
<mat-form-field fxFlex>
<mat-label translate>widget-config.order</mat-label>
<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({
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({
actionsData: [null, []]
@ -502,7 +503,8 @@ export class WidgetConfigComponent extends PageComponent implements OnInit, Cont
this.layoutSettings.patchValue(
{
mobileOrder: layout.mobileOrder,
mobileHeight: layout.mobileHeight
mobileHeight: layout.mobileHeight,
mobileHide: layout.mobileHide
},
{emitEvent: false}
);
@ -510,7 +512,8 @@ export class WidgetConfigComponent extends PageComponent implements OnInit, Cont
this.layoutSettings.patchValue(
{
mobileOrder: null,
mobileHeight: null
mobileHeight: null,
mobileHide: false
},
{emitEvent: false}
);

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

@ -63,6 +63,7 @@ export interface IDashboardComponent {
dashboardWidgets: DashboardWidgets;
mobileAutofillHeight: boolean;
isMobileSize: boolean;
isEdit: boolean;
autofillHeight: boolean;
dashboardTimewindow: Timewindow;
dashboardTimewindowChanged: Observable<Timewindow>;
@ -99,7 +100,14 @@ export class DashboardWidgets implements Iterable<DashboardWidget> {
widgetLayouts: WidgetLayouts;
[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,
@ -152,6 +160,7 @@ export class DashboardWidgets implements Iterable<DashboardWidget> {
}
if (updateRecords.length) {
updateRecords.forEach((record) => {
let index;
switch (record.operation) {
case 'add':
this.dashboardWidgets.push(
@ -159,7 +168,7 @@ export class DashboardWidgets implements Iterable<DashboardWidget> {
);
break;
case 'remove':
let index = this.dashboardWidgets.findIndex((dashboardWidget) => dashboardWidget.widgetId === record.widgetId);
index = this.dashboardWidgets.findIndex((dashboardWidget) => dashboardWidget.widgetId === record.widgetId);
if (index > -1) {
this.dashboardWidgets.splice(index, 1);
}
@ -261,7 +270,7 @@ export class DashboardWidgets implements Iterable<DashboardWidget> {
private updateRowsAndSort() {
let maxRows = this.dashboard.gridsterOpts.maxRows;
this.dashboardWidgets.forEach((dashboardWidget) => {
this.activeDashboardWidgets.forEach((dashboardWidget) => {
const bottom = dashboardWidget.y + dashboardWidget.rows;
maxRows = Math.max(maxRows, bottom);
});
@ -328,6 +337,10 @@ export class DashboardWidget implements GridsterItem, IDashboardWidget {
private gridsterItemComponentSubject = new Subject<GridsterItemComponentInterface>();
private gridsterItemComponentValue: GridsterItemComponentInterface;
get mobileHide(): boolean {
return this.widgetLayout ? this.widgetLayout.mobileHide === true : false;
}
set gridsterItemComponent(item: GridsterItemComponentInterface) {
this.gridsterItemComponentValue = item;
this.gridsterItemComponentSubject.next(this.gridsterItemComponentValue);
@ -423,7 +436,7 @@ export class DashboardWidget implements GridsterItem, IDashboardWidget {
this.showWidgetTitlePanel = this.widgetContext.hideTitlePanel ? false :
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.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 }}
</mat-error>
</mat-form-field>
<tb-image-input fxFlex
label="{{'dashboard.image' | translate}}"
maxSizeByte="524288"
formControlName="image">
</tb-image-input>
<div formGroupName="configuration" fxLayout="column">
<mat-form-field class="mat-block">
<mat-label translate>dashboard.description</mat-label>
<textarea matInput formControlName="description" rows="2"></textarea>
</mat-form-field>
</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>
</form>
</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]],
image: [entity ? entity.image : null],
mobileHide: [entity ? entity.mobileHide : false],
mobileOrder: [entity ? entity.mobileOrder : null, [Validators.pattern(/^-?[0-9]+$/)]],
configuration: this.fb.group(
{
description: [entity && entity.configuration ? entity.configuration.description : ''],
@ -94,6 +96,8 @@ export class DashboardFormComponent extends EntityComponent<Dashboard> {
this.updateFields(entity);
this.entityForm.patchValue({title: entity.title});
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 : ''}});
}

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

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

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

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

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

@ -694,6 +694,9 @@
"add-widget": "Add new widget",
"title": "Title",
"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",
"take-screenshot": "Take screenshot",
"select-widget-title": "Select widget",
@ -2970,6 +2973,7 @@
"mobile-mode-settings": "Mobile mode settings",
"order": "Order",
"height": "Height",
"mobile-hide": "Hide widget in mobile mode",
"units": "Special symbol to show next to value",
"decimals": "Number of digits after floating point",
"timewindow": "Timewindow",

Loading…
Cancel
Save