diff --git a/application/src/main/java/org/thingsboard/server/controller/BaseController.java b/application/src/main/java/org/thingsboard/server/controller/BaseController.java index a72f2f384b..c78ad18ded 100644 --- a/application/src/main/java/org/thingsboard/server/controller/BaseController.java +++ b/application/src/main/java/org/thingsboard/server/controller/BaseController.java @@ -434,7 +434,6 @@ public abstract class BaseController { try { validateId(dashboardId, "Incorrect dashboardId " + dashboardId); DashboardInfo dashboardInfo = dashboardService.findDashboardInfoById(dashboardId); - SecurityUser authUser = getCurrentUser(); checkDashboard(dashboardInfo); return dashboardInfo; } catch (Exception e) { @@ -447,7 +446,7 @@ public abstract class BaseController { checkTenantId(dashboard.getTenantId()); SecurityUser authUser = getCurrentUser(); if (authUser.getAuthority() == Authority.CUSTOMER_USER) { - if (dashboard.getAssignedCustomers() == null || !dashboard.getAssignedCustomers().containsKey(authUser.getCustomerId().toString())) { + if (!dashboard.isAssignedToCustomer(authUser.getCustomerId())) { throw new ThingsboardException(YOU_DON_T_HAVE_PERMISSION_TO_PERFORM_THIS_OPERATION, ThingsboardErrorCode.PERMISSION_DENIED); } diff --git a/application/src/main/java/org/thingsboard/server/controller/DashboardController.java b/application/src/main/java/org/thingsboard/server/controller/DashboardController.java index 30d57f3f4d..a4664a5a14 100644 --- a/application/src/main/java/org/thingsboard/server/controller/DashboardController.java +++ b/application/src/main/java/org/thingsboard/server/controller/DashboardController.java @@ -18,10 +18,7 @@ package org.thingsboard.server.controller; import org.springframework.http.HttpStatus; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.*; -import org.thingsboard.server.common.data.Customer; -import org.thingsboard.server.common.data.Dashboard; -import org.thingsboard.server.common.data.DashboardInfo; -import org.thingsboard.server.common.data.EntityType; +import org.thingsboard.server.common.data.*; import org.thingsboard.server.common.data.audit.ActionType; import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.DashboardId; @@ -34,6 +31,9 @@ import org.thingsboard.server.dao.exception.IncorrectParameterException; import org.thingsboard.server.dao.model.ModelConstants; import org.thingsboard.server.exception.ThingsboardException; +import java.util.HashSet; +import java.util.Set; + @RestController @RequestMapping("/api") public class DashboardController extends BaseController { @@ -181,6 +181,158 @@ public class DashboardController extends BaseController { } } + @PreAuthorize("hasAuthority('TENANT_ADMIN')") + @RequestMapping(value = "/dashboard/{dashboardId}/customers", method = RequestMethod.POST) + @ResponseBody + public Dashboard updateDashboardCustomers(@PathVariable(DASHBOARD_ID) String strDashboardId, + @RequestBody String[] strCustomerIds) throws ThingsboardException { + checkParameter(DASHBOARD_ID, strDashboardId); + try { + DashboardId dashboardId = new DashboardId(toUUID(strDashboardId)); + Dashboard dashboard = checkDashboardId(dashboardId); + + Set customerIds = new HashSet<>(); + if (strCustomerIds != null) { + for (String strCustomerId : strCustomerIds) { + customerIds.add(new CustomerId(toUUID(strCustomerId))); + } + } + + Set addedCustomerIds = new HashSet<>(); + Set removedCustomerIds = new HashSet<>(); + for (CustomerId customerId : customerIds) { + if (!dashboard.isAssignedToCustomer(customerId)) { + addedCustomerIds.add(customerId); + } + } + + Set assignedCustomers = dashboard.getAssignedCustomers(); + if (assignedCustomers != null) { + for (ShortCustomerInfo customerInfo : assignedCustomers) { + if (!customerIds.contains(customerInfo.getCustomerId())) { + removedCustomerIds.add(customerInfo.getCustomerId()); + } + } + } + + if (addedCustomerIds.isEmpty() && removedCustomerIds.isEmpty()) { + return dashboard; + } else { + Dashboard savedDashboard = null; + for (CustomerId customerId : addedCustomerIds) { + savedDashboard = checkNotNull(dashboardService.assignDashboardToCustomer(dashboardId, customerId)); + ShortCustomerInfo customerInfo = savedDashboard.getAssignedCustomerInfo(customerId); + logEntityAction(dashboardId, savedDashboard, + customerId, + ActionType.ASSIGNED_TO_CUSTOMER, null, strDashboardId, customerId.toString(), customerInfo.getTitle()); + } + for (CustomerId customerId : removedCustomerIds) { + ShortCustomerInfo customerInfo = dashboard.getAssignedCustomerInfo(customerId); + savedDashboard = checkNotNull(dashboardService.unassignDashboardFromCustomer(dashboardId, customerId)); + logEntityAction(dashboardId, dashboard, + customerId, + ActionType.UNASSIGNED_FROM_CUSTOMER, null, strDashboardId, customerId.toString(), customerInfo.getTitle()); + + } + return savedDashboard; + } + } catch (Exception e) { + + logEntityAction(emptyId(EntityType.DASHBOARD), null, + null, + ActionType.ASSIGNED_TO_CUSTOMER, e, strDashboardId); + + throw handleException(e); + } + } + + @PreAuthorize("hasAuthority('TENANT_ADMIN')") + @RequestMapping(value = "/dashboard/{dashboardId}/customers/add", method = RequestMethod.POST) + @ResponseBody + public Dashboard addDashboardCustomers(@PathVariable(DASHBOARD_ID) String strDashboardId, + @RequestBody String[] strCustomerIds) throws ThingsboardException { + checkParameter(DASHBOARD_ID, strDashboardId); + try { + DashboardId dashboardId = new DashboardId(toUUID(strDashboardId)); + Dashboard dashboard = checkDashboardId(dashboardId); + + Set customerIds = new HashSet<>(); + if (strCustomerIds != null) { + for (String strCustomerId : strCustomerIds) { + CustomerId customerId = new CustomerId(toUUID(strCustomerId)); + if (!dashboard.isAssignedToCustomer(customerId)) { + customerIds.add(customerId); + } + } + } + + if (customerIds.isEmpty()) { + return dashboard; + } else { + Dashboard savedDashboard = null; + for (CustomerId customerId : customerIds) { + savedDashboard = checkNotNull(dashboardService.assignDashboardToCustomer(dashboardId, customerId)); + ShortCustomerInfo customerInfo = savedDashboard.getAssignedCustomerInfo(customerId); + logEntityAction(dashboardId, savedDashboard, + customerId, + ActionType.ASSIGNED_TO_CUSTOMER, null, strDashboardId, customerId.toString(), customerInfo.getTitle()); + } + return savedDashboard; + } + } catch (Exception e) { + + logEntityAction(emptyId(EntityType.DASHBOARD), null, + null, + ActionType.ASSIGNED_TO_CUSTOMER, e, strDashboardId); + + throw handleException(e); + } + } + + @PreAuthorize("hasAuthority('TENANT_ADMIN')") + @RequestMapping(value = "/dashboard/{dashboardId}/customers/remove", method = RequestMethod.POST) + @ResponseBody + public Dashboard removeDashboardCustomers(@PathVariable(DASHBOARD_ID) String strDashboardId, + @RequestBody String[] strCustomerIds) throws ThingsboardException { + checkParameter(DASHBOARD_ID, strDashboardId); + try { + DashboardId dashboardId = new DashboardId(toUUID(strDashboardId)); + Dashboard dashboard = checkDashboardId(dashboardId); + + Set customerIds = new HashSet<>(); + if (strCustomerIds != null) { + for (String strCustomerId : strCustomerIds) { + CustomerId customerId = new CustomerId(toUUID(strCustomerId)); + if (dashboard.isAssignedToCustomer(customerId)) { + customerIds.add(customerId); + } + } + } + + if (customerIds.isEmpty()) { + return dashboard; + } else { + Dashboard savedDashboard = null; + for (CustomerId customerId : customerIds) { + ShortCustomerInfo customerInfo = dashboard.getAssignedCustomerInfo(customerId); + savedDashboard = checkNotNull(dashboardService.unassignDashboardFromCustomer(dashboardId, customerId)); + logEntityAction(dashboardId, dashboard, + customerId, + ActionType.UNASSIGNED_FROM_CUSTOMER, null, strDashboardId, customerId.toString(), customerInfo.getTitle()); + + } + return savedDashboard; + } + } catch (Exception e) { + + logEntityAction(emptyId(EntityType.DASHBOARD), null, + null, + ActionType.UNASSIGNED_FROM_CUSTOMER, e, strDashboardId); + + throw handleException(e); + } + } + @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/customer/public/dashboard/{dashboardId}", method = RequestMethod.POST) @ResponseBody diff --git a/application/src/main/java/org/thingsboard/server/service/install/DatabaseHelper.java b/application/src/main/java/org/thingsboard/server/service/install/DatabaseHelper.java index d26565f0b5..fa0dd2f4f1 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/DatabaseHelper.java +++ b/application/src/main/java/org/thingsboard/server/service/install/DatabaseHelper.java @@ -15,12 +15,13 @@ */ package org.thingsboard.server.service.install; +import com.fasterxml.jackson.databind.JavaType; import com.fasterxml.jackson.databind.ObjectMapper; import lombok.extern.slf4j.Slf4j; import org.apache.commons.csv.CSVFormat; import org.apache.commons.csv.CSVParser; import org.apache.commons.lang3.StringUtils; -import com.fasterxml.jackson.databind.JsonNode; +import org.thingsboard.server.common.data.ShortCustomerInfo; import org.thingsboard.server.common.data.UUIDConverter; import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.DashboardId; @@ -54,7 +55,8 @@ public class DatabaseHelper { public static final ObjectMapper objectMapper = new ObjectMapper(); public static void upgradeTo40_assignDashboards(Path dashboardsDump, DashboardService dashboardService, boolean sql) throws Exception { - String[] columns = new String[]{ID, TENANT_ID, CUSTOMER_ID, TITLE, SEARCH_TEXT, ASSIGNED_CUSTOMERS, CONFIGURATION}; + JavaType assignedCustomersType = + objectMapper.getTypeFactory().constructCollectionType(HashSet.class, ShortCustomerInfo.class); try (CSVParser csvParser = new CSVParser(Files.newBufferedReader(dashboardsDump), CSV_DUMP_FORMAT.withFirstRecordAsHeader())) { csvParser.forEach(record -> { String customerIdString = record.get(CUSTOMER_ID); @@ -63,12 +65,11 @@ public class DatabaseHelper { List customerIds = new ArrayList<>(); if (!StringUtils.isEmpty(assignedCustomersString)) { try { - JsonNode assignedCustomersJson = objectMapper.readTree(assignedCustomersString); - Map assignedCustomers = objectMapper.treeToValue(assignedCustomersJson, HashMap.class); - assignedCustomers.forEach((strCustomerId, title) -> { - CustomerId customerId = new CustomerId(UUID.fromString(strCustomerId)); + Set assignedCustomers = objectMapper.readValue(assignedCustomersString, assignedCustomersType); + assignedCustomers.forEach((customerInfo) -> { + CustomerId customerId = customerInfo.getCustomerId(); if (!customerId.isNullUid()) { - customerIds.add(new CustomerId(UUID.fromString(strCustomerId))); + customerIds.add(customerId); } }); } catch (IOException e) { @@ -78,7 +79,7 @@ public class DatabaseHelper { if (!StringUtils.isEmpty(customerIdString)) { CustomerId customerId = new CustomerId(toUUID(customerIdString, sql)); if (!customerId.isNullUid()) { - customerIds.add(new CustomerId(toUUID(customerIdString, sql))); + customerIds.add(customerId); } } for (CustomerId customerId : customerIds) { diff --git a/application/src/test/java/org/thingsboard/server/controller/BaseDashboardControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/BaseDashboardControllerTest.java index 434862bd9d..d73e7bab0c 100644 --- a/application/src/test/java/org/thingsboard/server/controller/BaseDashboardControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/BaseDashboardControllerTest.java @@ -138,10 +138,10 @@ public abstract class BaseDashboardControllerTest extends AbstractControllerTest Dashboard assignedDashboard = doPost("/api/customer/" + savedCustomer.getId().getId().toString() + "/dashboard/" + savedDashboard.getId().getId().toString(), Dashboard.class); - Assert.assertTrue(assignedDashboard.getAssignedCustomers().containsKey(savedCustomer.getId().toString())); + Assert.assertTrue(assignedDashboard.getAssignedCustomers().contains(savedCustomer.toShortCustomerInfo())); Dashboard foundDashboard = doGet("/api/dashboard/" + savedDashboard.getId().getId().toString(), Dashboard.class); - Assert.assertTrue(foundDashboard.getAssignedCustomers().containsKey(savedCustomer.getId().toString())); + Assert.assertTrue(foundDashboard.getAssignedCustomers().contains(savedCustomer.toShortCustomerInfo())); Dashboard unassignedDashboard = doDelete("/api/customer/"+savedCustomer.getId().getId().toString()+"/dashboard/" + savedDashboard.getId().getId().toString(), Dashboard.class); diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/Customer.java b/common/data/src/main/java/org/thingsboard/server/common/data/Customer.java index 1ee9cab68e..59431f3381 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/Customer.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/Customer.java @@ -69,6 +69,11 @@ public class Customer extends ContactBased implements HasName { return false; } + @JsonIgnore + public ShortCustomerInfo toShortCustomerInfo() { + return new ShortCustomerInfo(id, title, isPublic()); + } + @Override @JsonProperty(access = Access.READ_ONLY) public String getName() { diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/DashboardInfo.java b/common/data/src/main/java/org/thingsboard/server/common/data/DashboardInfo.java index 7e18dc6b80..65a467dbfd 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/DashboardInfo.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/DashboardInfo.java @@ -20,16 +20,13 @@ import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.DashboardId; import org.thingsboard.server.common.data.id.TenantId; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; +import java.util.*; public class DashboardInfo extends SearchTextBased implements HasName { private TenantId tenantId; private String title; - private Map assignedCustomers; + private Set assignedCustomers; public DashboardInfo() { super(); @@ -62,38 +59,56 @@ public class DashboardInfo extends SearchTextBased implements HasNa this.title = title; } - public Map getAssignedCustomers() { + public Set getAssignedCustomers() { return assignedCustomers; } - public void setAssignedCustomers(Map assignedCustomers) { + public void setAssignedCustomers(Set assignedCustomers) { this.assignedCustomers = assignedCustomers; } - public boolean addAssignedCustomer(CustomerId customerId, String title) { - if (this.assignedCustomers != null && this.assignedCustomers.containsKey(customerId.toString())) { + 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) { + if (customerInfo.getCustomerId().equals(customerId)) { + return customerInfo; + } + } + } + return null; + } + + public boolean addAssignedCustomer(Customer customer) { + ShortCustomerInfo customerInfo = customer.toShortCustomerInfo(); + if (this.assignedCustomers != null && this.assignedCustomers.contains(customerInfo)) { return false; } else { if (this.assignedCustomers == null) { - this.assignedCustomers = new HashMap<>(); + this.assignedCustomers = new HashSet<>(); } - this.assignedCustomers.put(customerId.toString(), title); + this.assignedCustomers.add(customerInfo); return true; } } - public boolean updateAssignedCustomer(CustomerId customerId, String title) { - if (this.assignedCustomers != null && this.assignedCustomers.containsKey(customerId.toString())) { - this.assignedCustomers.put(customerId.toString(), title); + public boolean updateAssignedCustomer(Customer customer) { + ShortCustomerInfo customerInfo = customer.toShortCustomerInfo(); + if (this.assignedCustomers != null && this.assignedCustomers.contains(customerInfo)) { + this.assignedCustomers.add(customerInfo); return true; } else { return false; } } - public boolean removeAssignedCustomer(CustomerId customerId) { - if (this.assignedCustomers != null && this.assignedCustomers.containsKey(customerId.toString())) { - this.assignedCustomers.remove(customerId.toString()); + public boolean removeAssignedCustomer(Customer customer) { + ShortCustomerInfo customerInfo = customer.toShortCustomerInfo(); + if (this.assignedCustomers != null && this.assignedCustomers.contains(customerInfo)) { + this.assignedCustomers.remove(customerInfo); return true; } else { return false; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/ShortCustomerInfo.java b/common/data/src/main/java/org/thingsboard/server/common/data/ShortCustomerInfo.java new file mode 100644 index 0000000000..68ca46ab99 --- /dev/null +++ b/common/data/src/main/java/org/thingsboard/server/common/data/ShortCustomerInfo.java @@ -0,0 +1,54 @@ +/** + * Copyright © 2016-2017 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.common.data; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.Setter; +import org.thingsboard.server.common.data.id.CustomerId; + +/** + * Created by igor on 2/27/18. + */ + +@AllArgsConstructor +public class ShortCustomerInfo { + + @Getter @Setter + private CustomerId customerId; + + @Getter @Setter + private String title; + + @Getter @Setter + private boolean isPublic; + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + ShortCustomerInfo that = (ShortCustomerInfo) o; + + return customerId.equals(that.customerId); + + } + + @Override + public int hashCode() { + return customerId.hashCode(); + } +} diff --git a/dao/src/main/java/org/thingsboard/server/dao/customer/CustomerServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/customer/CustomerServiceImpl.java index f118aff7a2..657bfba3d1 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/customer/CustomerServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/customer/CustomerServiceImpl.java @@ -98,7 +98,7 @@ public class CustomerServiceImpl extends AbstractEntityService implements Custom log.trace("Executing saveCustomer [{}]", customer); customerValidator.validate(customer); Customer savedCustomer = customerDao.save(customer); - dashboardService.updateCustomerDashboards(savedCustomer.getTenantId(), savedCustomer.getId(), savedCustomer.getTitle()); + dashboardService.updateCustomerDashboards(savedCustomer.getId()); return savedCustomer; } @@ -110,7 +110,7 @@ public class CustomerServiceImpl extends AbstractEntityService implements Custom if (customer == null) { throw new IncorrectParameterException("Unable to delete non-existent customer."); } - dashboardService.unassignCustomerDashboards(customer.getTenantId(), customerId); + dashboardService.unassignCustomerDashboards(customerId); assetService.unassignCustomerAssets(customer.getTenantId(), customerId); deviceService.unassignCustomerDevices(customer.getTenantId(), customerId); userService.deleteCustomerUsers(customer.getTenantId(), customerId); diff --git a/dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardService.java b/dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardService.java index f4af29c88d..06426e71a3 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardService.java @@ -26,7 +26,7 @@ import org.thingsboard.server.common.data.page.TextPageLink; import org.thingsboard.server.common.data.page.TimePageData; import org.thingsboard.server.common.data.page.TimePageLink; -import java.sql.Time; +import java.util.Set; public interface DashboardService { @@ -52,8 +52,8 @@ public interface DashboardService { ListenableFuture> findDashboardsByTenantIdAndCustomerId(TenantId tenantId, CustomerId customerId, TimePageLink pageLink); - void unassignCustomerDashboards(TenantId tenantId, CustomerId customerId); + void unassignCustomerDashboards(CustomerId customerId); - void updateCustomerDashboards(TenantId tenantId, CustomerId customerId, String customerTitle); + void updateCustomerDashboards(CustomerId customerId); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardServiceImpl.java index b9fa3abdc9..741d313940 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardServiceImpl.java @@ -117,7 +117,7 @@ public class DashboardServiceImpl extends AbstractEntityService implements Dashb if (!customer.getTenantId().getId().equals(dashboard.getTenantId().getId())) { throw new DataValidationException("Can't assign dashboard to customer from different tenant!"); } - if (dashboard.addAssignedCustomer(customerId, customer.getTitle())) { + if (dashboard.addAssignedCustomer(customer)) { try { createRelation(new EntityRelation(customerId, dashboardId, EntityRelation.CONTAINS_TYPE, RelationTypeGroup.DASHBOARD)); } catch (ExecutionException | InterruptedException e) { @@ -133,7 +133,11 @@ public class DashboardServiceImpl extends AbstractEntityService implements Dashb @Override public Dashboard unassignDashboardFromCustomer(DashboardId dashboardId, CustomerId customerId) { Dashboard dashboard = findDashboardById(dashboardId); - if (dashboard.removeAssignedCustomer(customerId)) { + Customer customer = customerDao.findById(customerId.getId()); + if (customer == null) { + throw new DataValidationException("Can't unassign dashboard from non-existent customer!"); + } + if (dashboard.removeAssignedCustomer(customer)) { try { deleteRelation(new EntityRelation(customerId, dashboardId, EntityRelation.CONTAINS_TYPE, RelationTypeGroup.DASHBOARD)); } catch (ExecutionException | InterruptedException e) { @@ -146,9 +150,9 @@ public class DashboardServiceImpl extends AbstractEntityService implements Dashb } } - private Dashboard updateAssignedCustomerTitle(DashboardId dashboardId, CustomerId customerId, String customerTitle) { + private Dashboard updateAssignedCustomer(DashboardId dashboardId, Customer customer) { Dashboard dashboard = findDashboardById(dashboardId); - if (dashboard.updateAssignedCustomer(customerId, customerTitle)) { + if (dashboard.updateAssignedCustomer(customer)) { return saveDashboard(dashboard); } else { return dashboard; @@ -207,20 +211,25 @@ public class DashboardServiceImpl extends AbstractEntityService implements Dashb } @Override - public void unassignCustomerDashboards(TenantId tenantId, CustomerId customerId) { - log.trace("Executing unassignCustomerDashboards, tenantId [{}], customerId [{}]", tenantId, customerId); - Validator.validateId(tenantId, INCORRECT_TENANT_ID + tenantId); + public void unassignCustomerDashboards(CustomerId customerId) { + log.trace("Executing unassignCustomerDashboards, customerId [{}]", customerId); Validator.validateId(customerId, "Incorrect customerId " + customerId); - new CustomerDashboardsUnassigner(tenantId, customerId).removeEntities(customerId); + Customer customer = customerDao.findById(customerId.getId()); + if (customer == null) { + throw new DataValidationException("Can't unassign dashboards from non-existent customer!"); + } + new CustomerDashboardsUnassigner(customer).removeEntities(customer); } @Override - public void updateCustomerDashboards(TenantId tenantId, CustomerId customerId, String customerTitle) { - log.trace("Executing updateCustomerDashboards, tenantId [{}], customerId [{}], customerTitle [{}]", tenantId, customerId, customerTitle); - Validator.validateId(tenantId, INCORRECT_TENANT_ID + tenantId); + public void updateCustomerDashboards(CustomerId customerId) { + log.trace("Executing updateCustomerDashboards, customerId [{}]", customerId); Validator.validateId(customerId, "Incorrect customerId " + customerId); - Validator.validateString(customerTitle, "Incorrect customerTitle " + customerTitle); - new CustomerDashboardsUpdater(tenantId, customerId, customerTitle).removeEntities(customerId); + Customer customer = customerDao.findById(customerId.getId()); + if (customer == null) { + throw new DataValidationException("Can't update dashboards for non-existent customer!"); + } + new CustomerDashboardsUpdater(customer).removeEntities(customer); } private DataValidator dashboardValidator = @@ -255,58 +264,52 @@ public class DashboardServiceImpl extends AbstractEntityService implements Dashb } }; - private class CustomerDashboardsUnassigner extends TimePaginatedRemover { - - private TenantId tenantId; - private CustomerId customerId; + private class CustomerDashboardsUnassigner extends TimePaginatedRemover { - CustomerDashboardsUnassigner(TenantId tenantId, CustomerId customerId) { - this.tenantId = tenantId; - this.customerId = customerId; + private Customer customer; + + CustomerDashboardsUnassigner(Customer customer) { + this.customer = customer; } @Override - protected List findEntities(CustomerId id, TimePageLink pageLink) { + protected List findEntities(Customer customer, TimePageLink pageLink) { try { - return dashboardInfoDao.findDashboardsByTenantIdAndCustomerId(tenantId.getId(), id.getId(), pageLink).get(); + return dashboardInfoDao.findDashboardsByTenantIdAndCustomerId(customer.getTenantId().getId(), customer.getId().getId(), pageLink).get(); } catch (InterruptedException | ExecutionException e) { - log.warn("Failed to get dashboards by tenantId [{}] and customerId [{}].", tenantId, id); + log.warn("Failed to get dashboards by tenantId [{}] and customerId [{}].", customer.getTenantId().getId(), customer.getId().getId()); throw new RuntimeException(e); } } @Override protected void removeEntity(DashboardInfo entity) { - unassignDashboardFromCustomer(new DashboardId(entity.getUuidId()), this.customerId); + unassignDashboardFromCustomer(new DashboardId(entity.getUuidId()), this.customer.getId()); } } - private class CustomerDashboardsUpdater extends TimePaginatedRemover { + private class CustomerDashboardsUpdater extends TimePaginatedRemover { - private TenantId tenantId; - private CustomerId customerId; - private String customerTitle; + private Customer customer; - CustomerDashboardsUpdater(TenantId tenantId, CustomerId customerId, String customerTitle) { - this.tenantId = tenantId; - this.customerId = customerId; - this.customerTitle = customerTitle; + CustomerDashboardsUpdater(Customer customer) { + this.customer = customer; } @Override - protected List findEntities(CustomerId id, TimePageLink pageLink) { + protected List findEntities(Customer customer, TimePageLink pageLink) { try { - return dashboardInfoDao.findDashboardsByTenantIdAndCustomerId(tenantId.getId(), id.getId(), pageLink).get(); + return dashboardInfoDao.findDashboardsByTenantIdAndCustomerId(customer.getTenantId().getId(), customer.getId().getId(), pageLink).get(); } catch (InterruptedException | ExecutionException e) { - log.warn("Failed to get dashboards by tenantId [{}] and customerId [{}].", tenantId, id); + log.warn("Failed to get dashboards by tenantId [{}] and customerId [{}].", customer.getTenantId().getId(), customer.getId().getId()); throw new RuntimeException(e); } } @Override protected void removeEntity(DashboardInfo entity) { - updateAssignedCustomerTitle(new DashboardId(entity.getUuidId()), this.customerId, this.customerTitle); + updateAssignedCustomer(new DashboardId(entity.getUuidId()), this.customer); } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/nosql/DashboardEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/nosql/DashboardEntity.java index 8590c2a36f..0327232f37 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/nosql/DashboardEntity.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/nosql/DashboardEntity.java @@ -20,18 +20,22 @@ import com.datastax.driver.mapping.annotations.Column; import com.datastax.driver.mapping.annotations.PartitionKey; import com.datastax.driver.mapping.annotations.Table; import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JavaType; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import lombok.EqualsAndHashCode; import lombok.ToString; import lombok.extern.slf4j.Slf4j; +import org.springframework.util.StringUtils; import org.thingsboard.server.common.data.Dashboard; +import org.thingsboard.server.common.data.ShortCustomerInfo; import org.thingsboard.server.common.data.id.DashboardId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.dao.model.SearchTextEntity; import org.thingsboard.server.dao.model.type.JsonCodec; -import java.util.HashMap; +import java.io.IOException; +import java.util.HashSet; import java.util.UUID; import static org.thingsboard.server.dao.model.ModelConstants.*; @@ -43,6 +47,8 @@ import static org.thingsboard.server.dao.model.ModelConstants.*; public final class DashboardEntity implements SearchTextEntity { private static final ObjectMapper objectMapper = new ObjectMapper(); + private static final JavaType assignedCustomersType = + objectMapper.getTypeFactory().constructCollectionType(HashSet.class, ShortCustomerInfo.class); @PartitionKey(value = 0) @Column(name = ID_PROPERTY) @@ -58,8 +64,8 @@ public final class DashboardEntity implements SearchTextEntity { @Column(name = SEARCH_TEXT_PROPERTY) private String searchText; - @Column(name = DASHBOARD_ASSIGNED_CUSTOMERS_PROPERTY, codec = JsonCodec.class) - private JsonNode assignedCustomers; + @Column(name = DASHBOARD_ASSIGNED_CUSTOMERS_PROPERTY) + private String assignedCustomers; @Column(name = DASHBOARD_CONFIGURATION_PROPERTY, codec = JsonCodec.class) private JsonNode configuration; @@ -77,7 +83,11 @@ public final class DashboardEntity implements SearchTextEntity { } this.title = dashboard.getTitle(); if (dashboard.getAssignedCustomers() != null) { - this.assignedCustomers = objectMapper.valueToTree(dashboard.getAssignedCustomers()); + try { + this.assignedCustomers = objectMapper.writeValueAsString(dashboard.getAssignedCustomers()); + } catch (JsonProcessingException e) { + log.error("Unable to serialize assigned customers to string!", e); + } } this.configuration = dashboard.getConfiguration(); } @@ -106,11 +116,11 @@ public final class DashboardEntity implements SearchTextEntity { this.title = title; } - public JsonNode getAssignedCustomers() { + public String getAssignedCustomers() { return assignedCustomers; } - public void setAssignedCustomers(JsonNode assignedCustomers) { + public void setAssignedCustomers(String assignedCustomers) { this.assignedCustomers = assignedCustomers; } @@ -144,10 +154,10 @@ public final class DashboardEntity implements SearchTextEntity { dashboard.setTenantId(new TenantId(tenantId)); } dashboard.setTitle(title); - if (assignedCustomers != null) { + if (!StringUtils.isEmpty(assignedCustomers)) { try { - dashboard.setAssignedCustomers(objectMapper.treeToValue(assignedCustomers, HashMap.class)); - } catch (JsonProcessingException e) { + dashboard.setAssignedCustomers(objectMapper.readValue(assignedCustomers, assignedCustomersType)); + } catch (IOException e) { log.warn("Unable to parse assigned customers!", e); } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/nosql/DashboardInfoEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/nosql/DashboardInfoEntity.java index 609f3bb598..f64bc44dc1 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/nosql/DashboardInfoEntity.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/nosql/DashboardInfoEntity.java @@ -20,20 +20,20 @@ import com.datastax.driver.mapping.annotations.Column; import com.datastax.driver.mapping.annotations.PartitionKey; import com.datastax.driver.mapping.annotations.Table; import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.JavaType; import com.fasterxml.jackson.databind.ObjectMapper; import lombok.EqualsAndHashCode; import lombok.ToString; import lombok.extern.slf4j.Slf4j; +import org.springframework.util.StringUtils; import org.thingsboard.server.common.data.DashboardInfo; -import org.thingsboard.server.common.data.id.CustomerId; +import org.thingsboard.server.common.data.ShortCustomerInfo; import org.thingsboard.server.common.data.id.DashboardId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.dao.model.SearchTextEntity; -import org.thingsboard.server.dao.model.type.JsonCodec; -import java.util.HashMap; -import java.util.Set; +import java.io.IOException; +import java.util.HashSet; import java.util.UUID; import static org.thingsboard.server.dao.model.ModelConstants.*; @@ -45,6 +45,8 @@ import static org.thingsboard.server.dao.model.ModelConstants.*; public class DashboardInfoEntity implements SearchTextEntity { private static final ObjectMapper objectMapper = new ObjectMapper(); + private static final JavaType assignedCustomersType = + objectMapper.getTypeFactory().constructCollectionType(HashSet.class, ShortCustomerInfo.class); @PartitionKey(value = 0) @Column(name = ID_PROPERTY) @@ -60,8 +62,8 @@ public class DashboardInfoEntity implements SearchTextEntity { @Column(name = SEARCH_TEXT_PROPERTY) private String searchText; - @Column(name = DASHBOARD_ASSIGNED_CUSTOMERS_PROPERTY, codec = JsonCodec.class) - private JsonNode assignedCustomers; + @Column(name = DASHBOARD_ASSIGNED_CUSTOMERS_PROPERTY) + private String assignedCustomers; public DashboardInfoEntity() { super(); @@ -76,7 +78,11 @@ public class DashboardInfoEntity implements SearchTextEntity { } this.title = dashboardInfo.getTitle(); if (dashboardInfo.getAssignedCustomers() != null) { - this.assignedCustomers = objectMapper.valueToTree(dashboardInfo.getAssignedCustomers()); + try { + this.assignedCustomers = objectMapper.writeValueAsString(dashboardInfo.getAssignedCustomers()); + } catch (JsonProcessingException e) { + log.error("Unable to serialize assigned customers to string!", e); + } } } @@ -104,11 +110,11 @@ public class DashboardInfoEntity implements SearchTextEntity { this.title = title; } - public JsonNode getAssignedCustomers() { + public String getAssignedCustomers() { return assignedCustomers; } - public void setAssignedCustomers(JsonNode assignedCustomers) { + public void setAssignedCustomers(String assignedCustomers) { this.assignedCustomers = assignedCustomers; } @@ -134,10 +140,10 @@ public class DashboardInfoEntity implements SearchTextEntity { dashboardInfo.setTenantId(new TenantId(tenantId)); } dashboardInfo.setTitle(title); - if (assignedCustomers != null) { + if (!StringUtils.isEmpty(assignedCustomers)) { try { - dashboardInfo.setAssignedCustomers(objectMapper.treeToValue(assignedCustomers, HashMap.class)); - } catch (JsonProcessingException e) { + dashboardInfo.setAssignedCustomers(objectMapper.readValue(assignedCustomers, assignedCustomersType)); + } catch (IOException e) { log.warn("Unable to parse assigned customers!", e); } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/sql/DashboardEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/sql/DashboardEntity.java index 6f7810bf55..99f65f0a32 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/sql/DashboardEntity.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/sql/DashboardEntity.java @@ -17,6 +17,7 @@ package org.thingsboard.server.dao.model.sql; import com.datastax.driver.core.utils.UUIDs; import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JavaType; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import lombok.Data; @@ -24,8 +25,9 @@ import lombok.EqualsAndHashCode; import lombok.extern.slf4j.Slf4j; import org.hibernate.annotations.Type; import org.hibernate.annotations.TypeDef; +import org.springframework.util.StringUtils; import org.thingsboard.server.common.data.Dashboard; -import org.thingsboard.server.common.data.id.CustomerId; +import org.thingsboard.server.common.data.ShortCustomerInfo; import org.thingsboard.server.common.data.id.DashboardId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.dao.model.BaseSqlEntity; @@ -36,9 +38,8 @@ import org.thingsboard.server.dao.util.mapping.JsonStringType; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.Table; -import java.util.HashMap; -import java.util.List; -import java.util.Set; +import java.io.IOException; +import java.util.HashSet; @Data @Slf4j @@ -49,6 +50,8 @@ import java.util.Set; public final class DashboardEntity extends BaseSqlEntity implements SearchTextEntity { private static final ObjectMapper objectMapper = new ObjectMapper(); + private static final JavaType assignedCustomersType = + objectMapper.getTypeFactory().constructCollectionType(HashSet.class, ShortCustomerInfo.class); @Column(name = ModelConstants.DASHBOARD_TENANT_ID_PROPERTY) private String tenantId; @@ -59,9 +62,8 @@ public final class DashboardEntity extends BaseSqlEntity implements S @Column(name = ModelConstants.SEARCH_TEXT_PROPERTY) private String searchText; - @Type(type = "json") @Column(name = ModelConstants.DASHBOARD_ASSIGNED_CUSTOMERS_PROPERTY) - private JsonNode assignedCustomers; + private String assignedCustomers; @Type(type = "json") @Column(name = ModelConstants.DASHBOARD_CONFIGURATION_PROPERTY) @@ -80,7 +82,11 @@ public final class DashboardEntity extends BaseSqlEntity implements S } this.title = dashboard.getTitle(); if (dashboard.getAssignedCustomers() != null) { - this.assignedCustomers = objectMapper.valueToTree(dashboard.getAssignedCustomers()); + try { + this.assignedCustomers = objectMapper.writeValueAsString(dashboard.getAssignedCustomers()); + } catch (JsonProcessingException e) { + log.error("Unable to serialize assigned customers to string!", e); + } } this.configuration = dashboard.getConfiguration(); } @@ -103,10 +109,10 @@ public final class DashboardEntity extends BaseSqlEntity implements S dashboard.setTenantId(new TenantId(toUUID(tenantId))); } dashboard.setTitle(title); - if (assignedCustomers != null) { + if (!StringUtils.isEmpty(assignedCustomers)) { try { - dashboard.setAssignedCustomers(objectMapper.treeToValue(assignedCustomers, HashMap.class)); - } catch (JsonProcessingException e) { + dashboard.setAssignedCustomers(objectMapper.readValue(assignedCustomers, assignedCustomersType)); + } catch (IOException e) { log.warn("Unable to parse assigned customers!", e); } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/sql/DashboardInfoEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/sql/DashboardInfoEntity.java index d9b8efe8f4..7c295d1bab 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/sql/DashboardInfoEntity.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/sql/DashboardInfoEntity.java @@ -17,14 +17,14 @@ package org.thingsboard.server.dao.model.sql; import com.datastax.driver.core.utils.UUIDs; import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.JavaType; import com.fasterxml.jackson.databind.ObjectMapper; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.extern.slf4j.Slf4j; -import org.hibernate.annotations.Type; +import org.springframework.util.StringUtils; import org.thingsboard.server.common.data.DashboardInfo; -import org.thingsboard.server.common.data.id.CustomerId; +import org.thingsboard.server.common.data.ShortCustomerInfo; import org.thingsboard.server.common.data.id.DashboardId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.dao.model.BaseSqlEntity; @@ -34,8 +34,8 @@ import org.thingsboard.server.dao.model.SearchTextEntity; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.Table; -import java.util.HashMap; -import java.util.Set; +import java.io.IOException; +import java.util.HashSet; @Data @Slf4j @@ -45,6 +45,8 @@ import java.util.Set; public class DashboardInfoEntity extends BaseSqlEntity implements SearchTextEntity { private static final ObjectMapper objectMapper = new ObjectMapper(); + private static final JavaType assignedCustomersType = + objectMapper.getTypeFactory().constructCollectionType(HashSet.class, ShortCustomerInfo.class); @Column(name = ModelConstants.DASHBOARD_TENANT_ID_PROPERTY) private String tenantId; @@ -55,9 +57,8 @@ public class DashboardInfoEntity extends BaseSqlEntity implements @Column(name = ModelConstants.SEARCH_TEXT_PROPERTY) private String searchText; - @Type(type = "json") @Column(name = ModelConstants.DASHBOARD_ASSIGNED_CUSTOMERS_PROPERTY) - private JsonNode assignedCustomers; + private String assignedCustomers; public DashboardInfoEntity() { super(); @@ -72,7 +73,11 @@ public class DashboardInfoEntity extends BaseSqlEntity implements } this.title = dashboardInfo.getTitle(); if (dashboardInfo.getAssignedCustomers() != null) { - this.assignedCustomers = objectMapper.valueToTree(dashboardInfo.getAssignedCustomers()); + try { + this.assignedCustomers = objectMapper.writeValueAsString(dashboardInfo.getAssignedCustomers()); + } catch (JsonProcessingException e) { + log.error("Unable to serialize assigned customers to string!", e); + } } } @@ -98,10 +103,10 @@ public class DashboardInfoEntity extends BaseSqlEntity implements dashboardInfo.setTenantId(new TenantId(toUUID(tenantId))); } dashboardInfo.setTitle(title); - if (assignedCustomers != null) { + if (!StringUtils.isEmpty(assignedCustomers)) { try { - dashboardInfo.setAssignedCustomers(objectMapper.treeToValue(assignedCustomers, HashMap.class)); - } catch (JsonProcessingException e) { + dashboardInfo.setAssignedCustomers(objectMapper.readValue(assignedCustomers, assignedCustomersType)); + } catch (IOException e) { log.warn("Unable to parse assigned customers!", e); } } diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseDashboardServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseDashboardServiceTest.java index 0427fb44f7..380c65e8f7 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseDashboardServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseDashboardServiceTest.java @@ -320,7 +320,7 @@ public abstract class BaseDashboardServiceTest extends AbstractServiceTest { Assert.assertEquals(dashboards, loadedDashboards); - dashboardService.unassignCustomerDashboards(tenantId, customerId); + dashboardService.unassignCustomerDashboards(customerId); pageLink = new TimePageLink(42); pageData = dashboardService.findDashboardsByTenantIdAndCustomerId(tenantId, customerId, pageLink).get(); diff --git a/ui/src/app/api/dashboard.service.js b/ui/src/app/api/dashboard.service.js index 3082bd3811..ae11f84e8b 100644 --- a/ui/src/app/api/dashboard.service.js +++ b/ui/src/app/api/dashboard.service.js @@ -17,7 +17,7 @@ export default angular.module('thingsboard.api.dashboard', []) .factory('dashboardService', DashboardService).name; /*@ngInject*/ -function DashboardService($rootScope, $http, $q, $location, customerService) { +function DashboardService($rootScope, $http, $q, $location, $filter) { var stDiffPromise; @@ -37,7 +37,11 @@ function DashboardService($rootScope, $http, $q, $location, customerService) { deleteDashboard: deleteDashboard, saveDashboard: saveDashboard, unassignDashboardFromCustomer: unassignDashboardFromCustomer, + updateDashboardCustomers: updateDashboardCustomers, + addDashboardCustomers: addDashboardCustomers, + removeDashboardCustomers: removeDashboardCustomers, makeDashboardPublic: makeDashboardPublic, + makeDashboardPrivate: makeDashboardPrivate, getPublicDashboardLink: getPublicDashboardLink } @@ -56,14 +60,14 @@ function DashboardService($rootScope, $http, $q, $location, customerService) { url += '&textOffset=' + pageLink.textOffset; } $http.get(url, config).then(function success(response) { - deferred.resolve(response.data); + deferred.resolve(prepareDashboards(response.data)); }, function fail() { deferred.reject(); }); return deferred.promise; } - function getTenantDashboards(pageLink, applyCustomersInfo, config) { + function getTenantDashboards(pageLink, config) { var deferred = $q.defer(); var url = '/api/tenant/dashboards?limit=' + pageLink.limit; if (angular.isDefined(pageLink.textSearch)) { @@ -76,51 +80,25 @@ function DashboardService($rootScope, $http, $q, $location, customerService) { url += '&textOffset=' + pageLink.textOffset; } $http.get(url, config).then(function success(response) { - if (applyCustomersInfo) { - customerService.applyAssignedCustomersInfo(response.data.data).then( - function success(data) { - response.data.data = data; - deferred.resolve(response.data); - }, - function fail() { - deferred.reject(); - } - ); - } else { - deferred.resolve(response.data); - } + deferred.resolve(prepareDashboards(response.data)); }, function fail() { deferred.reject(); }); return deferred.promise; } - function getCustomerDashboards(customerId, pageLink, applyCustomersInfo, config) { + function getCustomerDashboards(customerId, pageLink, config) { var deferred = $q.defer(); var url = '/api/customer/' + customerId + '/dashboards?limit=' + pageLink.limit; - if (angular.isDefined(pageLink.textSearch)) { - url += '&textSearch=' + pageLink.textSearch; - } if (angular.isDefined(pageLink.idOffset)) { - url += '&idOffset=' + pageLink.idOffset; - } - if (angular.isDefined(pageLink.textOffset)) { - url += '&textOffset=' + pageLink.textOffset; + url += '&offset=' + pageLink.idOffset; } $http.get(url, config).then(function success(response) { - if (applyCustomersInfo) { - customerService.applyAssignedCustomerInfo(response.data.data, customerId).then( - function success(data) { - response.data.data = data; - deferred.resolve(response.data); - }, - function fail() { - deferred.reject(); - } - ); - } else { - deferred.resolve(response.data); + response.data = prepareDashboards(response.data); + if (pageLink.textSearch) { + response.data.data = $filter('filter')(response.data.data, {title: pageLink.textSearch}); } + deferred.resolve(response.data); }, function fail() { deferred.reject(); }); @@ -151,7 +129,7 @@ function DashboardService($rootScope, $http, $q, $location, customerService) { var deferred = $q.defer(); var url = '/api/dashboard/' + dashboardId; $http.get(url, null).then(function success(response) { - deferred.resolve(response.data); + deferred.resolve(prepareDashboard(response.data)); }, function fail() { deferred.reject(); }); @@ -162,7 +140,7 @@ function DashboardService($rootScope, $http, $q, $location, customerService) { var deferred = $q.defer(); var url = '/api/dashboard/info/' + dashboardId; $http.get(url, config).then(function success(response) { - deferred.resolve(response.data); + deferred.resolve(prepareDashboard(response.data)); }, function fail() { deferred.reject(); }); @@ -172,8 +150,8 @@ function DashboardService($rootScope, $http, $q, $location, customerService) { function saveDashboard(dashboard) { var deferred = $q.defer(); var url = '/api/dashboard'; - $http.post(url, dashboard).then(function success(response) { - deferred.resolve(response.data); + $http.post(url, cleanDashboard(dashboard)).then(function success(response) { + deferred.resolve(prepareDashboard(response.data)); }, function fail() { deferred.reject(); }); @@ -195,18 +173,51 @@ function DashboardService($rootScope, $http, $q, $location, customerService) { var deferred = $q.defer(); var url = '/api/customer/' + customerId + '/dashboard/' + dashboardId; $http.post(url, null).then(function success(response) { - deferred.resolve(response.data); + deferred.resolve(prepareDashboard(response.data)); }, function fail() { deferred.reject(); }); return deferred.promise; } - function unassignDashboardFromCustomer(dashboardId) { + function unassignDashboardFromCustomer(customerId, dashboardId) { var deferred = $q.defer(); - var url = '/api/customer/dashboard/' + dashboardId; + var url = '/api/customer/' + customerId + '/dashboard/' + dashboardId; $http.delete(url).then(function success(response) { - deferred.resolve(response.data); + deferred.resolve(prepareDashboard(response.data)); + }, function fail() { + deferred.reject(); + }); + return deferred.promise; + } + + function updateDashboardCustomers(dashboardId, customerIds) { + var deferred = $q.defer(); + var url = '/api/dashboard/' + dashboardId + '/customers'; + $http.post(url, customerIds).then(function success(response) { + deferred.resolve(prepareDashboard(response.data)); + }, function fail() { + deferred.reject(); + }); + return deferred.promise; + } + + function addDashboardCustomers(dashboardId, customerIds) { + var deferred = $q.defer(); + var url = '/api/dashboard/' + dashboardId + '/customers/add'; + $http.post(url, customerIds).then(function success(response) { + deferred.resolve(prepareDashboard(response.data)); + }, function fail() { + deferred.reject(); + }); + return deferred.promise; + } + + function removeDashboardCustomers(dashboardId, customerIds) { + var deferred = $q.defer(); + var url = '/api/dashboard/' + dashboardId + '/customers/remove'; + $http.post(url, customerIds).then(function success(response) { + deferred.resolve(prepareDashboard(response.data)); }, function fail() { deferred.reject(); }); @@ -217,7 +228,18 @@ function DashboardService($rootScope, $http, $q, $location, customerService) { var deferred = $q.defer(); var url = '/api/customer/public/dashboard/' + dashboardId; $http.post(url, null).then(function success(response) { - deferred.resolve(response.data); + deferred.resolve(prepareDashboard(response.data)); + }, function fail() { + deferred.reject(); + }); + return deferred.promise; + } + + function makeDashboardPrivate(dashboardId) { + var deferred = $q.defer(); + var url = '/api/customer/public/dashboard/' + dashboardId; + $http.delete(url).then(function success(response) { + deferred.resolve(prepareDashboard(response.data)); }, function fail() { deferred.reject(); }); @@ -230,8 +252,44 @@ function DashboardService($rootScope, $http, $q, $location, customerService) { if (port != 80 && port != 443) { url += ":" + port; } - url += "/dashboards/" + dashboard.id.id + "?publicId=" + dashboard.customerId.id; + url += "/dashboards/" + dashboard.id.id + "?publicId=" + dashboard.publicCustomerId; return url; } + function prepareDashboards(dashboardsData) { + if (dashboardsData.data) { + for (var i = 0; i < dashboardsData.data.length; i++) { + dashboardsData.data[i] = prepareDashboard(dashboardsData.data[i]); + } + } + return dashboardsData; + } + + function prepareDashboard(dashboard) { + dashboard.publicCustomerId = null; + dashboard.assignedCustomersText = ""; + dashboard.assignedCustomersIds = []; + if (dashboard.assignedCustomers && dashboard.assignedCustomers.length) { + var assignedCustomersTitles = []; + for (var i = 0; i < dashboard.assignedCustomers.length; i++) { + var assignedCustomer = dashboard.assignedCustomers[i]; + dashboard.assignedCustomersIds.push(assignedCustomer.customerId.id); + if (assignedCustomer.public) { + dashboard.publicCustomerId = assignedCustomer.customerId.id; + } else { + assignedCustomersTitles.push(assignedCustomer.title); + } + } + dashboard.assignedCustomersText = assignedCustomersTitles.join(', '); + } + return dashboard; + } + + function cleanDashboard(dashboard) { + delete dashboard.publicCustomerId; + delete dashboard.assignedCustomersText; + delete dashboard.assignedCustomersIds; + return dashboard; + } + } diff --git a/ui/src/app/api/entity.service.js b/ui/src/app/api/entity.service.js index df1c3e0bc9..d30c10cc37 100644 --- a/ui/src/app/api/entity.service.js +++ b/ui/src/app/api/entity.service.js @@ -273,9 +273,9 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device break; case types.entityType.dashboard: if (user.authority === 'CUSTOMER_USER') { - promise = dashboardService.getCustomerDashboards(customerId, pageLink, false, config); + promise = dashboardService.getCustomerDashboards(customerId, pageLink, config); } else { - promise = dashboardService.getTenantDashboards(pageLink, false, config); + promise = dashboardService.getTenantDashboards(pageLink, config); } break; case types.entityType.user: @@ -403,6 +403,21 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device return deferred.promise; } + function resolveAliasEntityId(entityType, id) { + var entityId = { + entityType: entityType, + id: id + }; + if (entityType == types.aliasEntityType.current_customer) { + var user = userService.getCurrentUser(); + entityId.entityType = types.entityType.customer; + if (user.authority === 'CUSTOMER_USER') { + entityId.id = user.customerId; + } + } + return entityId; + } + function getStateEntityId(filter, stateParams) { var entityId = null; if (stateParams) { @@ -417,6 +432,9 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device if (!entityId) { entityId = filter.defaultStateEntity; } + if (entityId) { + entityId = resolveAliasEntityId(entityId.entityType, entityId.id); + } return entityId; } @@ -432,7 +450,8 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device var stateEntityId = getStateEntityId(filter, stateParams); switch (filter.type) { case types.aliasFilterType.singleEntity.value: - getEntity(filter.singleEntity.entityType, filter.singleEntity.id, {ignoreLoading: true}).then( + var aliasEntityId = resolveAliasEntityId(filter.singleEntity.entityType, filter.singleEntity.id); + getEntity(aliasEntityId.entityType, aliasEntityId.id, {ignoreLoading: true}).then( function success(entity) { result.entities = entitiesToEntitiesInfo([entity]); deferred.resolve(result); @@ -530,10 +549,11 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device rootEntityId = filter.rootEntity.id; } if (rootEntityType && rootEntityId) { + var relationQueryRootEntityId = resolveAliasEntityId(rootEntityType, rootEntityId); var searchQuery = { parameters: { - rootId: rootEntityId, - rootType: rootEntityType, + rootId: relationQueryRootEntityId.id, + rootType: relationQueryRootEntityId.entityType, direction: filter.direction }, filters: filter.filters @@ -571,10 +591,11 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device rootEntityId = filter.rootEntity.id; } if (rootEntityType && rootEntityId) { + var searchQueryRootEntityId = resolveAliasEntityId(rootEntityType, rootEntityId); searchQuery = { parameters: { - rootId: rootEntityId, - rootType: rootEntityType, + rootId: searchQueryRootEntityId.id, + rootType: searchQueryRootEntityId.entityType, direction: filter.direction }, relationType: filter.relationType @@ -709,7 +730,7 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device return result; } - function prepareAllowedEntityTypesList(allowedEntityTypes) { + function prepareAllowedEntityTypesList(allowedEntityTypes, useAliasEntityTypes) { var authority = userService.getAuthority(); var entityTypes = {}; switch(authority) { @@ -726,12 +747,18 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device entityTypes.rule = types.entityType.rule; entityTypes.plugin = types.entityType.plugin; entityTypes.dashboard = types.entityType.dashboard; + if (useAliasEntityTypes) { + entityTypes.current_customer = types.aliasEntityType.current_customer; + } break; case 'CUSTOMER_USER': entityTypes.device = types.entityType.device; entityTypes.asset = types.entityType.asset; entityTypes.customer = types.entityType.customer; entityTypes.dashboard = types.entityType.dashboard; + if (useAliasEntityTypes) { + entityTypes.current_customer = types.aliasEntityType.current_customer; + } break; } diff --git a/ui/src/app/api/user.service.js b/ui/src/app/api/user.service.js index ce5e673f18..c969c2f48c 100644 --- a/ui/src/app/api/user.service.js +++ b/ui/src/app/api/user.service.js @@ -266,9 +266,9 @@ function UserService($http, $q, $rootScope, adminService, dashboardService, logi var pageLink = {limit: 100}; var fetchDashboardsPromise; if (currentUser.authority === 'TENANT_ADMIN') { - fetchDashboardsPromise = dashboardService.getTenantDashboards(pageLink, false); + fetchDashboardsPromise = dashboardService.getTenantDashboards(pageLink); } else { - fetchDashboardsPromise = dashboardService.getCustomerDashboards(currentUser.customerId, pageLink, false); + fetchDashboardsPromise = dashboardService.getCustomerDashboards(currentUser.customerId, pageLink); } fetchDashboardsPromise.then( function success(result) { diff --git a/ui/src/app/common/types.constant.js b/ui/src/app/common/types.constant.js index d82add14c0..6f09f3417b 100644 --- a/ui/src/app/common/types.constant.js +++ b/ui/src/app/common/types.constant.js @@ -296,6 +296,9 @@ export default angular.module('thingsboard.types', []) dashboard: "DASHBOARD", alarm: "ALARM" }, + aliasEntityType: { + current_customer: "CURRENT_CUSTOMER" + }, entityTypeTranslations: { "DEVICE": { type: 'entity.type-device', @@ -350,6 +353,10 @@ export default angular.module('thingsboard.types', []) typePlural: 'entity.type-alarms', list: 'entity.list-of-alarms', nameStartsWith: 'entity.alarm-name-starts-with' + }, + "CURRENT_CUSTOMER": { + type: 'entity.type-current-customer', + list: 'entity.type-current-customer' } }, entitySearchDirection: { diff --git a/ui/src/app/components/dashboard-autocomplete.directive.js b/ui/src/app/components/dashboard-autocomplete.directive.js index 2235b82e95..6af55853b2 100644 --- a/ui/src/app/components/dashboard-autocomplete.directive.js +++ b/ui/src/app/components/dashboard-autocomplete.directive.js @@ -48,7 +48,7 @@ function DashboardAutocomplete($compile, $templateCache, $q, dashboardService, u var promise; if (scope.dashboardsScope === 'customer' || userService.getAuthority() === 'CUSTOMER_USER') { if (scope.customerId) { - promise = dashboardService.getCustomerDashboards(scope.customerId, pageLink, false, {ignoreLoading: true}); + promise = dashboardService.getCustomerDashboards(scope.customerId, pageLink, {ignoreLoading: true}); } else { promise = $q.when({data: []}); } @@ -60,7 +60,7 @@ function DashboardAutocomplete($compile, $templateCache, $q, dashboardService, u promise = $q.when({data: []}); } } else { - promise = dashboardService.getTenantDashboards(pageLink, false, {ignoreLoading: true}); + promise = dashboardService.getTenantDashboards(pageLink, {ignoreLoading: true}); } } diff --git a/ui/src/app/components/dashboard-select.directive.js b/ui/src/app/components/dashboard-select.directive.js index ac5cd3d5b1..b1721687a6 100644 --- a/ui/src/app/components/dashboard-select.directive.js +++ b/ui/src/app/components/dashboard-select.directive.js @@ -48,12 +48,12 @@ function DashboardSelect($compile, $templateCache, $q, $mdMedia, $mdPanel, $docu var promise; if (scope.dashboardsScope === 'customer' || userService.getAuthority() === 'CUSTOMER_USER') { if (scope.customerId && scope.customerId != types.id.nullUid) { - promise = dashboardService.getCustomerDashboards(scope.customerId, pageLink, false, {ignoreLoading: true}); + promise = dashboardService.getCustomerDashboards(scope.customerId, pageLink, {ignoreLoading: true}); } else { promise = $q.when({data: []}); } } else { - promise = dashboardService.getTenantDashboards(pageLink, false, {ignoreLoading: true}); + promise = dashboardService.getTenantDashboards(pageLink, {ignoreLoading: true}); } promise.then(function success(result) { diff --git a/ui/src/app/dashboard/add-dashboards-to-customer.controller.js b/ui/src/app/dashboard/add-dashboards-to-customer.controller.js index 6fe6e7932e..b0bbef1b75 100644 --- a/ui/src/app/dashboard/add-dashboards-to-customer.controller.js +++ b/ui/src/app/dashboard/add-dashboards-to-customer.controller.js @@ -52,7 +52,7 @@ export default function AddDashboardsToCustomerController(dashboardService, $mdD fetchMoreItems_: function () { if (vm.dashboards.hasNext && !vm.dashboards.pending) { vm.dashboards.pending = true; - dashboardService.getTenantDashboards(vm.dashboards.nextPageLink, false).then( + dashboardService.getTenantDashboards(vm.dashboards.nextPageLink).then( function success(dashboards) { vm.dashboards.data = vm.dashboards.data.concat(dashboards.data); vm.dashboards.nextPageLink = dashboards.nextPageLink; diff --git a/ui/src/app/dashboard/assign-to-customer.controller.js b/ui/src/app/dashboard/assign-to-customer.controller.js deleted file mode 100644 index fa2cd0505d..0000000000 --- a/ui/src/app/dashboard/assign-to-customer.controller.js +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright © 2016-2017 The Thingsboard Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/*@ngInject*/ -export default function AssignDashboardToCustomerController(customerService, dashboardService, $mdDialog, $q, dashboardIds, customers) { - - var vm = this; - - vm.customers = customers; - vm.searchText = ''; - - vm.assign = assign; - vm.cancel = cancel; - vm.isCustomerSelected = isCustomerSelected; - vm.hasData = hasData; - vm.noData = noData; - vm.searchCustomerTextUpdated = searchCustomerTextUpdated; - vm.toggleCustomerSelection = toggleCustomerSelection; - - vm.theCustomers = { - getItemAtIndex: function (index) { - if (index > vm.customers.data.length) { - vm.theCustomers.fetchMoreItems_(index); - return null; - } - var item = vm.customers.data[index]; - if (item) { - item.indexNumber = index + 1; - } - return item; - }, - - getLength: function () { - if (vm.customers.hasNext) { - return vm.customers.data.length + vm.customers.nextPageLink.limit; - } else { - return vm.customers.data.length; - } - }, - - fetchMoreItems_: function () { - if (vm.customers.hasNext && !vm.customers.pending) { - vm.customers.pending = true; - customerService.getCustomers(vm.customers.nextPageLink).then( - function success(customers) { - vm.customers.data = vm.customers.data.concat(customers.data); - vm.customers.nextPageLink = customers.nextPageLink; - vm.customers.hasNext = customers.hasNext; - if (vm.customers.hasNext) { - vm.customers.nextPageLink.limit = vm.customers.pageSize; - } - vm.customers.pending = false; - }, - function fail() { - vm.customers.hasNext = false; - vm.customers.pending = false; - }); - } - } - }; - - function cancel () { - $mdDialog.cancel(); - } - - function assign () { - var tasks = []; - for (var dashboardId in dashboardIds) { - tasks.push(dashboardService.assignDashboardToCustomer(vm.customers.selection.id.id, dashboardIds[dashboardId])); - } - $q.all(tasks).then(function () { - $mdDialog.hide(); - }); - } - - function noData () { - return vm.customers.data.length == 0 && !vm.customers.hasNext; - } - - function hasData () { - return vm.customers.data.length > 0; - } - - function toggleCustomerSelection ($event, customer) { - $event.stopPropagation(); - if (vm.isCustomerSelected(customer)) { - vm.customers.selection = null; - } else { - vm.customers.selection = customer; - } - } - - function isCustomerSelected (customer) { - return vm.customers.selection != null && customer && - customer.id.id === vm.customers.selection.id.id; - } - - function searchCustomerTextUpdated () { - vm.customers = { - pageSize: vm.customers.pageSize, - data: [], - nextPageLink: { - limit: vm.customers.pageSize, - textSearch: vm.searchText - }, - selection: null, - hasNext: true, - pending: false - }; - } -} diff --git a/ui/src/app/dashboard/assign-to-customer.tpl.html b/ui/src/app/dashboard/assign-to-customer.tpl.html deleted file mode 100644 index 4d7ba85452..0000000000 --- a/ui/src/app/dashboard/assign-to-customer.tpl.html +++ /dev/null @@ -1,76 +0,0 @@ - - -
- -
-

dashboard.assign-dashboard-to-customer

- - - - -
-
- - - -
-
- dashboard.assign-to-customer-text - - - - search - - - -
- customer.no-customers-text - - - - - {{ customer.title }} - - - -
-
-
-
- - - - {{ 'action.assign' | translate }} - - {{ 'action.cancel' | - translate }} - - -
-
\ No newline at end of file diff --git a/ui/src/app/dashboard/dashboard-card.scss b/ui/src/app/dashboard/dashboard-card.scss new file mode 100644 index 0000000000..32f25c7aab --- /dev/null +++ b/ui/src/app/dashboard/dashboard-card.scss @@ -0,0 +1,27 @@ +/** + * Copyright © 2016-2017 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +.tb-dashboard-assigned-customers { + display: block; + display: -webkit-box; + height: 34px; + overflow: hidden; + text-overflow: ellipsis; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + margin-bottom: 4px; +} + diff --git a/ui/src/app/dashboard/dashboard-card.tpl.html b/ui/src/app/dashboard/dashboard-card.tpl.html index 636786758e..ed19fda07a 100644 --- a/ui/src/app/dashboard/dashboard-card.tpl.html +++ b/ui/src/app/dashboard/dashboard-card.tpl.html @@ -15,6 +15,6 @@ limitations under the License. --> -
{{'dashboard.assignedToCustomer' | translate}} '{{vm.item.assignedCustomer.title}}'
-
{{'dashboard.public' | translate}}
+
{{'dashboard.assignedToCustomers' | translate}}: '{{vm.item.assignedCustomersText}}'
+
{{'dashboard.public' | translate}}
diff --git a/ui/src/app/dashboard/dashboard-fieldset.tpl.html b/ui/src/app/dashboard/dashboard-fieldset.tpl.html index a54f477d11..00ee554d84 100644 --- a/ui/src/app/dashboard/dashboard-fieldset.tpl.html +++ b/ui/src/app/dashboard/dashboard-fieldset.tpl.html @@ -19,24 +19,29 @@ ng-show="!isEdit && dashboardScope === 'tenant'" class="md-raised md-primary">{{ 'dashboard.export' | translate }} {{ 'dashboard.make-public' | translate }} -{{ 'dashboard.assign-to-customer' | translate }} -{{ isPublic ? 'dashboard.make-private' : 'dashboard.unassign-from-customer' | translate }} +{{ 'dashboard.make-private' | translate }} +{{ 'dashboard.manage-assigned-customers' | translate }} +{{ 'dashboard.unassign-from-customer' | translate }} {{ 'dashboard.delete' | translate }} - - + ng-show="!isEdit && dashboard.assignedCustomersText && dashboardScope === 'tenant'"> + + -
+
diff --git a/ui/src/app/dashboard/index.js b/ui/src/app/dashboard/index.js index 40897164fa..ac63dc55a2 100644 --- a/ui/src/app/dashboard/index.js +++ b/ui/src/app/dashboard/index.js @@ -40,8 +40,8 @@ import DashboardRoutes from './dashboard.routes'; import {DashboardsController, DashboardCardController, MakeDashboardPublicDialogController} from './dashboards.controller'; import DashboardController from './dashboard.controller'; import DashboardSettingsController from './dashboard-settings.controller'; -import AssignDashboardToCustomerController from './assign-to-customer.controller'; import AddDashboardsToCustomerController from './add-dashboards-to-customer.controller'; +import ManageAssignedCustomersController from './manage-assigned-customers.controller'; import AddWidgetController from './add-widget.controller'; import DashboardDirective from './dashboard.directive'; import EditWidgetDirective from './edit-widget.directive'; @@ -74,8 +74,8 @@ export default angular.module('thingsboard.dashboard', [ .controller('MakeDashboardPublicDialogController', MakeDashboardPublicDialogController) .controller('DashboardController', DashboardController) .controller('DashboardSettingsController', DashboardSettingsController) - .controller('AssignDashboardToCustomerController', AssignDashboardToCustomerController) .controller('AddDashboardsToCustomerController', AddDashboardsToCustomerController) + .controller('ManageAssignedCustomersController', ManageAssignedCustomersController) .controller('AddWidgetController', AddWidgetController) .directive('tbDashboardDetails', DashboardDirective) .directive('tbEditWidget', EditWidgetDirective) diff --git a/ui/src/app/dashboard/manage-assigned-customers.controller.js b/ui/src/app/dashboard/manage-assigned-customers.controller.js new file mode 100644 index 0000000000..90d3e6dc84 --- /dev/null +++ b/ui/src/app/dashboard/manage-assigned-customers.controller.js @@ -0,0 +1,69 @@ +/* + * Copyright © 2016-2017 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*@ngInject*/ +export default function ManageAssignedCustomersController($mdDialog, $q, types, dashboardService, actionType, dashboardIds, assignedCustomers) { + + var vm = this; + + vm.types = types; + vm.actionType = actionType; + vm.dashboardIds = dashboardIds; + vm.assignedCustomers = assignedCustomers; + if (actionType != 'manage') { + vm.assignedCustomers = []; + } + + if (actionType == 'manage') { + vm.titleText = 'dashboard.manage-assigned-customers'; + vm.labelText = 'dashboard.assigned-customers'; + vm.actionName = 'action.update'; + } else if (actionType == 'assign') { + vm.titleText = 'dashboard.assign-to-customers'; + vm.labelText = 'dashboard.assign-to-customers-text'; + vm.actionName = 'action.assign'; + } else if (actionType == 'unassign') { + vm.titleText = 'dashboard.unassign-from-customers'; + vm.labelText = 'dashboard.unassign-from-customers-text'; + vm.actionName = 'action.unassign'; + } + + vm.submit = submit; + vm.cancel = cancel; + + function cancel () { + $mdDialog.cancel(); + } + + function submit () { + var tasks = []; + for (var i=0;i + +
+ +
+

{{vm.titleText}}

+ + + + +
+
+ + + +
+
+ {{vm.labelText}} + +
+
+
+ + + + {{ vm.actionName | translate }} + + {{ 'action.cancel' | + translate }} + + +
+
\ No newline at end of file diff --git a/ui/src/app/entity/entity-autocomplete.directive.js b/ui/src/app/entity/entity-autocomplete.directive.js index 62f3d6d33e..2d114dbb2e 100644 --- a/ui/src/app/entity/entity-autocomplete.directive.js +++ b/ui/src/app/entity/entity-autocomplete.directive.js @@ -38,7 +38,12 @@ export default function EntityAutocomplete($compile, $templateCache, $q, $filter if (scope.excludeEntityIds && scope.excludeEntityIds.length) { limit += scope.excludeEntityIds.length; } - entityService.getEntitiesByNameFilter(scope.entityType, searchText, limit, {ignoreLoading: true}, scope.entitySubtype).then(function success(result) { + var targetType = scope.entityType; + if (targetType == types.aliasEntityType.current_customer) { + targetType = types.entityType.customer; + } + + entityService.getEntitiesByNameFilter(targetType, searchText, limit, {ignoreLoading: true}, scope.entitySubtype).then(function success(result) { if (result) { if (scope.excludeEntityIds && scope.excludeEntityIds.length) { var entities = []; @@ -71,7 +76,11 @@ export default function EntityAutocomplete($compile, $templateCache, $q, $filter ngModelCtrl.$render = function () { if (ngModelCtrl.$viewValue) { - entityService.getEntity(scope.entityType, ngModelCtrl.$viewValue).then( + var targetType = scope.entityType; + if (targetType == types.aliasEntityType.current_customer) { + targetType = types.entityType.customer; + } + entityService.getEntity(targetType, ngModelCtrl.$viewValue).then( function success(entity) { scope.entity = entity; }, @@ -114,55 +123,61 @@ export default function EntityAutocomplete($compile, $templateCache, $q, $filter scope.selectEntityText = 'asset.select-asset'; scope.entityText = 'asset.asset'; scope.noEntitiesMatchingText = 'asset.no-assets-matching'; - scope.entityRequiredText = 'asset.asset-required' + scope.entityRequiredText = 'asset.asset-required'; break; case types.entityType.device: scope.selectEntityText = 'device.select-device'; scope.entityText = 'device.device'; scope.noEntitiesMatchingText = 'device.no-devices-matching'; - scope.entityRequiredText = 'device.device-required' + scope.entityRequiredText = 'device.device-required'; break; case types.entityType.rule: scope.selectEntityText = 'rule.select-rule'; scope.entityText = 'rule.rule'; scope.noEntitiesMatchingText = 'rule.no-rules-matching'; - scope.entityRequiredText = 'rule.rule-required' + scope.entityRequiredText = 'rule.rule-required'; break; case types.entityType.plugin: scope.selectEntityText = 'plugin.select-plugin'; scope.entityText = 'plugin.plugin'; scope.noEntitiesMatchingText = 'plugin.no-plugins-matching'; - scope.entityRequiredText = 'plugin.plugin-required' + scope.entityRequiredText = 'plugin.plugin-required'; break; case types.entityType.tenant: scope.selectEntityText = 'tenant.select-tenant'; scope.entityText = 'tenant.tenant'; scope.noEntitiesMatchingText = 'tenant.no-tenants-matching'; - scope.entityRequiredText = 'tenant.tenant-required' + scope.entityRequiredText = 'tenant.tenant-required'; break; case types.entityType.customer: scope.selectEntityText = 'customer.select-customer'; scope.entityText = 'customer.customer'; scope.noEntitiesMatchingText = 'customer.no-customers-matching'; - scope.entityRequiredText = 'customer.customer-required' + scope.entityRequiredText = 'customer.customer-required'; break; case types.entityType.user: scope.selectEntityText = 'user.select-user'; scope.entityText = 'user.user'; scope.noEntitiesMatchingText = 'user.no-users-matching'; - scope.entityRequiredText = 'user.user-required' + scope.entityRequiredText = 'user.user-required'; break; case types.entityType.dashboard: scope.selectEntityText = 'dashboard.select-dashboard'; scope.entityText = 'dashboard.dashboard'; scope.noEntitiesMatchingText = 'dashboard.no-dashboards-matching'; - scope.entityRequiredText = 'dashboard.dashboard-required' + scope.entityRequiredText = 'dashboard.dashboard-required'; break; case types.entityType.alarm: scope.selectEntityText = 'alarm.select-alarm'; scope.entityText = 'alarm.alarm'; scope.noEntitiesMatchingText = 'alarm.no-alarms-matching'; - scope.entityRequiredText = 'alarm.alarm-required' + scope.entityRequiredText = 'alarm.alarm-required'; + break; + case types.aliasEntityType.current_customer: + scope.selectEntityText = 'customer.select-default-customer'; + scope.entityText = 'customer.default-customer'; + scope.noEntitiesMatchingText = 'customer.no-customers-matching'; + scope.entityRequiredText = 'customer.default-customer-required'; break; } if (scope.entity && scope.entity.id.entityType != scope.entityType) { diff --git a/ui/src/app/entity/entity-filter.tpl.html b/ui/src/app/entity/entity-filter.tpl.html index 9f62454915..0e8ee1177b 100644 --- a/ui/src/app/entity/entity-filter.tpl.html +++ b/ui/src/app/entity/entity-filter.tpl.html @@ -32,6 +32,7 @@ @@ -78,6 +79,7 @@
@@ -123,6 +125,7 @@ the-form="theForm" tb-required="!filter.rootStateEntity" ng-disabled="filter.rootStateEntity" + use-alias-entity-types="true" ng-model="filter.rootEntity">
@@ -139,6 +142,7 @@ @@ -182,6 +186,7 @@ the-form="theForm" tb-required="!filter.rootStateEntity" ng-disabled="filter.rootStateEntity" + use-alias-entity-types="true" ng-model="filter.rootEntity"> @@ -198,6 +203,7 @@ @@ -249,6 +255,7 @@ the-form="theForm" tb-required="!filter.rootStateEntity" ng-disabled="filter.rootStateEntity" + use-alias-entity-types="true" ng-model="filter.rootEntity"> @@ -265,6 +272,7 @@ diff --git a/ui/src/app/entity/entity-select.directive.js b/ui/src/app/entity/entity-select.directive.js index 2778a79a17..8e2fbf9674 100644 --- a/ui/src/app/entity/entity-select.directive.js +++ b/ui/src/app/entity/entity-select.directive.js @@ -105,7 +105,8 @@ export default function EntitySelect($compile, $templateCache) { scope: { theForm: '=?', tbRequired: '=?', - disabled:'=ngDisabled' + disabled:'=ngDisabled', + useAliasEntityTypes: "=?" } }; } diff --git a/ui/src/app/entity/entity-select.tpl.html b/ui/src/app/entity/entity-select.tpl.html index 13e17e7af1..d37020220d 100644 --- a/ui/src/app/entity/entity-select.tpl.html +++ b/ui/src/app/entity/entity-select.tpl.html @@ -20,6 +20,7 @@ the-form="theForm" ng-disabled="disabled" tb-required="tbRequired" + use-alias-entity-types="useAliasEntityTypes" ng-model="model.entityType">