diff --git a/application/src/main/java/org/thingsboard/server/service/edge/DefaultEdgeNotificationService.java b/application/src/main/java/org/thingsboard/server/service/edge/DefaultEdgeNotificationService.java index 0a85dcacf5..9ce455c758 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/DefaultEdgeNotificationService.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/DefaultEdgeNotificationService.java @@ -292,7 +292,7 @@ public class DefaultEdgeNotificationService implements EdgeNotificationService { case ADDED: // used only for USER entity case UPDATED: case CREDENTIALS_UPDATED: - edgeIdsFuture = findRelatedEdgeIdsByEntityId(tenantId, entityId); + edgeIdsFuture = edgeService.findRelatedEdgeIdsByEntityId(tenantId, entityId); Futures.addCallback(edgeIdsFuture, new FutureCallback>() { @Override public void onSuccess(@Nullable List edgeIds) { @@ -310,7 +310,7 @@ public class DefaultEdgeNotificationService implements EdgeNotificationService { break; case ASSIGNED_TO_CUSTOMER: case UNASSIGNED_FROM_CUSTOMER: - edgeIdsFuture = findRelatedEdgeIdsByEntityId(tenantId, entityId); + edgeIdsFuture = edgeService.findRelatedEdgeIdsByEntityId(tenantId, entityId); Futures.addCallback(edgeIdsFuture, new FutureCallback>() { @Override public void onSuccess(@Nullable List edgeIds) { @@ -408,7 +408,7 @@ public class DefaultEdgeNotificationService implements EdgeNotificationService { if (alarm != null) { EdgeEventType edgeEventType = getEdgeQueueTypeByEntityType(alarm.getOriginator().getEntityType()); if (edgeEventType != null) { - ListenableFuture> relatedEdgeIdsByEntityIdFuture = findRelatedEdgeIdsByEntityId(tenantId, alarm.getOriginator()); + ListenableFuture> relatedEdgeIdsByEntityIdFuture = edgeService.findRelatedEdgeIdsByEntityId(tenantId, alarm.getOriginator()); Futures.transform(relatedEdgeIdsByEntityIdFuture, relatedEdgeIdsByEntityId -> { if (relatedEdgeIdsByEntityId != null) { for (EdgeId edgeId : relatedEdgeIdsByEntityId) { @@ -433,8 +433,8 @@ public class DefaultEdgeNotificationService implements EdgeNotificationService { if (!relation.getFrom().getEntityType().equals(EntityType.EDGE) && !relation.getTo().getEntityType().equals(EntityType.EDGE)) { List>> futures = new ArrayList<>(); - futures.add(findRelatedEdgeIdsByEntityId(tenantId, relation.getTo())); - futures.add(findRelatedEdgeIdsByEntityId(tenantId, relation.getFrom())); + futures.add(edgeService.findRelatedEdgeIdsByEntityId(tenantId, relation.getTo())); + futures.add(edgeService.findRelatedEdgeIdsByEntityId(tenantId, relation.getFrom())); ListenableFuture>> combinedFuture = Futures.allAsList(futures); Futures.transform(combinedFuture, listOfListsEdgeIds -> { Set uniqueEdgeIds = new HashSet<>(); @@ -460,48 +460,6 @@ public class DefaultEdgeNotificationService implements EdgeNotificationService { } } - private ListenableFuture> findRelatedEdgeIdsByEntityId(TenantId tenantId, EntityId entityId) { - switch (entityId.getEntityType()) { - case DEVICE: - case ASSET: - case ENTITY_VIEW: - ListenableFuture> originatorEdgeRelationsFuture = - relationService.findByToAndTypeAsync(tenantId, entityId, EntityRelation.CONTAINS_TYPE, RelationTypeGroup.EDGE); - return Futures.transform(originatorEdgeRelationsFuture, originatorEdgeRelations -> { - if (originatorEdgeRelations != null && originatorEdgeRelations.size() > 0) { - return Collections.singletonList(new EdgeId(originatorEdgeRelations.get(0).getFrom().getId())); - } else { - return Collections.emptyList(); - } - }, dbCallbackExecutorService); - case DASHBOARD: - return convertToEdgeIds(edgeService.findEdgesByTenantIdAndDashboardId(tenantId, new DashboardId(entityId.getId()))); - case RULE_CHAIN: - return convertToEdgeIds(edgeService.findEdgesByTenantIdAndRuleChainId(tenantId, new RuleChainId(entityId.getId()))); - case USER: - User userById = userService.findUserById(tenantId, new UserId(entityId.getId())); - TextPageData edges; - if (userById.getCustomerId() == null || userById.getCustomerId().isNullUid()) { - edges = edgeService.findEdgesByTenantId(tenantId, new TextPageLink(Integer.MAX_VALUE)); - } else { - edges = edgeService.findEdgesByTenantIdAndCustomerId(tenantId, new CustomerId(entityId.getId()), new TextPageLink(Integer.MAX_VALUE)); - } - return convertToEdgeIds(Futures.immediateFuture(edges.getData())); - default: - return Futures.immediateFuture(Collections.emptyList()); - } - } - - private ListenableFuture> convertToEdgeIds(ListenableFuture> future) { - return Futures.transform(future, edges -> { - if (edges != null && !edges.isEmpty()) { - return edges.stream().map(IdBased::getId).collect(Collectors.toList()); - } else { - return Collections.emptyList(); - } - }, dbCallbackExecutorService); - } - private EdgeEventType getEdgeQueueTypeByEntityType(EntityType entityType) { switch (entityType) { case DEVICE: diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcSession.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcSession.java index e036349ab1..7a088fd836 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcSession.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcSession.java @@ -32,6 +32,7 @@ import lombok.Data; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang.RandomStringUtils; import org.checkerframework.checker.nullness.qual.Nullable; +import org.thingsboard.rule.engine.api.msg.DeviceAttributesEventNotificationMsg; import org.thingsboard.server.common.data.AdminSettings; import org.thingsboard.server.common.data.Customer; import org.thingsboard.server.common.data.Dashboard; @@ -64,6 +65,7 @@ import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.UserId; import org.thingsboard.server.common.data.id.WidgetTypeId; import org.thingsboard.server.common.data.id.WidgetsBundleId; +import org.thingsboard.server.common.data.kv.AttributeKey; import org.thingsboard.server.common.data.kv.AttributeKvEntry; import org.thingsboard.server.common.data.kv.BaseAttributeKvEntry; import org.thingsboard.server.common.data.kv.LongDataEntry; @@ -87,6 +89,7 @@ import org.thingsboard.server.common.transport.util.JsonUtils; import org.thingsboard.server.gen.edge.AdminSettingsUpdateMsg; import org.thingsboard.server.gen.edge.AlarmUpdateMsg; import org.thingsboard.server.gen.edge.AssetUpdateMsg; +import org.thingsboard.server.gen.edge.AttributeDeleteMsg; import org.thingsboard.server.gen.edge.AttributesRequestMsg; import org.thingsboard.server.gen.edge.ConnectRequestMsg; import org.thingsboard.server.gen.edge.ConnectResponseCode; @@ -124,11 +127,12 @@ import org.thingsboard.server.queue.common.TbProtoQueueMsg; import org.thingsboard.server.service.edge.EdgeContextComponent; import java.io.Closeable; -import java.io.IOException; import java.util.ArrayList; import java.util.Collections; +import java.util.HashSet; import java.util.List; import java.util.Optional; +import java.util.Set; import java.util.UUID; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutionException; @@ -387,7 +391,7 @@ public final class EdgeGrpcSession implements Closeable { ctx.getAttributesService().save(edge.getTenantId(), edge.getId(), DataConstants.SERVER_SCOPE, attributes); } - private DownlinkMsg processTelemetryMessage(EdgeEvent edgeEvent) throws IOException { + private DownlinkMsg processTelemetryMessage(EdgeEvent edgeEvent) { log.trace("Executing processTelemetryMessage, edgeEvent [{}]", edgeEvent); EntityId entityId = null; switch (edgeEvent.getEdgeEventType()) { @@ -840,6 +844,9 @@ public final class EdgeGrpcSession implements Closeable { result.add(processPostTelemetry(entityId, entityData.getPostTelemetryMsg(), metaData)); } } + if (entityData.hasAttributeDeleteMsg()) { + result.add(processAttributeDeleteMsg(entityId, entityData.getAttributeDeleteMsg(), entityData.getEntityType())); + } } } @@ -962,6 +969,7 @@ public final class EdgeGrpcSession implements Closeable { @Override public void onFailure(Throwable t) { + log.error("Can't process post telemetry [{}]", msg, t); futureToSet.setException(t); } }); @@ -970,11 +978,49 @@ public final class EdgeGrpcSession implements Closeable { } private ListenableFuture processPostAttributes(EntityId entityId, TransportProtos.PostAttributeMsg msg, TbMsgMetaData metaData) { + SettableFuture futureToSet = SettableFuture.create(); JsonObject json = JsonUtils.getJsonObject(msg.getKvList()); TbMsg tbMsg = TbMsg.newMsg(SessionMsgType.POST_ATTRIBUTES_REQUEST.name(), entityId, metaData, gson.toJson(json)); - // TODO: voba - verify that null callback is OK - ctx.getTbClusterService().pushMsgToRuleEngine(edge.getTenantId(), tbMsg.getOriginator(), tbMsg, null); - return Futures.immediateFuture(null); + ctx.getTbClusterService().pushMsgToRuleEngine(edge.getTenantId(), tbMsg.getOriginator(), tbMsg, new TbQueueCallback() { + @Override + public void onSuccess(TbQueueMsgMetadata metadata) { + futureToSet.set(null); + } + + @Override + public void onFailure(Throwable t) { + log.error("Can't process post attributes [{}]", msg, t); + futureToSet.setException(t); + } + }); + return futureToSet; + } + + private ListenableFuture processAttributeDeleteMsg(EntityId entityId, AttributeDeleteMsg attributeDeleteMsg, String entityType) { + SettableFuture futureToSet = SettableFuture.create(); + String scope = attributeDeleteMsg.getScope(); + List attributeNames = attributeDeleteMsg.getAttributeNamesList(); + ctx.getAttributesService().removeAll(edge.getTenantId(), entityId, scope, attributeNames); + if (EntityType.DEVICE.name().equals(entityType)) { + Set attributeKeys = new HashSet<>(); + for (String attributeName : attributeNames) { + attributeKeys.add(new AttributeKey(scope, attributeName)); + } + ctx.getTbClusterService().pushMsgToCore(DeviceAttributesEventNotificationMsg.onDelete( + edge.getTenantId(), (DeviceId) entityId, attributeKeys), new TbQueueCallback() { + @Override + public void onSuccess(TbQueueMsgMetadata metadata) { + futureToSet.set(null); + } + + @Override + public void onFailure(Throwable t) { + log.error("Can't process attribute delete msg [{}]", attributeDeleteMsg, t); + futureToSet.setException(t); + } + }); + } + return futureToSet; } private ListenableFuture onDeviceUpdate(DeviceUpdateMsg deviceUpdateMsg) { diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/EntityDataMsgConstructor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/EntityDataMsgConstructor.java index c1d211af58..0f7fb0523d 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/EntityDataMsgConstructor.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/EntityDataMsgConstructor.java @@ -43,9 +43,11 @@ public class EntityDataMsgConstructor { case TIMESERIES_UPDATED: try { JsonObject data = entityData.getAsJsonObject(); - long ts = System.currentTimeMillis(); + long ts; if (data.get("ts") != null && !data.get("ts").isJsonNull()) { - ts = data.getAsJsonObject("ts").getAsLong(); + ts = data.getAsJsonPrimitive("ts").getAsLong(); + } else { + ts = System.currentTimeMillis(); } builder.setPostTelemetryMsg(JsonConverter.convertToTelemetryProto(data.getAsJsonObject("data"), ts)); } catch (Exception e) { diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/RuleChainUpdateMsgConstructor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/RuleChainUpdateMsgConstructor.java index 52e487d973..1d81763a1f 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/RuleChainUpdateMsgConstructor.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/RuleChainUpdateMsgConstructor.java @@ -68,6 +68,8 @@ public class RuleChainUpdateMsgConstructor { .addAllRuleChainConnections(constructRuleChainConnections(ruleChainMetaData.getRuleChainConnections())); if (ruleChainMetaData.getFirstNodeIndex() != null) { builder.setFirstNodeIndex(ruleChainMetaData.getFirstNodeIndex()); + } else { + builder.setFirstNodeIndex(-1); } builder.setMsgType(msgType); return builder.build(); diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/edge/EdgeService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/edge/EdgeService.java index 5c6e5d7559..13702a13ef 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/edge/EdgeService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/edge/EdgeService.java @@ -22,12 +22,11 @@ import org.thingsboard.server.common.data.edge.EdgeSearchQuery; import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.DashboardId; import org.thingsboard.server.common.data.id.EdgeId; +import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.RuleChainId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.TextPageData; 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.util.List; import java.util.Optional; @@ -75,6 +74,8 @@ public interface EdgeService { ListenableFuture> findEdgesByTenantIdAndRuleChainId(TenantId tenantId, RuleChainId ruleChainId); ListenableFuture> findEdgesByTenantIdAndDashboardId(TenantId tenantId, DashboardId dashboardId); + + ListenableFuture> findRelatedEdgeIdsByEntityId(TenantId tenantId, EntityId entityId); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/edge/EdgeServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/edge/EdgeServiceImpl.java index 0cc5c056d8..023c65fd37 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/edge/EdgeServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/edge/EdgeServiceImpl.java @@ -31,18 +31,22 @@ import org.thingsboard.server.common.data.Customer; import org.thingsboard.server.common.data.EntitySubtype; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.Tenant; +import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.edge.Edge; import org.thingsboard.server.common.data.edge.EdgeSearchQuery; import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.DashboardId; import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.data.id.IdBased; import org.thingsboard.server.common.data.id.RuleChainId; import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.id.UserId; import org.thingsboard.server.common.data.page.TextPageData; import org.thingsboard.server.common.data.page.TextPageLink; import org.thingsboard.server.common.data.relation.EntityRelation; import org.thingsboard.server.common.data.relation.EntitySearchDirection; +import org.thingsboard.server.common.data.relation.RelationTypeGroup; import org.thingsboard.server.common.data.rule.RuleChain; import org.thingsboard.server.dao.asset.AssetService; import org.thingsboard.server.dao.customer.CustomerDao; @@ -51,12 +55,14 @@ import org.thingsboard.server.dao.device.DeviceService; import org.thingsboard.server.dao.entity.AbstractEntityService; import org.thingsboard.server.dao.entityview.EntityViewService; import org.thingsboard.server.dao.exception.DataValidationException; +import org.thingsboard.server.dao.model.ModelConstants; import org.thingsboard.server.dao.relation.RelationService; import org.thingsboard.server.dao.rule.RuleChainService; import org.thingsboard.server.dao.service.DataValidator; import org.thingsboard.server.dao.service.PaginatedRemover; import org.thingsboard.server.dao.service.Validator; import org.thingsboard.server.dao.tenant.TenantDao; +import org.thingsboard.server.dao.user.UserService; import javax.annotation.Nullable; import java.util.ArrayList; @@ -92,6 +98,9 @@ public class EdgeServiceImpl extends AbstractEntityService implements EdgeServic @Autowired private CustomerDao customerDao; + @Autowired + private UserService userService; + @Autowired private CacheManager cacheManager; @@ -430,4 +439,47 @@ public class EdgeServiceImpl extends AbstractEntityService implements EdgeServic } }; + @Override + public ListenableFuture> findRelatedEdgeIdsByEntityId(TenantId tenantId, EntityId entityId) { + switch (entityId.getEntityType()) { + case DEVICE: + case ASSET: + case ENTITY_VIEW: + ListenableFuture> originatorEdgeRelationsFuture = + relationService.findByToAndTypeAsync(tenantId, entityId, EntityRelation.CONTAINS_TYPE, RelationTypeGroup.EDGE); + return Futures.transform(originatorEdgeRelationsFuture, originatorEdgeRelations -> { + if (originatorEdgeRelations != null && originatorEdgeRelations.size() > 0) { + return Collections.singletonList(new EdgeId(originatorEdgeRelations.get(0).getFrom().getId())); + } else { + return Collections.emptyList(); + } + }, MoreExecutors.directExecutor()); + case DASHBOARD: + return convertToEdgeIds(findEdgesByTenantIdAndDashboardId(tenantId, new DashboardId(entityId.getId()))); + case RULE_CHAIN: + return convertToEdgeIds(findEdgesByTenantIdAndRuleChainId(tenantId, new RuleChainId(entityId.getId()))); + case USER: + User userById = userService.findUserById(tenantId, new UserId(entityId.getId())); + TextPageData edges; + if (userById.getCustomerId() == null || userById.getCustomerId().isNullUid()) { + edges = findEdgesByTenantId(tenantId, new TextPageLink(Integer.MAX_VALUE)); + } else { + edges = findEdgesByTenantIdAndCustomerId(tenantId, new CustomerId(entityId.getId()), new TextPageLink(Integer.MAX_VALUE)); + } + return convertToEdgeIds(Futures.immediateFuture(edges.getData())); + default: + return Futures.immediateFuture(Collections.emptyList()); + } + } + + private ListenableFuture> convertToEdgeIds(ListenableFuture> future) { + return Futures.transform(future, edges -> { + if (edges != null && !edges.isEmpty()) { + return edges.stream().map(IdBased::getId).collect(Collectors.toList()); + } else { + return Collections.emptyList(); + } + }, MoreExecutors.directExecutor()); + } + } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/edge/TbMsgPushToEdgeNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/edge/TbMsgPushToEdgeNode.java index be265ebc19..1c0e44050d 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/edge/TbMsgPushToEdgeNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/edge/TbMsgPushToEdgeNode.java @@ -232,14 +232,7 @@ public class TbMsgPushToEdgeNode implements TbNode { TextPageData edgesByTenantId = ctx.getEdgeService().findEdgesByTenantId(tenantId, new TextPageLink(Integer.MAX_VALUE)); return Futures.immediateFuture(edgesByTenantId.getData().stream().map(IdBased::getId).collect(Collectors.toList())); } else { - ListenableFuture> future = ctx.getRelationService().findByToAndTypeAsync(tenantId, originatorId, EntityRelation.CONTAINS_TYPE, RelationTypeGroup.EDGE); - return Futures.transform(future, relations -> { - List result = new ArrayList<>(); - if (relations != null && relations.size() > 0) { - result.add(new EdgeId(relations.get(0).getFrom().getId())); - } - return result; - }, ctx.getDbCallbackExecutor()); + return ctx.getEdgeService().findRelatedEdgeIdsByEntityId(tenantId, originatorId); } } diff --git a/ui/src/app/api/dashboard.service.js b/ui/src/app/api/dashboard.service.js index 7280c9d06d..9d59e24ebc 100644 --- a/ui/src/app/api/dashboard.service.js +++ b/ui/src/app/api/dashboard.service.js @@ -284,13 +284,6 @@ function DashboardService($rootScope, $http, $q, $location, $filter) { } dashboard.assignedCustomersText = assignedCustomersTitles.join(', '); } - dashboard.assignedEdgesIds = []; - if (dashboard.assignedEdges && dashboard.assignedEdges.length) { - for (var j = 0; j < dashboard.assignedEdges.length; j++) { - var assignedEdge = dashboard.assignedEdges[j]; - dashboard.assignedEdgesIds.push(assignedEdge.edgeId.id); - } - } return dashboard; } @@ -298,7 +291,6 @@ function DashboardService($rootScope, $http, $q, $location, $filter) { delete dashboard.publicCustomerId; delete dashboard.assignedCustomersText; delete dashboard.assignedCustomersIds; - delete dashboard.assignedEdgesIds; return dashboard; } diff --git a/ui/src/app/customer/customer-fieldset.tpl.html b/ui/src/app/customer/customer-fieldset.tpl.html index 11b2d58fb8..a23959ef96 100644 --- a/ui/src/app/customer/customer-fieldset.tpl.html +++ b/ui/src/app/customer/customer-fieldset.tpl.html @@ -19,6 +19,7 @@ {{ 'customer.manage-assets' | translate }} {{ 'customer.manage-devices' | translate }} {{ 'customer.manage-dashboards' | translate }} +{{ 'customer.manage-edges' | translate }} {{ 'customer.delete' | translate }}
diff --git a/ui/src/app/customer/customer.controller.js b/ui/src/app/customer/customer.controller.js index 42a3801efa..c61962f9f3 100644 --- a/ui/src/app/customer/customer.controller.js +++ b/ui/src/app/customer/customer.controller.js @@ -77,6 +77,20 @@ export default function CustomerController(customerService, $state, $stateParams }, icon: "dashboard" }, + { + onAction: function ($event, item) { + openCustomerEdges($event, item); + }, + name: function() { return $translate.instant('edge.edges') }, + details: function(customer) { + if (customer && customer.additionalInfo && customer.additionalInfo.isPublic) { + return $translate.instant('customer.manage-public-edges') + } else { + return $translate.instant('customer.manage-customer-edges') + } + }, + icon: "router" + }, { onAction: function ($event, item) { vm.grid.deleteItem($event, item); @@ -147,6 +161,7 @@ export default function CustomerController(customerService, $state, $stateParams vm.openCustomerAssets = openCustomerAssets; vm.openCustomerDevices = openCustomerDevices; vm.openCustomerDashboards = openCustomerDashboards; + vm.openCustomerEdges = openCustomerEdges; function deleteCustomerTitle(customer) { return $translate.instant('customer.delete-customer-title', {customerTitle: customer.title}); @@ -216,4 +231,11 @@ export default function CustomerController(customerService, $state, $stateParams $state.go('home.customers.dashboards', {customerId: customer.id.id}); } + function openCustomerEdges($event, customer) { + if ($event) { + $event.stopPropagation(); + } + $state.go('home.customers.edges', {customerId: customer.id.id}); + } + } diff --git a/ui/src/app/customer/customer.directive.js b/ui/src/app/customer/customer.directive.js index ff1befaf9e..33245654bb 100644 --- a/ui/src/app/customer/customer.directive.js +++ b/ui/src/app/customer/customer.directive.js @@ -55,6 +55,7 @@ export default function CustomerDirective($compile, $templateCache, $translate, onManageAssets: '&', onManageDevices: '&', onManageDashboards: '&', + onManageEdges: '&', onDeleteCustomer: '&' } }; diff --git a/ui/src/app/customer/customers.tpl.html b/ui/src/app/customer/customers.tpl.html index 396fc6734b..755425a2ff 100644 --- a/ui/src/app/customer/customers.tpl.html +++ b/ui/src/app/customer/customers.tpl.html @@ -29,6 +29,7 @@ on-manage-assets="vm.openCustomerAssets(event, vm.grid.detailsConfig.currentItem)" on-manage-devices="vm.openCustomerDevices(event, vm.grid.detailsConfig.currentItem)" on-manage-dashboards="vm.openCustomerDashboards(event, vm.grid.detailsConfig.currentItem)" + on-manage-edges="vm.openCustomerEdges(event, vm.grid.detailsConfig.currentItem)" on-delete-customer="vm.grid.deleteItem(event, vm.grid.detailsConfig.currentItem)"> diff --git a/ui/src/app/edge/edge.controller.js b/ui/src/app/edge/edge.controller.js index 7e57fce6a6..94f076c1af 100644 --- a/ui/src/app/edge/edge.controller.js +++ b/ui/src/app/edge/edge.controller.js @@ -552,7 +552,7 @@ export function EdgeController($rootScope, userService, edgeService, customerSer $event.stopPropagation(); } var pageSize = 10; - ruleChainService.getRuleChains({limit: pageSize, textSearch: ''}).then( + ruleChainService.getEdgesRuleChains({limit: pageSize, textSearch: ''}).then( function success(_ruleChains) { var ruleChains = { pageSize: pageSize, diff --git a/ui/src/app/edge/edge.routes.js b/ui/src/app/edge/edge.routes.js index 1afd319609..e3443d1211 100644 --- a/ui/src/app/edge/edge.routes.js +++ b/ui/src/app/edge/edge.routes.js @@ -161,5 +161,28 @@ export default function EdgeRoutes($stateProvider, types) { ncyBreadcrumb: { label: '{"icon": "dashboard", "label": "{{ vm.dashboard.title }}", "translate": "false"}' } + }) + .state('home.customers.edges', { + url: '/:customerId/edges', + params: {'topIndex': 0}, + module: 'private', + auth: ['TENANT_ADMIN'], + views: { + "content@home": { + templateUrl: edgesTemplate, + controllerAs: 'vm', + controller: 'EdgeController' + } + }, + data: { + edgesType: 'customer', + searchEnabled: true, + searchByEntitySubtype: true, + searchEntityType: types.entityType.edge, + pageTitle: 'customer.edges' + }, + ncyBreadcrumb: { + label: '{"icon": "router", "label": "{{ vm.customerEdgesTitle }}", "translate": "false"}' + } }); } diff --git a/ui/src/app/edge/set-root-rule-chain-to-edges.controller.js b/ui/src/app/edge/set-root-rule-chain-to-edges.controller.js index a474fde6a7..a8d134b20e 100644 --- a/ui/src/app/edge/set-root-rule-chain-to-edges.controller.js +++ b/ui/src/app/edge/set-root-rule-chain-to-edges.controller.js @@ -53,7 +53,7 @@ export default function SetRootRuleChainToEdgesController(ruleChainService, edge fetchMoreItems_: function () { if (vm.ruleChains.hasNext && !vm.ruleChains.pending) { vm.ruleChains.pending = true; - ruleChainService.getRuleChains(vm.ruleChains.nextPageLink).then( + ruleChainService.getEdgesRuleChains(vm.ruleChains.nextPageLink).then( function success(ruleChains) { vm.ruleChains.data = vm.ruleChains.data.concat(ruleChains.data); vm.ruleChains.nextPageLink = ruleChains.nextPageLink; diff --git a/ui/src/app/locale/locale.constant-en_US.json b/ui/src/app/locale/locale.constant-en_US.json index f8d1c8568a..a86d4b2ffd 100644 --- a/ui/src/app/locale/locale.constant-en_US.json +++ b/ui/src/app/locale/locale.constant-en_US.json @@ -441,6 +441,7 @@ "manage-assets": "Manage assets", "manage-devices": "Manage devices", "manage-dashboards": "Manage dashboards", + "manage-edges": "Manage edges", "title": "Title", "title-required": "Title is required.", "description": "Description", @@ -812,6 +813,8 @@ "assign-edges-text": "Assign { count, plural, 1 {1 edge} other {# edges} } to customer", "unassign-edge-title": "Are you sure you want to unassign the edge '{{edgeName}}'?", "unassign-edge-text": "After the confirmation the edge will be unassigned and won't be accessible by the customer.", + "unassign-edges-title": "Are you sure you want to unassign { count, plural, 1 {1 edge} other {# edges} }?", + "unassign-edges-text": "After the confirmation all selected edges will be unassigned and won't be accessible by the customer.", "make-public": "Make edge public", "make-public-edge-title": "Are you sure you want to make the edge '{{edgeName}}' public?", "make-public-edge-text": "After the confirmation the edge and all its data will be made public and accessible by others.",