Commit e1afbe6667524d290895e9ece4c29dc731d1aedf
1 parent
74aca329
Control visibility and order of dashboard in mobile application. Ability to hide…
… widgets in mobile mode. Fix dashboard state changes processing.
Showing
28 changed files
with
301 additions
and
25 deletions
@@ -142,7 +142,9 @@ CREATE TABLE IF NOT EXISTS oauth2_mobile ( | @@ -142,7 +142,9 @@ CREATE TABLE IF NOT EXISTS oauth2_mobile ( | ||
142 | ); | 142 | ); |
143 | 143 | ||
144 | ALTER TABLE dashboard | 144 | ALTER TABLE dashboard |
145 | - ADD COLUMN IF NOT EXISTS image varchar(1000000); | 145 | + ADD COLUMN IF NOT EXISTS image varchar(1000000), |
146 | + ADD COLUMN IF NOT EXISTS mobile_hide boolean DEFAULT false, | ||
147 | + ADD COLUMN IF NOT EXISTS mobile_order int; | ||
146 | 148 | ||
147 | ALTER TABLE device_profile | 149 | ALTER TABLE device_profile |
148 | ADD COLUMN IF NOT EXISTS image varchar(1000000), | 150 | ADD COLUMN IF NOT EXISTS image varchar(1000000), |
@@ -210,4 +212,3 @@ CREATE TABLE IF NOT EXISTS rpc ( | @@ -210,4 +212,3 @@ CREATE TABLE IF NOT EXISTS rpc ( | ||
210 | ); | 212 | ); |
211 | 213 | ||
212 | CREATE INDEX IF NOT EXISTS idx_rpc_tenant_id_device_id ON rpc(tenant_id, device_id); | 214 | CREATE INDEX IF NOT EXISTS idx_rpc_tenant_id_device_id ON rpc(tenant_id, device_id); |
213 | - |
@@ -468,13 +468,18 @@ public class DashboardController extends BaseController { | @@ -468,13 +468,18 @@ public class DashboardController extends BaseController { | ||
468 | public PageData<DashboardInfo> getTenantDashboards( | 468 | public PageData<DashboardInfo> getTenantDashboards( |
469 | @RequestParam int pageSize, | 469 | @RequestParam int pageSize, |
470 | @RequestParam int page, | 470 | @RequestParam int page, |
471 | + @RequestParam(required = false) Boolean mobile, | ||
471 | @RequestParam(required = false) String textSearch, | 472 | @RequestParam(required = false) String textSearch, |
472 | @RequestParam(required = false) String sortProperty, | 473 | @RequestParam(required = false) String sortProperty, |
473 | @RequestParam(required = false) String sortOrder) throws ThingsboardException { | 474 | @RequestParam(required = false) String sortOrder) throws ThingsboardException { |
474 | try { | 475 | try { |
475 | TenantId tenantId = getCurrentUser().getTenantId(); | 476 | TenantId tenantId = getCurrentUser().getTenantId(); |
476 | PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder); | 477 | PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder); |
477 | - return checkNotNull(dashboardService.findDashboardsByTenantId(tenantId, pageLink)); | 478 | + if (mobile != null && mobile.booleanValue()) { |
479 | + return checkNotNull(dashboardService.findMobileDashboardsByTenantId(tenantId, pageLink)); | ||
480 | + } else { | ||
481 | + return checkNotNull(dashboardService.findDashboardsByTenantId(tenantId, pageLink)); | ||
482 | + } | ||
478 | } catch (Exception e) { | 483 | } catch (Exception e) { |
479 | throw handleException(e); | 484 | throw handleException(e); |
480 | } | 485 | } |
@@ -487,6 +492,7 @@ public class DashboardController extends BaseController { | @@ -487,6 +492,7 @@ public class DashboardController extends BaseController { | ||
487 | @PathVariable("customerId") String strCustomerId, | 492 | @PathVariable("customerId") String strCustomerId, |
488 | @RequestParam int pageSize, | 493 | @RequestParam int pageSize, |
489 | @RequestParam int page, | 494 | @RequestParam int page, |
495 | + @RequestParam(required = false) Boolean mobile, | ||
490 | @RequestParam(required = false) String textSearch, | 496 | @RequestParam(required = false) String textSearch, |
491 | @RequestParam(required = false) String sortProperty, | 497 | @RequestParam(required = false) String sortProperty, |
492 | @RequestParam(required = false) String sortOrder) throws ThingsboardException { | 498 | @RequestParam(required = false) String sortOrder) throws ThingsboardException { |
@@ -496,7 +502,11 @@ public class DashboardController extends BaseController { | @@ -496,7 +502,11 @@ public class DashboardController extends BaseController { | ||
496 | CustomerId customerId = new CustomerId(toUUID(strCustomerId)); | 502 | CustomerId customerId = new CustomerId(toUUID(strCustomerId)); |
497 | checkCustomerId(customerId, Operation.READ); | 503 | checkCustomerId(customerId, Operation.READ); |
498 | PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder); | 504 | PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder); |
499 | - return checkNotNull(dashboardService.findDashboardsByTenantIdAndCustomerId(tenantId, customerId, pageLink)); | 505 | + if (mobile != null && mobile.booleanValue()) { |
506 | + return checkNotNull(dashboardService.findMobileDashboardsByTenantIdAndCustomerId(tenantId, customerId, pageLink)); | ||
507 | + } else { | ||
508 | + return checkNotNull(dashboardService.findDashboardsByTenantIdAndCustomerId(tenantId, customerId, pageLink)); | ||
509 | + } | ||
500 | } catch (Exception e) { | 510 | } catch (Exception e) { |
501 | throw handleException(e); | 511 | throw handleException(e); |
502 | } | 512 | } |
@@ -45,10 +45,14 @@ public interface DashboardService { | @@ -45,10 +45,14 @@ public interface DashboardService { | ||
45 | 45 | ||
46 | PageData<DashboardInfo> findDashboardsByTenantId(TenantId tenantId, PageLink pageLink); | 46 | PageData<DashboardInfo> findDashboardsByTenantId(TenantId tenantId, PageLink pageLink); |
47 | 47 | ||
48 | + PageData<DashboardInfo> findMobileDashboardsByTenantId(TenantId tenantId, PageLink pageLink); | ||
49 | + | ||
48 | void deleteDashboardsByTenantId(TenantId tenantId); | 50 | void deleteDashboardsByTenantId(TenantId tenantId); |
49 | 51 | ||
50 | PageData<DashboardInfo> findDashboardsByTenantIdAndCustomerId(TenantId tenantId, CustomerId customerId, PageLink pageLink); | 52 | PageData<DashboardInfo> findDashboardsByTenantIdAndCustomerId(TenantId tenantId, CustomerId customerId, PageLink pageLink); |
51 | 53 | ||
54 | + PageData<DashboardInfo> findMobileDashboardsByTenantIdAndCustomerId(TenantId tenantId, CustomerId customerId, PageLink pageLink); | ||
55 | + | ||
52 | void unassignCustomerDashboards(TenantId tenantId, CustomerId customerId); | 56 | void unassignCustomerDashboards(TenantId tenantId, CustomerId customerId); |
53 | 57 | ||
54 | void updateCustomerDashboards(TenantId tenantId, CustomerId customerId); | 58 | void updateCustomerDashboards(TenantId tenantId, CustomerId customerId); |
@@ -33,6 +33,8 @@ public class DashboardInfo extends SearchTextBased<DashboardId> implements HasNa | @@ -33,6 +33,8 @@ public class DashboardInfo extends SearchTextBased<DashboardId> implements HasNa | ||
33 | private String image; | 33 | private String image; |
34 | @Valid | 34 | @Valid |
35 | private Set<ShortCustomerInfo> assignedCustomers; | 35 | private Set<ShortCustomerInfo> assignedCustomers; |
36 | + private boolean mobileHide; | ||
37 | + private Integer mobileOrder; | ||
36 | 38 | ||
37 | public DashboardInfo() { | 39 | public DashboardInfo() { |
38 | super(); | 40 | super(); |
@@ -48,6 +50,8 @@ public class DashboardInfo extends SearchTextBased<DashboardId> implements HasNa | @@ -48,6 +50,8 @@ public class DashboardInfo extends SearchTextBased<DashboardId> implements HasNa | ||
48 | this.title = dashboardInfo.getTitle(); | 50 | this.title = dashboardInfo.getTitle(); |
49 | this.image = dashboardInfo.getImage(); | 51 | this.image = dashboardInfo.getImage(); |
50 | this.assignedCustomers = dashboardInfo.getAssignedCustomers(); | 52 | this.assignedCustomers = dashboardInfo.getAssignedCustomers(); |
53 | + this.mobileHide = dashboardInfo.isMobileHide(); | ||
54 | + this.mobileOrder = dashboardInfo.getMobileOrder(); | ||
51 | } | 55 | } |
52 | 56 | ||
53 | public TenantId getTenantId() { | 57 | public TenantId getTenantId() { |
@@ -82,10 +86,27 @@ public class DashboardInfo extends SearchTextBased<DashboardId> implements HasNa | @@ -82,10 +86,27 @@ public class DashboardInfo extends SearchTextBased<DashboardId> implements HasNa | ||
82 | this.assignedCustomers = assignedCustomers; | 86 | this.assignedCustomers = assignedCustomers; |
83 | } | 87 | } |
84 | 88 | ||
89 | + public boolean isMobileHide() { | ||
90 | + return mobileHide; | ||
91 | + } | ||
92 | + | ||
93 | + public void setMobileHide(boolean mobileHide) { | ||
94 | + this.mobileHide = mobileHide; | ||
95 | + } | ||
96 | + | ||
97 | + public Integer getMobileOrder() { | ||
98 | + return mobileOrder; | ||
99 | + } | ||
100 | + | ||
101 | + public void setMobileOrder(Integer mobileOrder) { | ||
102 | + this.mobileOrder = mobileOrder; | ||
103 | + } | ||
104 | + | ||
85 | public boolean isAssignedToCustomer(CustomerId customerId) { | 105 | public boolean isAssignedToCustomer(CustomerId customerId) { |
86 | return this.assignedCustomers != null && this.assignedCustomers.contains(new ShortCustomerInfo(customerId, null, false)); | 106 | return this.assignedCustomers != null && this.assignedCustomers.contains(new ShortCustomerInfo(customerId, null, false)); |
87 | } | 107 | } |
88 | 108 | ||
109 | + | ||
89 | public ShortCustomerInfo getAssignedCustomerInfo(CustomerId customerId) { | 110 | public ShortCustomerInfo getAssignedCustomerInfo(CustomerId customerId) { |
90 | if (this.assignedCustomers != null) { | 111 | if (this.assignedCustomers != null) { |
91 | for (ShortCustomerInfo customerInfo : this.assignedCustomers) { | 112 | for (ShortCustomerInfo customerInfo : this.assignedCustomers) { |
@@ -32,6 +32,7 @@ import java.util.List; | @@ -32,6 +32,7 @@ import java.util.List; | ||
32 | import java.util.Map; | 32 | import java.util.Map; |
33 | import java.util.Optional; | 33 | import java.util.Optional; |
34 | import java.util.UUID; | 34 | import java.util.UUID; |
35 | +import java.util.stream.Collectors; | ||
35 | 36 | ||
36 | public abstract class DaoUtil { | 37 | public abstract class DaoUtil { |
37 | 38 | ||
@@ -55,6 +56,14 @@ public abstract class DaoUtil { | @@ -55,6 +56,14 @@ public abstract class DaoUtil { | ||
55 | return PageRequest.of(pageLink.getPage(), pageLink.getPageSize(), toSort(pageLink.getSortOrder(), columnMap)); | 56 | return PageRequest.of(pageLink.getPage(), pageLink.getPageSize(), toSort(pageLink.getSortOrder(), columnMap)); |
56 | } | 57 | } |
57 | 58 | ||
59 | + public static Pageable toPageable(PageLink pageLink, List<SortOrder> sortOrders) { | ||
60 | + return toPageable(pageLink, Collections.emptyMap(), sortOrders); | ||
61 | + } | ||
62 | + | ||
63 | + public static Pageable toPageable(PageLink pageLink, Map<String,String> columnMap, List<SortOrder> sortOrders) { | ||
64 | + return PageRequest.of(pageLink.getPage(), pageLink.getPageSize(), toSort(sortOrders, columnMap)); | ||
65 | + } | ||
66 | + | ||
58 | public static Sort toSort(SortOrder sortOrder) { | 67 | public static Sort toSort(SortOrder sortOrder) { |
59 | return toSort(sortOrder, Collections.emptyMap()); | 68 | return toSort(sortOrder, Collections.emptyMap()); |
60 | } | 69 | } |
@@ -71,6 +80,26 @@ public abstract class DaoUtil { | @@ -71,6 +80,26 @@ public abstract class DaoUtil { | ||
71 | } | 80 | } |
72 | } | 81 | } |
73 | 82 | ||
83 | + public static Sort toSort(List<SortOrder> sortOrders) { | ||
84 | + return toSort(sortOrders, Collections.emptyMap()); | ||
85 | + } | ||
86 | + | ||
87 | + public static Sort toSort(List<SortOrder> sortOrders, Map<String,String> columnMap) { | ||
88 | + return toSort(sortOrders, columnMap, Sort.NullHandling.NULLS_LAST); | ||
89 | + } | ||
90 | + | ||
91 | + public static Sort toSort(List<SortOrder> sortOrders, Map<String,String> columnMap, Sort.NullHandling nullHandlingHint) { | ||
92 | + return Sort.by(sortOrders.stream().map(s -> toSortOrder(s, columnMap, nullHandlingHint)).collect(Collectors.toList())); | ||
93 | + } | ||
94 | + | ||
95 | + public static Sort.Order toSortOrder(SortOrder sortOrder, Map<String,String> columnMap, Sort.NullHandling nullHandlingHint) { | ||
96 | + String property = sortOrder.getProperty(); | ||
97 | + if (columnMap.containsKey(property)) { | ||
98 | + property = columnMap.get(property); | ||
99 | + } | ||
100 | + return new Sort.Order(Sort.Direction.fromString(sortOrder.getDirection().name()), property, nullHandlingHint); | ||
101 | + } | ||
102 | + | ||
74 | public static <T> List<T> convertDataList(Collection<? extends ToData<T>> toDataList) { | 103 | public static <T> List<T> convertDataList(Collection<? extends ToData<T>> toDataList) { |
75 | List<T> list = Collections.emptyList(); | 104 | List<T> list = Collections.emptyList(); |
76 | if (toDataList != null && !toDataList.isEmpty()) { | 105 | if (toDataList != null && !toDataList.isEmpty()) { |
@@ -37,6 +37,15 @@ public interface DashboardInfoDao extends Dao<DashboardInfo> { | @@ -37,6 +37,15 @@ public interface DashboardInfoDao extends Dao<DashboardInfo> { | ||
37 | PageData<DashboardInfo> findDashboardsByTenantId(UUID tenantId, PageLink pageLink); | 37 | PageData<DashboardInfo> findDashboardsByTenantId(UUID tenantId, PageLink pageLink); |
38 | 38 | ||
39 | /** | 39 | /** |
40 | + * Find dashboards not hidden for mobile by tenantId and page link. | ||
41 | + * | ||
42 | + * @param tenantId the tenantId | ||
43 | + * @param pageLink the page link | ||
44 | + * @return the list of dashboard objects | ||
45 | + */ | ||
46 | + PageData<DashboardInfo> findMobileDashboardsByTenantId(UUID tenantId, PageLink pageLink); | ||
47 | + | ||
48 | + /** | ||
40 | * Find dashboards by tenantId, customerId and page link. | 49 | * Find dashboards by tenantId, customerId and page link. |
41 | * | 50 | * |
42 | * @param tenantId the tenantId | 51 | * @param tenantId the tenantId |
@@ -47,6 +56,16 @@ public interface DashboardInfoDao extends Dao<DashboardInfo> { | @@ -47,6 +56,16 @@ public interface DashboardInfoDao extends Dao<DashboardInfo> { | ||
47 | PageData<DashboardInfo> findDashboardsByTenantIdAndCustomerId(UUID tenantId, UUID customerId, PageLink pageLink); | 56 | PageData<DashboardInfo> findDashboardsByTenantIdAndCustomerId(UUID tenantId, UUID customerId, PageLink pageLink); |
48 | 57 | ||
49 | /** | 58 | /** |
59 | + * Find dashboards not hidden for mobile by tenantId, customerId and page link. | ||
60 | + * | ||
61 | + * @param tenantId the tenantId | ||
62 | + * @param customerId the customerId | ||
63 | + * @param pageLink the page link | ||
64 | + * @return the list of dashboard objects | ||
65 | + */ | ||
66 | + PageData<DashboardInfo> findMobileDashboardsByTenantIdAndCustomerId(UUID tenantId, UUID customerId, PageLink pageLink); | ||
67 | + | ||
68 | + /** | ||
50 | * Find dashboards by tenantId, edgeId and page link. | 69 | * Find dashboards by tenantId, edgeId and page link. |
51 | * | 70 | * |
52 | * @param tenantId the tenantId | 71 | * @param tenantId the tenantId |
@@ -187,6 +187,14 @@ public class DashboardServiceImpl extends AbstractEntityService implements Dashb | @@ -187,6 +187,14 @@ public class DashboardServiceImpl extends AbstractEntityService implements Dashb | ||
187 | } | 187 | } |
188 | 188 | ||
189 | @Override | 189 | @Override |
190 | + public PageData<DashboardInfo> findMobileDashboardsByTenantId(TenantId tenantId, PageLink pageLink) { | ||
191 | + log.trace("Executing findMobileDashboardsByTenantId, tenantId [{}], pageLink [{}]", tenantId, pageLink); | ||
192 | + Validator.validateId(tenantId, INCORRECT_TENANT_ID + tenantId); | ||
193 | + Validator.validatePageLink(pageLink); | ||
194 | + return dashboardInfoDao.findMobileDashboardsByTenantId(tenantId.getId(), pageLink); | ||
195 | + } | ||
196 | + | ||
197 | + @Override | ||
190 | public void deleteDashboardsByTenantId(TenantId tenantId) { | 198 | public void deleteDashboardsByTenantId(TenantId tenantId) { |
191 | log.trace("Executing deleteDashboardsByTenantId, tenantId [{}]", tenantId); | 199 | log.trace("Executing deleteDashboardsByTenantId, tenantId [{}]", tenantId); |
192 | Validator.validateId(tenantId, INCORRECT_TENANT_ID + tenantId); | 200 | Validator.validateId(tenantId, INCORRECT_TENANT_ID + tenantId); |
@@ -203,6 +211,15 @@ public class DashboardServiceImpl extends AbstractEntityService implements Dashb | @@ -203,6 +211,15 @@ public class DashboardServiceImpl extends AbstractEntityService implements Dashb | ||
203 | } | 211 | } |
204 | 212 | ||
205 | @Override | 213 | @Override |
214 | + public PageData<DashboardInfo> findMobileDashboardsByTenantIdAndCustomerId(TenantId tenantId, CustomerId customerId, PageLink pageLink) { | ||
215 | + log.trace("Executing findMobileDashboardsByTenantIdAndCustomerId, tenantId [{}], customerId [{}], pageLink [{}]", tenantId, customerId, pageLink); | ||
216 | + Validator.validateId(tenantId, INCORRECT_TENANT_ID + tenantId); | ||
217 | + Validator.validateId(customerId, "Incorrect customerId " + customerId); | ||
218 | + Validator.validatePageLink(pageLink); | ||
219 | + return dashboardInfoDao.findMobileDashboardsByTenantIdAndCustomerId(tenantId.getId(), customerId.getId(), pageLink); | ||
220 | + } | ||
221 | + | ||
222 | + @Override | ||
206 | public void unassignCustomerDashboards(TenantId tenantId, CustomerId customerId) { | 223 | public void unassignCustomerDashboards(TenantId tenantId, CustomerId customerId) { |
207 | log.trace("Executing unassignCustomerDashboards, customerId [{}]", customerId); | 224 | log.trace("Executing unassignCustomerDashboards, customerId [{}]", customerId); |
208 | Validator.validateId(customerId, "Incorrect customerId " + customerId); | 225 | Validator.validateId(customerId, "Incorrect customerId " + customerId); |
@@ -339,6 +339,8 @@ public class ModelConstants { | @@ -339,6 +339,8 @@ public class ModelConstants { | ||
339 | public static final String DASHBOARD_IMAGE_PROPERTY = "image"; | 339 | public static final String DASHBOARD_IMAGE_PROPERTY = "image"; |
340 | public static final String DASHBOARD_CONFIGURATION_PROPERTY = "configuration"; | 340 | public static final String DASHBOARD_CONFIGURATION_PROPERTY = "configuration"; |
341 | public static final String DASHBOARD_ASSIGNED_CUSTOMERS_PROPERTY = "assigned_customers"; | 341 | public static final String DASHBOARD_ASSIGNED_CUSTOMERS_PROPERTY = "assigned_customers"; |
342 | + public static final String DASHBOARD_MOBILE_HIDE_PROPERTY = "mobile_hide"; | ||
343 | + public static final String DASHBOARD_MOBILE_ORDER_PROPERTY = "mobile_order"; | ||
342 | 344 | ||
343 | public static final String DASHBOARD_BY_TENANT_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME = "dashboard_by_tenant_and_search_text"; | 345 | public static final String DASHBOARD_BY_TENANT_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME = "dashboard_by_tenant_and_search_text"; |
344 | 346 |
@@ -68,6 +68,12 @@ public final class DashboardEntity extends BaseSqlEntity<Dashboard> implements S | @@ -68,6 +68,12 @@ public final class DashboardEntity extends BaseSqlEntity<Dashboard> implements S | ||
68 | @Column(name = ModelConstants.DASHBOARD_ASSIGNED_CUSTOMERS_PROPERTY) | 68 | @Column(name = ModelConstants.DASHBOARD_ASSIGNED_CUSTOMERS_PROPERTY) |
69 | private String assignedCustomers; | 69 | private String assignedCustomers; |
70 | 70 | ||
71 | + @Column(name = ModelConstants.DASHBOARD_MOBILE_HIDE_PROPERTY) | ||
72 | + private boolean mobileHide; | ||
73 | + | ||
74 | + @Column(name = ModelConstants.DASHBOARD_MOBILE_ORDER_PROPERTY) | ||
75 | + private Integer mobileOrder; | ||
76 | + | ||
71 | @Type(type = "json") | 77 | @Type(type = "json") |
72 | @Column(name = ModelConstants.DASHBOARD_CONFIGURATION_PROPERTY) | 78 | @Column(name = ModelConstants.DASHBOARD_CONFIGURATION_PROPERTY) |
73 | private JsonNode configuration; | 79 | private JsonNode configuration; |
@@ -93,6 +99,8 @@ public final class DashboardEntity extends BaseSqlEntity<Dashboard> implements S | @@ -93,6 +99,8 @@ public final class DashboardEntity extends BaseSqlEntity<Dashboard> implements S | ||
93 | log.error("Unable to serialize assigned customers to string!", e); | 99 | log.error("Unable to serialize assigned customers to string!", e); |
94 | } | 100 | } |
95 | } | 101 | } |
102 | + this.mobileHide = dashboard.isMobileHide(); | ||
103 | + this.mobileOrder = dashboard.getMobileOrder(); | ||
96 | this.configuration = dashboard.getConfiguration(); | 104 | this.configuration = dashboard.getConfiguration(); |
97 | } | 105 | } |
98 | 106 | ||
@@ -122,6 +130,8 @@ public final class DashboardEntity extends BaseSqlEntity<Dashboard> implements S | @@ -122,6 +130,8 @@ public final class DashboardEntity extends BaseSqlEntity<Dashboard> implements S | ||
122 | log.warn("Unable to parse assigned customers!", e); | 130 | log.warn("Unable to parse assigned customers!", e); |
123 | } | 131 | } |
124 | } | 132 | } |
133 | + dashboard.setMobileHide(mobileHide); | ||
134 | + dashboard.setMobileOrder(mobileOrder); | ||
125 | dashboard.setConfiguration(configuration); | 135 | dashboard.setConfiguration(configuration); |
126 | return dashboard; | 136 | return dashboard; |
127 | } | 137 | } |
@@ -63,6 +63,12 @@ public class DashboardInfoEntity extends BaseSqlEntity<DashboardInfo> implements | @@ -63,6 +63,12 @@ public class DashboardInfoEntity extends BaseSqlEntity<DashboardInfo> implements | ||
63 | @Column(name = ModelConstants.DASHBOARD_ASSIGNED_CUSTOMERS_PROPERTY) | 63 | @Column(name = ModelConstants.DASHBOARD_ASSIGNED_CUSTOMERS_PROPERTY) |
64 | private String assignedCustomers; | 64 | private String assignedCustomers; |
65 | 65 | ||
66 | + @Column(name = ModelConstants.DASHBOARD_MOBILE_HIDE_PROPERTY) | ||
67 | + private boolean mobileHide; | ||
68 | + | ||
69 | + @Column(name = ModelConstants.DASHBOARD_MOBILE_ORDER_PROPERTY) | ||
70 | + private Integer mobileOrder; | ||
71 | + | ||
66 | public DashboardInfoEntity() { | 72 | public DashboardInfoEntity() { |
67 | super(); | 73 | super(); |
68 | } | 74 | } |
@@ -84,6 +90,8 @@ public class DashboardInfoEntity extends BaseSqlEntity<DashboardInfo> implements | @@ -84,6 +90,8 @@ public class DashboardInfoEntity extends BaseSqlEntity<DashboardInfo> implements | ||
84 | log.error("Unable to serialize assigned customers to string!", e); | 90 | log.error("Unable to serialize assigned customers to string!", e); |
85 | } | 91 | } |
86 | } | 92 | } |
93 | + this.mobileHide = dashboardInfo.isMobileHide(); | ||
94 | + this.mobileOrder = dashboardInfo.getMobileOrder(); | ||
87 | } | 95 | } |
88 | 96 | ||
89 | @Override | 97 | @Override |
@@ -116,6 +124,8 @@ public class DashboardInfoEntity extends BaseSqlEntity<DashboardInfo> implements | @@ -116,6 +124,8 @@ public class DashboardInfoEntity extends BaseSqlEntity<DashboardInfo> implements | ||
116 | log.warn("Unable to parse assigned customers!", e); | 124 | log.warn("Unable to parse assigned customers!", e); |
117 | } | 125 | } |
118 | } | 126 | } |
127 | + dashboardInfo.setMobileHide(mobileHide); | ||
128 | + dashboardInfo.setMobileOrder(mobileOrder); | ||
119 | return dashboardInfo; | 129 | return dashboardInfo; |
120 | } | 130 | } |
121 | 131 |
@@ -37,6 +37,13 @@ public interface DashboardInfoRepository extends PagingAndSortingRepository<Dash | @@ -37,6 +37,13 @@ public interface DashboardInfoRepository extends PagingAndSortingRepository<Dash | ||
37 | @Param("searchText") String searchText, | 37 | @Param("searchText") String searchText, |
38 | Pageable pageable); | 38 | Pageable pageable); |
39 | 39 | ||
40 | + @Query("SELECT di FROM DashboardInfoEntity di WHERE di.tenantId = :tenantId " + | ||
41 | + "AND di.mobileHide = false " + | ||
42 | + "AND LOWER(di.searchText) LIKE LOWER(CONCAT(:searchText, '%'))") | ||
43 | + Page<DashboardInfoEntity> findMobileByTenantId(@Param("tenantId") UUID tenantId, | ||
44 | + @Param("searchText") String searchText, | ||
45 | + Pageable pageable); | ||
46 | + | ||
40 | @Query("SELECT di FROM DashboardInfoEntity di, RelationEntity re WHERE di.tenantId = :tenantId " + | 47 | @Query("SELECT di FROM DashboardInfoEntity di, RelationEntity re WHERE di.tenantId = :tenantId " + |
41 | "AND di.id = re.toId AND re.toType = 'DASHBOARD' AND re.relationTypeGroup = 'DASHBOARD' " + | 48 | "AND di.id = re.toId AND re.toType = 'DASHBOARD' AND re.relationTypeGroup = 'DASHBOARD' " + |
42 | "AND re.relationType = 'Contains' AND re.fromId = :customerId AND re.fromType = 'CUSTOMER' " + | 49 | "AND re.relationType = 'Contains' AND re.fromId = :customerId AND re.fromType = 'CUSTOMER' " + |
@@ -47,6 +54,16 @@ public interface DashboardInfoRepository extends PagingAndSortingRepository<Dash | @@ -47,6 +54,16 @@ public interface DashboardInfoRepository extends PagingAndSortingRepository<Dash | ||
47 | Pageable pageable); | 54 | Pageable pageable); |
48 | 55 | ||
49 | @Query("SELECT di FROM DashboardInfoEntity di, RelationEntity re WHERE di.tenantId = :tenantId " + | 56 | @Query("SELECT di FROM DashboardInfoEntity di, RelationEntity re WHERE di.tenantId = :tenantId " + |
57 | + "AND di.mobileHide = false " + | ||
58 | + "AND di.id = re.toId AND re.toType = 'DASHBOARD' AND re.relationTypeGroup = 'DASHBOARD' " + | ||
59 | + "AND re.relationType = 'Contains' AND re.fromId = :customerId AND re.fromType = 'CUSTOMER' " + | ||
60 | + "AND LOWER(di.searchText) LIKE LOWER(CONCAT(:searchText, '%'))") | ||
61 | + Page<DashboardInfoEntity> findMobileByTenantIdAndCustomerId(@Param("tenantId") UUID tenantId, | ||
62 | + @Param("customerId") UUID customerId, | ||
63 | + @Param("searchText") String searchText, | ||
64 | + Pageable pageable); | ||
65 | + | ||
66 | + @Query("SELECT di FROM DashboardInfoEntity di, RelationEntity re WHERE di.tenantId = :tenantId " + | ||
50 | "AND di.id = re.toId AND re.toType = 'DASHBOARD' AND re.relationTypeGroup = 'EDGE' " + | 67 | "AND di.id = re.toId AND re.toType = 'DASHBOARD' AND re.relationTypeGroup = 'EDGE' " + |
51 | "AND re.relationType = 'Contains' AND re.fromId = :edgeId AND re.fromType = 'EDGE' " + | 68 | "AND re.relationType = 'Contains' AND re.fromId = :edgeId AND re.fromType = 'EDGE' " + |
52 | "AND LOWER(di.searchText) LIKE LOWER(CONCAT(:searchText, '%'))") | 69 | "AND LOWER(di.searchText) LIKE LOWER(CONCAT(:searchText, '%'))") |
@@ -22,12 +22,15 @@ import org.springframework.stereotype.Component; | @@ -22,12 +22,15 @@ import org.springframework.stereotype.Component; | ||
22 | import org.thingsboard.server.common.data.DashboardInfo; | 22 | import org.thingsboard.server.common.data.DashboardInfo; |
23 | import org.thingsboard.server.common.data.page.PageData; | 23 | import org.thingsboard.server.common.data.page.PageData; |
24 | import org.thingsboard.server.common.data.page.PageLink; | 24 | import org.thingsboard.server.common.data.page.PageLink; |
25 | +import org.thingsboard.server.common.data.page.SortOrder; | ||
25 | import org.thingsboard.server.dao.DaoUtil; | 26 | import org.thingsboard.server.dao.DaoUtil; |
26 | import org.thingsboard.server.dao.dashboard.DashboardInfoDao; | 27 | import org.thingsboard.server.dao.dashboard.DashboardInfoDao; |
27 | import org.thingsboard.server.dao.model.sql.DashboardInfoEntity; | 28 | import org.thingsboard.server.dao.model.sql.DashboardInfoEntity; |
28 | import org.thingsboard.server.dao.relation.RelationDao; | 29 | import org.thingsboard.server.dao.relation.RelationDao; |
29 | import org.thingsboard.server.dao.sql.JpaAbstractSearchTextDao; | 30 | import org.thingsboard.server.dao.sql.JpaAbstractSearchTextDao; |
30 | 31 | ||
32 | +import java.util.ArrayList; | ||
33 | +import java.util.List; | ||
31 | import java.util.Objects; | 34 | import java.util.Objects; |
32 | import java.util.UUID; | 35 | import java.util.UUID; |
33 | 36 | ||
@@ -41,9 +44,6 @@ public class JpaDashboardInfoDao extends JpaAbstractSearchTextDao<DashboardInfoE | @@ -41,9 +44,6 @@ public class JpaDashboardInfoDao extends JpaAbstractSearchTextDao<DashboardInfoE | ||
41 | @Autowired | 44 | @Autowired |
42 | private DashboardInfoRepository dashboardInfoRepository; | 45 | private DashboardInfoRepository dashboardInfoRepository; |
43 | 46 | ||
44 | - @Autowired | ||
45 | - private RelationDao relationDao; | ||
46 | - | ||
47 | @Override | 47 | @Override |
48 | protected Class<DashboardInfoEntity> getEntityClass() { | 48 | protected Class<DashboardInfoEntity> getEntityClass() { |
49 | return DashboardInfoEntity.class; | 49 | return DashboardInfoEntity.class; |
@@ -64,6 +64,20 @@ public class JpaDashboardInfoDao extends JpaAbstractSearchTextDao<DashboardInfoE | @@ -64,6 +64,20 @@ public class JpaDashboardInfoDao extends JpaAbstractSearchTextDao<DashboardInfoE | ||
64 | } | 64 | } |
65 | 65 | ||
66 | @Override | 66 | @Override |
67 | + public PageData<DashboardInfo> findMobileDashboardsByTenantId(UUID tenantId, PageLink pageLink) { | ||
68 | + List<SortOrder> sortOrders = new ArrayList<>(); | ||
69 | + sortOrders.add(new SortOrder("mobileOrder", SortOrder.Direction.ASC)); | ||
70 | + if (pageLink.getSortOrder() != null) { | ||
71 | + sortOrders.add(pageLink.getSortOrder()); | ||
72 | + } | ||
73 | + return DaoUtil.toPageData(dashboardInfoRepository | ||
74 | + .findMobileByTenantId( | ||
75 | + tenantId, | ||
76 | + Objects.toString(pageLink.getTextSearch(), ""), | ||
77 | + DaoUtil.toPageable(pageLink, sortOrders))); | ||
78 | + } | ||
79 | + | ||
80 | + @Override | ||
67 | public PageData<DashboardInfo> findDashboardsByTenantIdAndCustomerId(UUID tenantId, UUID customerId, PageLink pageLink) { | 81 | public PageData<DashboardInfo> findDashboardsByTenantIdAndCustomerId(UUID tenantId, UUID customerId, PageLink pageLink) { |
68 | return DaoUtil.toPageData(dashboardInfoRepository | 82 | return DaoUtil.toPageData(dashboardInfoRepository |
69 | .findByTenantIdAndCustomerId( | 83 | .findByTenantIdAndCustomerId( |
@@ -74,6 +88,21 @@ public class JpaDashboardInfoDao extends JpaAbstractSearchTextDao<DashboardInfoE | @@ -74,6 +88,21 @@ public class JpaDashboardInfoDao extends JpaAbstractSearchTextDao<DashboardInfoE | ||
74 | } | 88 | } |
75 | 89 | ||
76 | @Override | 90 | @Override |
91 | + public PageData<DashboardInfo> findMobileDashboardsByTenantIdAndCustomerId(UUID tenantId, UUID customerId, PageLink pageLink) { | ||
92 | + List<SortOrder> sortOrders = new ArrayList<>(); | ||
93 | + sortOrders.add(new SortOrder("mobileOrder", SortOrder.Direction.ASC)); | ||
94 | + if (pageLink.getSortOrder() != null) { | ||
95 | + sortOrders.add(pageLink.getSortOrder()); | ||
96 | + } | ||
97 | + return DaoUtil.toPageData(dashboardInfoRepository | ||
98 | + .findMobileByTenantIdAndCustomerId( | ||
99 | + tenantId, | ||
100 | + customerId, | ||
101 | + Objects.toString(pageLink.getTextSearch(), ""), | ||
102 | + DaoUtil.toPageable(pageLink, sortOrders))); | ||
103 | + } | ||
104 | + | ||
105 | + @Override | ||
77 | public PageData<DashboardInfo> findDashboardsByTenantIdAndEdgeId(UUID tenantId, UUID edgeId, PageLink pageLink) { | 106 | public PageData<DashboardInfo> findDashboardsByTenantIdAndEdgeId(UUID tenantId, UUID edgeId, PageLink pageLink) { |
78 | log.debug("Try to find dashboards by tenantId [{}], edgeId [{}] and pageLink [{}]", tenantId, edgeId, pageLink); | 107 | log.debug("Try to find dashboards by tenantId [{}], edgeId [{}] and pageLink [{}]", tenantId, edgeId, pageLink); |
79 | return DaoUtil.toPageData(dashboardInfoRepository | 108 | return DaoUtil.toPageData(dashboardInfoRepository |
@@ -123,6 +123,8 @@ CREATE TABLE IF NOT EXISTS dashboard ( | @@ -123,6 +123,8 @@ CREATE TABLE IF NOT EXISTS dashboard ( | ||
123 | search_text varchar(255), | 123 | search_text varchar(255), |
124 | tenant_id uuid, | 124 | tenant_id uuid, |
125 | title varchar(255), | 125 | title varchar(255), |
126 | + mobile_hide boolean DEFAULT false, | ||
127 | + mobile_order int, | ||
126 | image varchar(1000000) | 128 | image varchar(1000000) |
127 | ); | 129 | ); |
128 | 130 |
@@ -138,6 +138,8 @@ CREATE TABLE IF NOT EXISTS dashboard ( | @@ -138,6 +138,8 @@ CREATE TABLE IF NOT EXISTS dashboard ( | ||
138 | search_text varchar(255), | 138 | search_text varchar(255), |
139 | tenant_id uuid, | 139 | tenant_id uuid, |
140 | title varchar(255), | 140 | title varchar(255), |
141 | + mobile_hide boolean DEFAULT false, | ||
142 | + mobile_order int, | ||
141 | image varchar(1000000) | 143 | image varchar(1000000) |
142 | ); | 144 | ); |
143 | 145 |
@@ -31,12 +31,14 @@ import org.thingsboard.server.common.data.id.EdgeId; | @@ -31,12 +31,14 @@ import org.thingsboard.server.common.data.id.EdgeId; | ||
31 | import org.thingsboard.server.common.data.id.TenantId; | 31 | import org.thingsboard.server.common.data.id.TenantId; |
32 | import org.thingsboard.server.common.data.page.PageData; | 32 | import org.thingsboard.server.common.data.page.PageData; |
33 | import org.thingsboard.server.common.data.page.PageLink; | 33 | import org.thingsboard.server.common.data.page.PageLink; |
34 | +import org.thingsboard.server.common.data.page.SortOrder; | ||
34 | import org.thingsboard.server.common.data.page.TimePageLink; | 35 | import org.thingsboard.server.common.data.page.TimePageLink; |
35 | import org.thingsboard.server.dao.exception.DataValidationException; | 36 | import org.thingsboard.server.dao.exception.DataValidationException; |
36 | 37 | ||
37 | import java.io.IOException; | 38 | import java.io.IOException; |
38 | import java.util.ArrayList; | 39 | import java.util.ArrayList; |
39 | import java.util.Collections; | 40 | import java.util.Collections; |
41 | +import java.util.Comparator; | ||
40 | import java.util.List; | 42 | import java.util.List; |
41 | import java.util.concurrent.ExecutionException; | 43 | import java.util.concurrent.ExecutionException; |
42 | 44 | ||
@@ -204,6 +206,66 @@ public abstract class BaseDashboardServiceTest extends AbstractServiceTest { | @@ -204,6 +206,66 @@ public abstract class BaseDashboardServiceTest extends AbstractServiceTest { | ||
204 | 206 | ||
205 | tenantService.deleteTenant(tenantId); | 207 | tenantService.deleteTenant(tenantId); |
206 | } | 208 | } |
209 | + | ||
210 | + @Test | ||
211 | + public void testFindMobileDashboardsByTenantId() { | ||
212 | + Tenant tenant = new Tenant(); | ||
213 | + tenant.setTitle("Test tenant"); | ||
214 | + tenant = tenantService.saveTenant(tenant); | ||
215 | + | ||
216 | + TenantId tenantId = tenant.getId(); | ||
217 | + | ||
218 | + List<DashboardInfo> mobileDashboards = new ArrayList<>(); | ||
219 | + for (int i=0;i<165;i++) { | ||
220 | + Dashboard dashboard = new Dashboard(); | ||
221 | + dashboard.setTenantId(tenantId); | ||
222 | + dashboard.setTitle("Dashboard"+i); | ||
223 | + dashboard.setMobileHide(i % 2 == 0); | ||
224 | + if (!dashboard.isMobileHide()) { | ||
225 | + dashboard.setMobileOrder(i % 4 == 0 ? (int)(Math.random() * 100) : null); | ||
226 | + } | ||
227 | + Dashboard savedDashboard = dashboardService.saveDashboard(dashboard); | ||
228 | + if (!dashboard.isMobileHide()) { | ||
229 | + mobileDashboards.add(new DashboardInfo(savedDashboard)); | ||
230 | + } | ||
231 | + } | ||
232 | + | ||
233 | + List<DashboardInfo> loadedMobileDashboards = new ArrayList<>(); | ||
234 | + PageLink pageLink = new PageLink(16, 0, null, new SortOrder("createdTime", SortOrder.Direction.ASC)); | ||
235 | + PageData<DashboardInfo> pageData = null; | ||
236 | + do { | ||
237 | + pageData = dashboardService.findMobileDashboardsByTenantId(tenantId, pageLink); | ||
238 | + loadedMobileDashboards.addAll(pageData.getData()); | ||
239 | + if (pageData.hasNext()) { | ||
240 | + pageLink = pageLink.nextPageLink(); | ||
241 | + } | ||
242 | + } while (pageData.hasNext()); | ||
243 | + | ||
244 | + Collections.sort(mobileDashboards, (o1, o2) -> { | ||
245 | + Integer order1 = o1.getMobileOrder(); | ||
246 | + Integer order2 = o2.getMobileOrder(); | ||
247 | + if (order1 == null && order2 == null) { | ||
248 | + return o1.getId().getId().compareTo(o2.getId().getId()); | ||
249 | + } else if (order1 == null && order2 != null) { | ||
250 | + return 1; | ||
251 | + } else if (order2 == null) { | ||
252 | + return -1; | ||
253 | + } else { | ||
254 | + return order1 - order2; | ||
255 | + } | ||
256 | + }); | ||
257 | + | ||
258 | + Assert.assertEquals(mobileDashboards, loadedMobileDashboards); | ||
259 | + | ||
260 | + dashboardService.deleteDashboardsByTenantId(tenantId); | ||
261 | + | ||
262 | + pageLink = new PageLink(31); | ||
263 | + pageData = dashboardService.findMobileDashboardsByTenantId(tenantId, pageLink); | ||
264 | + Assert.assertFalse(pageData.hasNext()); | ||
265 | + Assert.assertTrue(pageData.getData().isEmpty()); | ||
266 | + | ||
267 | + tenantService.deleteTenant(tenantId); | ||
268 | + } | ||
207 | 269 | ||
208 | @Test | 270 | @Test |
209 | public void testFindDashboardsByTenantIdAndTitle() { | 271 | public void testFindDashboardsByTenantIdAndTitle() { |
@@ -389,7 +389,8 @@ export class DashboardUtilsService { | @@ -389,7 +389,8 @@ export class DashboardUtilsService { | ||
389 | sizeX: originalSize ? originalSize.sizeX : widget.sizeX, | 389 | sizeX: originalSize ? originalSize.sizeX : widget.sizeX, |
390 | sizeY: originalSize ? originalSize.sizeY : widget.sizeY, | 390 | sizeY: originalSize ? originalSize.sizeY : widget.sizeY, |
391 | mobileOrder: widget.config.mobileOrder, | 391 | mobileOrder: widget.config.mobileOrder, |
392 | - mobileHeight: widget.config.mobileHeight | 392 | + mobileHeight: widget.config.mobileHeight, |
393 | + mobileHide: widget.config.mobileHide | ||
393 | }; | 394 | }; |
394 | if (isUndefined(originalColumns)) { | 395 | if (isUndefined(originalColumns)) { |
395 | originalColumns = 24; | 396 | originalColumns = 24; |
@@ -127,6 +127,7 @@ export class AddWidgetDialogComponent extends DialogComponent<AddWidgetDialogCom | @@ -127,6 +127,7 @@ export class AddWidgetDialogComponent extends DialogComponent<AddWidgetDialogCom | ||
127 | this.widget.config = widgetConfig.config; | 127 | this.widget.config = widgetConfig.config; |
128 | this.widget.config.mobileOrder = widgetConfig.layout.mobileOrder; | 128 | this.widget.config.mobileOrder = widgetConfig.layout.mobileOrder; |
129 | this.widget.config.mobileHeight = widgetConfig.layout.mobileHeight; | 129 | this.widget.config.mobileHeight = widgetConfig.layout.mobileHeight; |
130 | + this.widget.config.mobileHide = widgetConfig.layout.mobileHide; | ||
130 | this.dialogRef.close(this.widget); | 131 | this.dialogRef.close(this.widget); |
131 | } | 132 | } |
132 | } | 133 | } |
@@ -23,7 +23,7 @@ import { StateControllerComponent } from './state-controller.component'; | @@ -23,7 +23,7 @@ import { StateControllerComponent } from './state-controller.component'; | ||
23 | import { StatesControllerService } from '@home/components/dashboard-page/states/states-controller.service'; | 23 | import { StatesControllerService } from '@home/components/dashboard-page/states/states-controller.service'; |
24 | import { EntityId } from '@app/shared/models/id/entity-id'; | 24 | import { EntityId } from '@app/shared/models/id/entity-id'; |
25 | import { UtilsService } from '@core/services/utils.service'; | 25 | import { UtilsService } from '@core/services/utils.service'; |
26 | -import { base64toObj, objToBase64URI } from '@app/core/utils'; | 26 | +import { base64toObj, objToBase64 } from '@app/core/utils'; |
27 | import { DashboardUtilsService } from '@core/services/dashboard-utils.service'; | 27 | import { DashboardUtilsService } from '@core/services/dashboard-utils.service'; |
28 | import { EntityService } from '@core/http/entity.service'; | 28 | import { EntityService } from '@core/http/entity.service'; |
29 | import { MobileService } from '@core/services/mobile.service'; | 29 | import { MobileService } from '@core/services/mobile.service'; |
@@ -246,7 +246,7 @@ export class DefaultStateControllerComponent extends StateControllerComponent im | @@ -246,7 +246,7 @@ export class DefaultStateControllerComponent extends StateControllerComponent im | ||
246 | 246 | ||
247 | private updateLocation() { | 247 | private updateLocation() { |
248 | if (this.stateObject[0].id) { | 248 | if (this.stateObject[0].id) { |
249 | - const newState = objToBase64URI(this.stateObject); | 249 | + const newState = objToBase64(this.stateObject); |
250 | this.updateStateParam(newState); | 250 | this.updateStateParam(newState); |
251 | } | 251 | } |
252 | } | 252 | } |
@@ -23,7 +23,7 @@ import { StateControllerComponent } from './state-controller.component'; | @@ -23,7 +23,7 @@ import { StateControllerComponent } from './state-controller.component'; | ||
23 | import { StatesControllerService } from '@home/components/dashboard-page/states/states-controller.service'; | 23 | import { StatesControllerService } from '@home/components/dashboard-page/states/states-controller.service'; |
24 | import { EntityId } from '@app/shared/models/id/entity-id'; | 24 | import { EntityId } from '@app/shared/models/id/entity-id'; |
25 | import { UtilsService } from '@core/services/utils.service'; | 25 | import { UtilsService } from '@core/services/utils.service'; |
26 | -import { base64toObj, insertVariable, isEmpty, objToBase64URI } from '@app/core/utils'; | 26 | +import { base64toObj, insertVariable, isEmpty, objToBase64 } from '@app/core/utils'; |
27 | import { DashboardUtilsService } from '@core/services/dashboard-utils.service'; | 27 | import { DashboardUtilsService } from '@core/services/dashboard-utils.service'; |
28 | import { EntityService } from '@core/http/entity.service'; | 28 | import { EntityService } from '@core/http/entity.service'; |
29 | import { EntityType } from '@shared/models/entity-type.models'; | 29 | import { EntityType } from '@shared/models/entity-type.models'; |
@@ -289,7 +289,7 @@ export class EntityStateControllerComponent extends StateControllerComponent imp | @@ -289,7 +289,7 @@ export class EntityStateControllerComponent extends StateControllerComponent imp | ||
289 | if (this.isDefaultState()) { | 289 | if (this.isDefaultState()) { |
290 | newState = null; | 290 | newState = null; |
291 | } else { | 291 | } else { |
292 | - newState = objToBase64URI(this.stateObject); | 292 | + newState = objToBase64(this.stateObject); |
293 | } | 293 | } |
294 | this.updateStateParam(newState, !isStateIdChanged); | 294 | this.updateStateParam(newState, !isStateIdChanged); |
295 | } | 295 | } |
@@ -129,7 +129,7 @@ export abstract class StateControllerComponent implements IStateControllerCompon | @@ -129,7 +129,7 @@ export abstract class StateControllerComponent implements IStateControllerCompon | ||
129 | protected updateStateParam(newState: string, replaceCurrentHistoryUrl = false) { | 129 | protected updateStateParam(newState: string, replaceCurrentHistoryUrl = false) { |
130 | this.currentState = newState; | 130 | this.currentState = newState; |
131 | if (this.syncStateWithQueryParam) { | 131 | if (this.syncStateWithQueryParam) { |
132 | - const queryParams: Params = {state: this.currentState}; | 132 | + const queryParams: Params = {state: encodeURIComponent(this.currentState)}; |
133 | this.ngZone.run(() => { | 133 | this.ngZone.run(() => { |
134 | this.router.navigate( | 134 | this.router.navigate( |
135 | [], | 135 | [], |
@@ -418,6 +418,9 @@ | @@ -418,6 +418,9 @@ | ||
418 | <span translate>widget-config.mobile-mode-settings</span> | 418 | <span translate>widget-config.mobile-mode-settings</span> |
419 | <div fxLayout.xs="column" fxLayoutAlign.xs="center" fxLayout="row" fxLayoutAlign="start center" | 419 | <div fxLayout.xs="column" fxLayoutAlign.xs="center" fxLayout="row" fxLayoutAlign="start center" |
420 | fxLayoutGap="8px"> | 420 | fxLayoutGap="8px"> |
421 | + <mat-checkbox formControlName="mobileHide"> | ||
422 | + {{ 'widget-config.mobile-hide' | translate }} | ||
423 | + </mat-checkbox> | ||
421 | <mat-form-field fxFlex> | 424 | <mat-form-field fxFlex> |
422 | <mat-label translate>widget-config.order</mat-label> | 425 | <mat-label translate>widget-config.order</mat-label> |
423 | <input matInput formControlName="mobileOrder" type="number" step="1"> | 426 | <input matInput formControlName="mobileOrder" type="number" step="1"> |
@@ -228,7 +228,8 @@ export class WidgetConfigComponent extends PageComponent implements OnInit, Cont | @@ -228,7 +228,8 @@ export class WidgetConfigComponent extends PageComponent implements OnInit, Cont | ||
228 | }); | 228 | }); |
229 | this.layoutSettings = this.fb.group({ | 229 | this.layoutSettings = this.fb.group({ |
230 | mobileOrder: [null, [Validators.pattern(/^-?[0-9]+$/)]], | 230 | mobileOrder: [null, [Validators.pattern(/^-?[0-9]+$/)]], |
231 | - mobileHeight: [null, [Validators.min(1), Validators.max(10), Validators.pattern(/^\d*$/)]] | 231 | + mobileHeight: [null, [Validators.min(1), Validators.max(10), Validators.pattern(/^\d*$/)]], |
232 | + mobileHide: [false] | ||
232 | }); | 233 | }); |
233 | this.actionsSettings = this.fb.group({ | 234 | this.actionsSettings = this.fb.group({ |
234 | actionsData: [null, []] | 235 | actionsData: [null, []] |
@@ -502,7 +503,8 @@ export class WidgetConfigComponent extends PageComponent implements OnInit, Cont | @@ -502,7 +503,8 @@ export class WidgetConfigComponent extends PageComponent implements OnInit, Cont | ||
502 | this.layoutSettings.patchValue( | 503 | this.layoutSettings.patchValue( |
503 | { | 504 | { |
504 | mobileOrder: layout.mobileOrder, | 505 | mobileOrder: layout.mobileOrder, |
505 | - mobileHeight: layout.mobileHeight | 506 | + mobileHeight: layout.mobileHeight, |
507 | + mobileHide: layout.mobileHide | ||
506 | }, | 508 | }, |
507 | {emitEvent: false} | 509 | {emitEvent: false} |
508 | ); | 510 | ); |
@@ -510,7 +512,8 @@ export class WidgetConfigComponent extends PageComponent implements OnInit, Cont | @@ -510,7 +512,8 @@ export class WidgetConfigComponent extends PageComponent implements OnInit, Cont | ||
510 | this.layoutSettings.patchValue( | 512 | this.layoutSettings.patchValue( |
511 | { | 513 | { |
512 | mobileOrder: null, | 514 | mobileOrder: null, |
513 | - mobileHeight: null | 515 | + mobileHeight: null, |
516 | + mobileHide: false | ||
514 | }, | 517 | }, |
515 | {emitEvent: false} | 518 | {emitEvent: false} |
516 | ); | 519 | ); |
@@ -63,6 +63,7 @@ export interface IDashboardComponent { | @@ -63,6 +63,7 @@ export interface IDashboardComponent { | ||
63 | dashboardWidgets: DashboardWidgets; | 63 | dashboardWidgets: DashboardWidgets; |
64 | mobileAutofillHeight: boolean; | 64 | mobileAutofillHeight: boolean; |
65 | isMobileSize: boolean; | 65 | isMobileSize: boolean; |
66 | + isEdit: boolean; | ||
66 | autofillHeight: boolean; | 67 | autofillHeight: boolean; |
67 | dashboardTimewindow: Timewindow; | 68 | dashboardTimewindow: Timewindow; |
68 | dashboardTimewindowChanged: Observable<Timewindow>; | 69 | dashboardTimewindowChanged: Observable<Timewindow>; |
@@ -99,7 +100,14 @@ export class DashboardWidgets implements Iterable<DashboardWidget> { | @@ -99,7 +100,14 @@ export class DashboardWidgets implements Iterable<DashboardWidget> { | ||
99 | widgetLayouts: WidgetLayouts; | 100 | widgetLayouts: WidgetLayouts; |
100 | 101 | ||
101 | [Symbol.iterator](): Iterator<DashboardWidget> { | 102 | [Symbol.iterator](): Iterator<DashboardWidget> { |
102 | - return this.dashboardWidgets[Symbol.iterator](); | 103 | + return this.activeDashboardWidgets[Symbol.iterator](); |
104 | + } | ||
105 | + | ||
106 | + get activeDashboardWidgets(): Array<DashboardWidget> { | ||
107 | + if (this.dashboard.isMobileSize && !this.dashboard.isEdit) { | ||
108 | + return this.dashboardWidgets.filter(w => !w.mobileHide); | ||
109 | + } | ||
110 | + return this.dashboardWidgets; | ||
103 | } | 111 | } |
104 | 112 | ||
105 | constructor(private dashboard: IDashboardComponent, | 113 | constructor(private dashboard: IDashboardComponent, |
@@ -152,6 +160,7 @@ export class DashboardWidgets implements Iterable<DashboardWidget> { | @@ -152,6 +160,7 @@ export class DashboardWidgets implements Iterable<DashboardWidget> { | ||
152 | } | 160 | } |
153 | if (updateRecords.length) { | 161 | if (updateRecords.length) { |
154 | updateRecords.forEach((record) => { | 162 | updateRecords.forEach((record) => { |
163 | + let index; | ||
155 | switch (record.operation) { | 164 | switch (record.operation) { |
156 | case 'add': | 165 | case 'add': |
157 | this.dashboardWidgets.push( | 166 | this.dashboardWidgets.push( |
@@ -159,7 +168,7 @@ export class DashboardWidgets implements Iterable<DashboardWidget> { | @@ -159,7 +168,7 @@ export class DashboardWidgets implements Iterable<DashboardWidget> { | ||
159 | ); | 168 | ); |
160 | break; | 169 | break; |
161 | case 'remove': | 170 | case 'remove': |
162 | - let index = this.dashboardWidgets.findIndex((dashboardWidget) => dashboardWidget.widgetId === record.widgetId); | 171 | + index = this.dashboardWidgets.findIndex((dashboardWidget) => dashboardWidget.widgetId === record.widgetId); |
163 | if (index > -1) { | 172 | if (index > -1) { |
164 | this.dashboardWidgets.splice(index, 1); | 173 | this.dashboardWidgets.splice(index, 1); |
165 | } | 174 | } |
@@ -261,7 +270,7 @@ export class DashboardWidgets implements Iterable<DashboardWidget> { | @@ -261,7 +270,7 @@ export class DashboardWidgets implements Iterable<DashboardWidget> { | ||
261 | 270 | ||
262 | private updateRowsAndSort() { | 271 | private updateRowsAndSort() { |
263 | let maxRows = this.dashboard.gridsterOpts.maxRows; | 272 | let maxRows = this.dashboard.gridsterOpts.maxRows; |
264 | - this.dashboardWidgets.forEach((dashboardWidget) => { | 273 | + this.activeDashboardWidgets.forEach((dashboardWidget) => { |
265 | const bottom = dashboardWidget.y + dashboardWidget.rows; | 274 | const bottom = dashboardWidget.y + dashboardWidget.rows; |
266 | maxRows = Math.max(maxRows, bottom); | 275 | maxRows = Math.max(maxRows, bottom); |
267 | }); | 276 | }); |
@@ -328,6 +337,10 @@ export class DashboardWidget implements GridsterItem, IDashboardWidget { | @@ -328,6 +337,10 @@ export class DashboardWidget implements GridsterItem, IDashboardWidget { | ||
328 | private gridsterItemComponentSubject = new Subject<GridsterItemComponentInterface>(); | 337 | private gridsterItemComponentSubject = new Subject<GridsterItemComponentInterface>(); |
329 | private gridsterItemComponentValue: GridsterItemComponentInterface; | 338 | private gridsterItemComponentValue: GridsterItemComponentInterface; |
330 | 339 | ||
340 | + get mobileHide(): boolean { | ||
341 | + return this.widgetLayout ? this.widgetLayout.mobileHide === true : false; | ||
342 | + } | ||
343 | + | ||
331 | set gridsterItemComponent(item: GridsterItemComponentInterface) { | 344 | set gridsterItemComponent(item: GridsterItemComponentInterface) { |
332 | this.gridsterItemComponentValue = item; | 345 | this.gridsterItemComponentValue = item; |
333 | this.gridsterItemComponentSubject.next(this.gridsterItemComponentValue); | 346 | this.gridsterItemComponentSubject.next(this.gridsterItemComponentValue); |
@@ -423,7 +436,7 @@ export class DashboardWidget implements GridsterItem, IDashboardWidget { | @@ -423,7 +436,7 @@ export class DashboardWidget implements GridsterItem, IDashboardWidget { | ||
423 | this.showWidgetTitlePanel = this.widgetContext.hideTitlePanel ? false : | 436 | this.showWidgetTitlePanel = this.widgetContext.hideTitlePanel ? false : |
424 | this.showTitle || this.hasTimewindow; | 437 | this.showTitle || this.hasTimewindow; |
425 | 438 | ||
426 | - this.showWidgetActions = this.widgetContext.hideTitlePanel ? false : true; | 439 | + this.showWidgetActions = !this.widgetContext.hideTitlePanel; |
427 | 440 | ||
428 | this.customHeaderActions = this.widgetContext.customHeaderActions ? this.widgetContext.customHeaderActions : []; | 441 | this.customHeaderActions = this.widgetContext.customHeaderActions ? this.widgetContext.customHeaderActions : []; |
429 | this.widgetActions = this.widgetContext.widgetActions ? this.widgetContext.widgetActions : []; | 442 | this.widgetActions = this.widgetContext.widgetActions ? this.widgetContext.widgetActions : []; |
@@ -105,17 +105,25 @@ | @@ -105,17 +105,25 @@ | ||
105 | {{ 'dashboard.title-required' | translate }} | 105 | {{ 'dashboard.title-required' | translate }} |
106 | </mat-error> | 106 | </mat-error> |
107 | </mat-form-field> | 107 | </mat-form-field> |
108 | - <tb-image-input fxFlex | ||
109 | - label="{{'dashboard.image' | translate}}" | ||
110 | - maxSizeByte="524288" | ||
111 | - formControlName="image"> | ||
112 | - </tb-image-input> | ||
113 | <div formGroupName="configuration" fxLayout="column"> | 108 | <div formGroupName="configuration" fxLayout="column"> |
114 | <mat-form-field class="mat-block"> | 109 | <mat-form-field class="mat-block"> |
115 | <mat-label translate>dashboard.description</mat-label> | 110 | <mat-label translate>dashboard.description</mat-label> |
116 | <textarea matInput formControlName="description" rows="2"></textarea> | 111 | <textarea matInput formControlName="description" rows="2"></textarea> |
117 | </mat-form-field> | 112 | </mat-form-field> |
118 | </div> | 113 | </div> |
114 | + <div style="padding-bottom: 16px;" translate>dashboard.mobile-app-settings</div> | ||
115 | + <tb-image-input fxFlex | ||
116 | + label="{{'dashboard.image' | translate}}" | ||
117 | + maxSizeByte="524288" | ||
118 | + formControlName="image"> | ||
119 | + </tb-image-input> | ||
120 | + <mat-checkbox fxFlex formControlName="mobileHide" style="padding-bottom: 16px; padding-top: 16px;"> | ||
121 | + {{ 'dashboard.mobile-hide' | translate }} | ||
122 | + </mat-checkbox> | ||
123 | + <mat-form-field class="mat-block"> | ||
124 | + <mat-label translate>dashboard.mobile-order</mat-label> | ||
125 | + <input matInput formControlName="mobileOrder" type="number" step="1"> | ||
126 | + </mat-form-field> | ||
119 | </fieldset> | 127 | </fieldset> |
120 | </form> | 128 | </form> |
121 | </div> | 129 | </div> |
@@ -81,6 +81,8 @@ export class DashboardFormComponent extends EntityComponent<Dashboard> { | @@ -81,6 +81,8 @@ export class DashboardFormComponent extends EntityComponent<Dashboard> { | ||
81 | { | 81 | { |
82 | title: [entity ? entity.title : '', [Validators.required]], | 82 | title: [entity ? entity.title : '', [Validators.required]], |
83 | image: [entity ? entity.image : null], | 83 | image: [entity ? entity.image : null], |
84 | + mobileHide: [entity ? entity.mobileHide : false], | ||
85 | + mobileOrder: [entity ? entity.mobileOrder : null, [Validators.pattern(/^-?[0-9]+$/)]], | ||
84 | configuration: this.fb.group( | 86 | configuration: this.fb.group( |
85 | { | 87 | { |
86 | description: [entity && entity.configuration ? entity.configuration.description : ''], | 88 | description: [entity && entity.configuration ? entity.configuration.description : ''], |
@@ -94,6 +96,8 @@ export class DashboardFormComponent extends EntityComponent<Dashboard> { | @@ -94,6 +96,8 @@ export class DashboardFormComponent extends EntityComponent<Dashboard> { | ||
94 | this.updateFields(entity); | 96 | this.updateFields(entity); |
95 | this.entityForm.patchValue({title: entity.title}); | 97 | this.entityForm.patchValue({title: entity.title}); |
96 | this.entityForm.patchValue({image: entity.image}); | 98 | this.entityForm.patchValue({image: entity.image}); |
99 | + this.entityForm.patchValue({mobileHide: entity.mobileHide}); | ||
100 | + this.entityForm.patchValue({mobileOrder: entity.mobileOrder}); | ||
97 | this.entityForm.patchValue({configuration: {description: entity.configuration ? entity.configuration.description : ''}}); | 101 | this.entityForm.patchValue({configuration: {description: entity.configuration ? entity.configuration.description : ''}}); |
98 | } | 102 | } |
99 | 103 |
@@ -28,11 +28,14 @@ export interface DashboardInfo extends BaseData<DashboardId> { | @@ -28,11 +28,14 @@ export interface DashboardInfo extends BaseData<DashboardId> { | ||
28 | title?: string; | 28 | title?: string; |
29 | image?: string; | 29 | image?: string; |
30 | assignedCustomers?: Array<ShortCustomerInfo>; | 30 | assignedCustomers?: Array<ShortCustomerInfo>; |
31 | + mobileHide?: boolean; | ||
32 | + mobileOrder?: number; | ||
31 | } | 33 | } |
32 | 34 | ||
33 | export interface WidgetLayout { | 35 | export interface WidgetLayout { |
34 | sizeX?: number; | 36 | sizeX?: number; |
35 | sizeY?: number; | 37 | sizeY?: number; |
38 | + mobileHide?: boolean; | ||
36 | mobileHeight?: number; | 39 | mobileHeight?: number; |
37 | mobileOrder?: number; | 40 | mobileOrder?: number; |
38 | col?: number; | 41 | col?: number; |
@@ -484,6 +484,7 @@ export interface WidgetConfig { | @@ -484,6 +484,7 @@ export interface WidgetConfig { | ||
484 | showLegend?: boolean; | 484 | showLegend?: boolean; |
485 | legendConfig?: LegendConfig; | 485 | legendConfig?: LegendConfig; |
486 | timewindow?: Timewindow; | 486 | timewindow?: Timewindow; |
487 | + mobileHide?: boolean; | ||
487 | mobileHeight?: number; | 488 | mobileHeight?: number; |
488 | mobileOrder?: number; | 489 | mobileOrder?: number; |
489 | color?: string; | 490 | color?: string; |
@@ -694,6 +694,9 @@ | @@ -694,6 +694,9 @@ | ||
694 | "add-widget": "Add new widget", | 694 | "add-widget": "Add new widget", |
695 | "title": "Title", | 695 | "title": "Title", |
696 | "image": "Dashboard image", | 696 | "image": "Dashboard image", |
697 | + "mobile-app-settings": "Mobile application settings", | ||
698 | + "mobile-order": "Dashboard order in mobile application", | ||
699 | + "mobile-hide": "Hide dashboard in mobile application", | ||
697 | "update-image": "Update dashboard image", | 700 | "update-image": "Update dashboard image", |
698 | "take-screenshot": "Take screenshot", | 701 | "take-screenshot": "Take screenshot", |
699 | "select-widget-title": "Select widget", | 702 | "select-widget-title": "Select widget", |
@@ -2970,6 +2973,7 @@ | @@ -2970,6 +2973,7 @@ | ||
2970 | "mobile-mode-settings": "Mobile mode settings", | 2973 | "mobile-mode-settings": "Mobile mode settings", |
2971 | "order": "Order", | 2974 | "order": "Order", |
2972 | "height": "Height", | 2975 | "height": "Height", |
2976 | + "mobile-hide": "Hide widget in mobile mode", | ||
2973 | "units": "Special symbol to show next to value", | 2977 | "units": "Special symbol to show next to value", |
2974 | "decimals": "Number of digits after floating point", | 2978 | "decimals": "Number of digits after floating point", |
2975 | "timewindow": "Timewindow", | 2979 | "timewindow": "Timewindow", |