Commit c991ab96f179ec71cb040d5a9dc4040288e1ef0a
Merge branch 'feature/edge' of github.com:volodymyr-babak/thingsboard into feature/edge
Showing
16 changed files
with
171 additions
and
74 deletions
@@ -292,7 +292,7 @@ public class DefaultEdgeNotificationService implements EdgeNotificationService { | @@ -292,7 +292,7 @@ public class DefaultEdgeNotificationService implements EdgeNotificationService { | ||
292 | case ADDED: // used only for USER entity | 292 | case ADDED: // used only for USER entity |
293 | case UPDATED: | 293 | case UPDATED: |
294 | case CREDENTIALS_UPDATED: | 294 | case CREDENTIALS_UPDATED: |
295 | - edgeIdsFuture = findRelatedEdgeIdsByEntityId(tenantId, entityId); | 295 | + edgeIdsFuture = edgeService.findRelatedEdgeIdsByEntityId(tenantId, entityId); |
296 | Futures.addCallback(edgeIdsFuture, new FutureCallback<List<EdgeId>>() { | 296 | Futures.addCallback(edgeIdsFuture, new FutureCallback<List<EdgeId>>() { |
297 | @Override | 297 | @Override |
298 | public void onSuccess(@Nullable List<EdgeId> edgeIds) { | 298 | public void onSuccess(@Nullable List<EdgeId> edgeIds) { |
@@ -310,7 +310,7 @@ public class DefaultEdgeNotificationService implements EdgeNotificationService { | @@ -310,7 +310,7 @@ public class DefaultEdgeNotificationService implements EdgeNotificationService { | ||
310 | break; | 310 | break; |
311 | case ASSIGNED_TO_CUSTOMER: | 311 | case ASSIGNED_TO_CUSTOMER: |
312 | case UNASSIGNED_FROM_CUSTOMER: | 312 | case UNASSIGNED_FROM_CUSTOMER: |
313 | - edgeIdsFuture = findRelatedEdgeIdsByEntityId(tenantId, entityId); | 313 | + edgeIdsFuture = edgeService.findRelatedEdgeIdsByEntityId(tenantId, entityId); |
314 | Futures.addCallback(edgeIdsFuture, new FutureCallback<List<EdgeId>>() { | 314 | Futures.addCallback(edgeIdsFuture, new FutureCallback<List<EdgeId>>() { |
315 | @Override | 315 | @Override |
316 | public void onSuccess(@Nullable List<EdgeId> edgeIds) { | 316 | public void onSuccess(@Nullable List<EdgeId> edgeIds) { |
@@ -408,7 +408,7 @@ public class DefaultEdgeNotificationService implements EdgeNotificationService { | @@ -408,7 +408,7 @@ public class DefaultEdgeNotificationService implements EdgeNotificationService { | ||
408 | if (alarm != null) { | 408 | if (alarm != null) { |
409 | EdgeEventType edgeEventType = getEdgeQueueTypeByEntityType(alarm.getOriginator().getEntityType()); | 409 | EdgeEventType edgeEventType = getEdgeQueueTypeByEntityType(alarm.getOriginator().getEntityType()); |
410 | if (edgeEventType != null) { | 410 | if (edgeEventType != null) { |
411 | - ListenableFuture<List<EdgeId>> relatedEdgeIdsByEntityIdFuture = findRelatedEdgeIdsByEntityId(tenantId, alarm.getOriginator()); | 411 | + ListenableFuture<List<EdgeId>> relatedEdgeIdsByEntityIdFuture = edgeService.findRelatedEdgeIdsByEntityId(tenantId, alarm.getOriginator()); |
412 | Futures.transform(relatedEdgeIdsByEntityIdFuture, relatedEdgeIdsByEntityId -> { | 412 | Futures.transform(relatedEdgeIdsByEntityIdFuture, relatedEdgeIdsByEntityId -> { |
413 | if (relatedEdgeIdsByEntityId != null) { | 413 | if (relatedEdgeIdsByEntityId != null) { |
414 | for (EdgeId edgeId : relatedEdgeIdsByEntityId) { | 414 | for (EdgeId edgeId : relatedEdgeIdsByEntityId) { |
@@ -433,8 +433,8 @@ public class DefaultEdgeNotificationService implements EdgeNotificationService { | @@ -433,8 +433,8 @@ public class DefaultEdgeNotificationService implements EdgeNotificationService { | ||
433 | if (!relation.getFrom().getEntityType().equals(EntityType.EDGE) && | 433 | if (!relation.getFrom().getEntityType().equals(EntityType.EDGE) && |
434 | !relation.getTo().getEntityType().equals(EntityType.EDGE)) { | 434 | !relation.getTo().getEntityType().equals(EntityType.EDGE)) { |
435 | List<ListenableFuture<List<EdgeId>>> futures = new ArrayList<>(); | 435 | List<ListenableFuture<List<EdgeId>>> futures = new ArrayList<>(); |
436 | - futures.add(findRelatedEdgeIdsByEntityId(tenantId, relation.getTo())); | ||
437 | - futures.add(findRelatedEdgeIdsByEntityId(tenantId, relation.getFrom())); | 436 | + futures.add(edgeService.findRelatedEdgeIdsByEntityId(tenantId, relation.getTo())); |
437 | + futures.add(edgeService.findRelatedEdgeIdsByEntityId(tenantId, relation.getFrom())); | ||
438 | ListenableFuture<List<List<EdgeId>>> combinedFuture = Futures.allAsList(futures); | 438 | ListenableFuture<List<List<EdgeId>>> combinedFuture = Futures.allAsList(futures); |
439 | Futures.transform(combinedFuture, listOfListsEdgeIds -> { | 439 | Futures.transform(combinedFuture, listOfListsEdgeIds -> { |
440 | Set<EdgeId> uniqueEdgeIds = new HashSet<>(); | 440 | Set<EdgeId> uniqueEdgeIds = new HashSet<>(); |
@@ -460,48 +460,6 @@ public class DefaultEdgeNotificationService implements EdgeNotificationService { | @@ -460,48 +460,6 @@ public class DefaultEdgeNotificationService implements EdgeNotificationService { | ||
460 | } | 460 | } |
461 | } | 461 | } |
462 | 462 | ||
463 | - private ListenableFuture<List<EdgeId>> findRelatedEdgeIdsByEntityId(TenantId tenantId, EntityId entityId) { | ||
464 | - switch (entityId.getEntityType()) { | ||
465 | - case DEVICE: | ||
466 | - case ASSET: | ||
467 | - case ENTITY_VIEW: | ||
468 | - ListenableFuture<List<EntityRelation>> originatorEdgeRelationsFuture = | ||
469 | - relationService.findByToAndTypeAsync(tenantId, entityId, EntityRelation.CONTAINS_TYPE, RelationTypeGroup.EDGE); | ||
470 | - return Futures.transform(originatorEdgeRelationsFuture, originatorEdgeRelations -> { | ||
471 | - if (originatorEdgeRelations != null && originatorEdgeRelations.size() > 0) { | ||
472 | - return Collections.singletonList(new EdgeId(originatorEdgeRelations.get(0).getFrom().getId())); | ||
473 | - } else { | ||
474 | - return Collections.emptyList(); | ||
475 | - } | ||
476 | - }, dbCallbackExecutorService); | ||
477 | - case DASHBOARD: | ||
478 | - return convertToEdgeIds(edgeService.findEdgesByTenantIdAndDashboardId(tenantId, new DashboardId(entityId.getId()))); | ||
479 | - case RULE_CHAIN: | ||
480 | - return convertToEdgeIds(edgeService.findEdgesByTenantIdAndRuleChainId(tenantId, new RuleChainId(entityId.getId()))); | ||
481 | - case USER: | ||
482 | - User userById = userService.findUserById(tenantId, new UserId(entityId.getId())); | ||
483 | - TextPageData<Edge> edges; | ||
484 | - if (userById.getCustomerId() == null || userById.getCustomerId().isNullUid()) { | ||
485 | - edges = edgeService.findEdgesByTenantId(tenantId, new TextPageLink(Integer.MAX_VALUE)); | ||
486 | - } else { | ||
487 | - edges = edgeService.findEdgesByTenantIdAndCustomerId(tenantId, new CustomerId(entityId.getId()), new TextPageLink(Integer.MAX_VALUE)); | ||
488 | - } | ||
489 | - return convertToEdgeIds(Futures.immediateFuture(edges.getData())); | ||
490 | - default: | ||
491 | - return Futures.immediateFuture(Collections.emptyList()); | ||
492 | - } | ||
493 | - } | ||
494 | - | ||
495 | - private ListenableFuture<List<EdgeId>> convertToEdgeIds(ListenableFuture<List<Edge>> future) { | ||
496 | - return Futures.transform(future, edges -> { | ||
497 | - if (edges != null && !edges.isEmpty()) { | ||
498 | - return edges.stream().map(IdBased::getId).collect(Collectors.toList()); | ||
499 | - } else { | ||
500 | - return Collections.emptyList(); | ||
501 | - } | ||
502 | - }, dbCallbackExecutorService); | ||
503 | - } | ||
504 | - | ||
505 | private EdgeEventType getEdgeQueueTypeByEntityType(EntityType entityType) { | 463 | private EdgeEventType getEdgeQueueTypeByEntityType(EntityType entityType) { |
506 | switch (entityType) { | 464 | switch (entityType) { |
507 | case DEVICE: | 465 | case DEVICE: |
@@ -32,6 +32,7 @@ import lombok.Data; | @@ -32,6 +32,7 @@ import lombok.Data; | ||
32 | import lombok.extern.slf4j.Slf4j; | 32 | import lombok.extern.slf4j.Slf4j; |
33 | import org.apache.commons.lang.RandomStringUtils; | 33 | import org.apache.commons.lang.RandomStringUtils; |
34 | import org.checkerframework.checker.nullness.qual.Nullable; | 34 | import org.checkerframework.checker.nullness.qual.Nullable; |
35 | +import org.thingsboard.rule.engine.api.msg.DeviceAttributesEventNotificationMsg; | ||
35 | import org.thingsboard.server.common.data.AdminSettings; | 36 | import org.thingsboard.server.common.data.AdminSettings; |
36 | import org.thingsboard.server.common.data.Customer; | 37 | import org.thingsboard.server.common.data.Customer; |
37 | import org.thingsboard.server.common.data.Dashboard; | 38 | import org.thingsboard.server.common.data.Dashboard; |
@@ -64,6 +65,7 @@ import org.thingsboard.server.common.data.id.TenantId; | @@ -64,6 +65,7 @@ import org.thingsboard.server.common.data.id.TenantId; | ||
64 | import org.thingsboard.server.common.data.id.UserId; | 65 | import org.thingsboard.server.common.data.id.UserId; |
65 | import org.thingsboard.server.common.data.id.WidgetTypeId; | 66 | import org.thingsboard.server.common.data.id.WidgetTypeId; |
66 | import org.thingsboard.server.common.data.id.WidgetsBundleId; | 67 | import org.thingsboard.server.common.data.id.WidgetsBundleId; |
68 | +import org.thingsboard.server.common.data.kv.AttributeKey; | ||
67 | import org.thingsboard.server.common.data.kv.AttributeKvEntry; | 69 | import org.thingsboard.server.common.data.kv.AttributeKvEntry; |
68 | import org.thingsboard.server.common.data.kv.BaseAttributeKvEntry; | 70 | import org.thingsboard.server.common.data.kv.BaseAttributeKvEntry; |
69 | import org.thingsboard.server.common.data.kv.LongDataEntry; | 71 | import org.thingsboard.server.common.data.kv.LongDataEntry; |
@@ -87,6 +89,7 @@ import org.thingsboard.server.common.transport.util.JsonUtils; | @@ -87,6 +89,7 @@ import org.thingsboard.server.common.transport.util.JsonUtils; | ||
87 | import org.thingsboard.server.gen.edge.AdminSettingsUpdateMsg; | 89 | import org.thingsboard.server.gen.edge.AdminSettingsUpdateMsg; |
88 | import org.thingsboard.server.gen.edge.AlarmUpdateMsg; | 90 | import org.thingsboard.server.gen.edge.AlarmUpdateMsg; |
89 | import org.thingsboard.server.gen.edge.AssetUpdateMsg; | 91 | import org.thingsboard.server.gen.edge.AssetUpdateMsg; |
92 | +import org.thingsboard.server.gen.edge.AttributeDeleteMsg; | ||
90 | import org.thingsboard.server.gen.edge.AttributesRequestMsg; | 93 | import org.thingsboard.server.gen.edge.AttributesRequestMsg; |
91 | import org.thingsboard.server.gen.edge.ConnectRequestMsg; | 94 | import org.thingsboard.server.gen.edge.ConnectRequestMsg; |
92 | import org.thingsboard.server.gen.edge.ConnectResponseCode; | 95 | import org.thingsboard.server.gen.edge.ConnectResponseCode; |
@@ -124,11 +127,12 @@ import org.thingsboard.server.queue.common.TbProtoQueueMsg; | @@ -124,11 +127,12 @@ import org.thingsboard.server.queue.common.TbProtoQueueMsg; | ||
124 | import org.thingsboard.server.service.edge.EdgeContextComponent; | 127 | import org.thingsboard.server.service.edge.EdgeContextComponent; |
125 | 128 | ||
126 | import java.io.Closeable; | 129 | import java.io.Closeable; |
127 | -import java.io.IOException; | ||
128 | import java.util.ArrayList; | 130 | import java.util.ArrayList; |
129 | import java.util.Collections; | 131 | import java.util.Collections; |
132 | +import java.util.HashSet; | ||
130 | import java.util.List; | 133 | import java.util.List; |
131 | import java.util.Optional; | 134 | import java.util.Optional; |
135 | +import java.util.Set; | ||
132 | import java.util.UUID; | 136 | import java.util.UUID; |
133 | import java.util.concurrent.CountDownLatch; | 137 | import java.util.concurrent.CountDownLatch; |
134 | import java.util.concurrent.ExecutionException; | 138 | import java.util.concurrent.ExecutionException; |
@@ -387,7 +391,7 @@ public final class EdgeGrpcSession implements Closeable { | @@ -387,7 +391,7 @@ public final class EdgeGrpcSession implements Closeable { | ||
387 | ctx.getAttributesService().save(edge.getTenantId(), edge.getId(), DataConstants.SERVER_SCOPE, attributes); | 391 | ctx.getAttributesService().save(edge.getTenantId(), edge.getId(), DataConstants.SERVER_SCOPE, attributes); |
388 | } | 392 | } |
389 | 393 | ||
390 | - private DownlinkMsg processTelemetryMessage(EdgeEvent edgeEvent) throws IOException { | 394 | + private DownlinkMsg processTelemetryMessage(EdgeEvent edgeEvent) { |
391 | log.trace("Executing processTelemetryMessage, edgeEvent [{}]", edgeEvent); | 395 | log.trace("Executing processTelemetryMessage, edgeEvent [{}]", edgeEvent); |
392 | EntityId entityId = null; | 396 | EntityId entityId = null; |
393 | switch (edgeEvent.getEdgeEventType()) { | 397 | switch (edgeEvent.getEdgeEventType()) { |
@@ -840,6 +844,9 @@ public final class EdgeGrpcSession implements Closeable { | @@ -840,6 +844,9 @@ public final class EdgeGrpcSession implements Closeable { | ||
840 | result.add(processPostTelemetry(entityId, entityData.getPostTelemetryMsg(), metaData)); | 844 | result.add(processPostTelemetry(entityId, entityData.getPostTelemetryMsg(), metaData)); |
841 | } | 845 | } |
842 | } | 846 | } |
847 | + if (entityData.hasAttributeDeleteMsg()) { | ||
848 | + result.add(processAttributeDeleteMsg(entityId, entityData.getAttributeDeleteMsg(), entityData.getEntityType())); | ||
849 | + } | ||
843 | } | 850 | } |
844 | } | 851 | } |
845 | 852 | ||
@@ -962,6 +969,7 @@ public final class EdgeGrpcSession implements Closeable { | @@ -962,6 +969,7 @@ public final class EdgeGrpcSession implements Closeable { | ||
962 | 969 | ||
963 | @Override | 970 | @Override |
964 | public void onFailure(Throwable t) { | 971 | public void onFailure(Throwable t) { |
972 | + log.error("Can't process post telemetry [{}]", msg, t); | ||
965 | futureToSet.setException(t); | 973 | futureToSet.setException(t); |
966 | } | 974 | } |
967 | }); | 975 | }); |
@@ -970,11 +978,49 @@ public final class EdgeGrpcSession implements Closeable { | @@ -970,11 +978,49 @@ public final class EdgeGrpcSession implements Closeable { | ||
970 | } | 978 | } |
971 | 979 | ||
972 | private ListenableFuture<Void> processPostAttributes(EntityId entityId, TransportProtos.PostAttributeMsg msg, TbMsgMetaData metaData) { | 980 | private ListenableFuture<Void> processPostAttributes(EntityId entityId, TransportProtos.PostAttributeMsg msg, TbMsgMetaData metaData) { |
981 | + SettableFuture<Void> futureToSet = SettableFuture.create(); | ||
973 | JsonObject json = JsonUtils.getJsonObject(msg.getKvList()); | 982 | JsonObject json = JsonUtils.getJsonObject(msg.getKvList()); |
974 | TbMsg tbMsg = TbMsg.newMsg(SessionMsgType.POST_ATTRIBUTES_REQUEST.name(), entityId, metaData, gson.toJson(json)); | 983 | TbMsg tbMsg = TbMsg.newMsg(SessionMsgType.POST_ATTRIBUTES_REQUEST.name(), entityId, metaData, gson.toJson(json)); |
975 | - // TODO: voba - verify that null callback is OK | ||
976 | - ctx.getTbClusterService().pushMsgToRuleEngine(edge.getTenantId(), tbMsg.getOriginator(), tbMsg, null); | ||
977 | - return Futures.immediateFuture(null); | 984 | + ctx.getTbClusterService().pushMsgToRuleEngine(edge.getTenantId(), tbMsg.getOriginator(), tbMsg, new TbQueueCallback() { |
985 | + @Override | ||
986 | + public void onSuccess(TbQueueMsgMetadata metadata) { | ||
987 | + futureToSet.set(null); | ||
988 | + } | ||
989 | + | ||
990 | + @Override | ||
991 | + public void onFailure(Throwable t) { | ||
992 | + log.error("Can't process post attributes [{}]", msg, t); | ||
993 | + futureToSet.setException(t); | ||
994 | + } | ||
995 | + }); | ||
996 | + return futureToSet; | ||
997 | + } | ||
998 | + | ||
999 | + private ListenableFuture<Void> processAttributeDeleteMsg(EntityId entityId, AttributeDeleteMsg attributeDeleteMsg, String entityType) { | ||
1000 | + SettableFuture<Void> futureToSet = SettableFuture.create(); | ||
1001 | + String scope = attributeDeleteMsg.getScope(); | ||
1002 | + List<String> attributeNames = attributeDeleteMsg.getAttributeNamesList(); | ||
1003 | + ctx.getAttributesService().removeAll(edge.getTenantId(), entityId, scope, attributeNames); | ||
1004 | + if (EntityType.DEVICE.name().equals(entityType)) { | ||
1005 | + Set<AttributeKey> attributeKeys = new HashSet<>(); | ||
1006 | + for (String attributeName : attributeNames) { | ||
1007 | + attributeKeys.add(new AttributeKey(scope, attributeName)); | ||
1008 | + } | ||
1009 | + ctx.getTbClusterService().pushMsgToCore(DeviceAttributesEventNotificationMsg.onDelete( | ||
1010 | + edge.getTenantId(), (DeviceId) entityId, attributeKeys), new TbQueueCallback() { | ||
1011 | + @Override | ||
1012 | + public void onSuccess(TbQueueMsgMetadata metadata) { | ||
1013 | + futureToSet.set(null); | ||
1014 | + } | ||
1015 | + | ||
1016 | + @Override | ||
1017 | + public void onFailure(Throwable t) { | ||
1018 | + log.error("Can't process attribute delete msg [{}]", attributeDeleteMsg, t); | ||
1019 | + futureToSet.setException(t); | ||
1020 | + } | ||
1021 | + }); | ||
1022 | + } | ||
1023 | + return futureToSet; | ||
978 | } | 1024 | } |
979 | 1025 | ||
980 | private ListenableFuture<Void> onDeviceUpdate(DeviceUpdateMsg deviceUpdateMsg) { | 1026 | private ListenableFuture<Void> onDeviceUpdate(DeviceUpdateMsg deviceUpdateMsg) { |
@@ -43,9 +43,11 @@ public class EntityDataMsgConstructor { | @@ -43,9 +43,11 @@ public class EntityDataMsgConstructor { | ||
43 | case TIMESERIES_UPDATED: | 43 | case TIMESERIES_UPDATED: |
44 | try { | 44 | try { |
45 | JsonObject data = entityData.getAsJsonObject(); | 45 | JsonObject data = entityData.getAsJsonObject(); |
46 | - long ts = System.currentTimeMillis(); | 46 | + long ts; |
47 | if (data.get("ts") != null && !data.get("ts").isJsonNull()) { | 47 | if (data.get("ts") != null && !data.get("ts").isJsonNull()) { |
48 | - ts = data.getAsJsonObject("ts").getAsLong(); | 48 | + ts = data.getAsJsonPrimitive("ts").getAsLong(); |
49 | + } else { | ||
50 | + ts = System.currentTimeMillis(); | ||
49 | } | 51 | } |
50 | builder.setPostTelemetryMsg(JsonConverter.convertToTelemetryProto(data.getAsJsonObject("data"), ts)); | 52 | builder.setPostTelemetryMsg(JsonConverter.convertToTelemetryProto(data.getAsJsonObject("data"), ts)); |
51 | } catch (Exception e) { | 53 | } catch (Exception e) { |
@@ -68,6 +68,8 @@ public class RuleChainUpdateMsgConstructor { | @@ -68,6 +68,8 @@ public class RuleChainUpdateMsgConstructor { | ||
68 | .addAllRuleChainConnections(constructRuleChainConnections(ruleChainMetaData.getRuleChainConnections())); | 68 | .addAllRuleChainConnections(constructRuleChainConnections(ruleChainMetaData.getRuleChainConnections())); |
69 | if (ruleChainMetaData.getFirstNodeIndex() != null) { | 69 | if (ruleChainMetaData.getFirstNodeIndex() != null) { |
70 | builder.setFirstNodeIndex(ruleChainMetaData.getFirstNodeIndex()); | 70 | builder.setFirstNodeIndex(ruleChainMetaData.getFirstNodeIndex()); |
71 | + } else { | ||
72 | + builder.setFirstNodeIndex(-1); | ||
71 | } | 73 | } |
72 | builder.setMsgType(msgType); | 74 | builder.setMsgType(msgType); |
73 | return builder.build(); | 75 | return builder.build(); |
@@ -22,12 +22,11 @@ import org.thingsboard.server.common.data.edge.EdgeSearchQuery; | @@ -22,12 +22,11 @@ import org.thingsboard.server.common.data.edge.EdgeSearchQuery; | ||
22 | import org.thingsboard.server.common.data.id.CustomerId; | 22 | import org.thingsboard.server.common.data.id.CustomerId; |
23 | import org.thingsboard.server.common.data.id.DashboardId; | 23 | import org.thingsboard.server.common.data.id.DashboardId; |
24 | import org.thingsboard.server.common.data.id.EdgeId; | 24 | import org.thingsboard.server.common.data.id.EdgeId; |
25 | +import org.thingsboard.server.common.data.id.EntityId; | ||
25 | import org.thingsboard.server.common.data.id.RuleChainId; | 26 | import org.thingsboard.server.common.data.id.RuleChainId; |
26 | import org.thingsboard.server.common.data.id.TenantId; | 27 | import org.thingsboard.server.common.data.id.TenantId; |
27 | import org.thingsboard.server.common.data.page.TextPageData; | 28 | import org.thingsboard.server.common.data.page.TextPageData; |
28 | import org.thingsboard.server.common.data.page.TextPageLink; | 29 | import org.thingsboard.server.common.data.page.TextPageLink; |
29 | -import org.thingsboard.server.common.data.page.TimePageData; | ||
30 | -import org.thingsboard.server.common.data.page.TimePageLink; | ||
31 | 30 | ||
32 | import java.util.List; | 31 | import java.util.List; |
33 | import java.util.Optional; | 32 | import java.util.Optional; |
@@ -75,6 +74,8 @@ public interface EdgeService { | @@ -75,6 +74,8 @@ public interface EdgeService { | ||
75 | ListenableFuture<List<Edge>> findEdgesByTenantIdAndRuleChainId(TenantId tenantId, RuleChainId ruleChainId); | 74 | ListenableFuture<List<Edge>> findEdgesByTenantIdAndRuleChainId(TenantId tenantId, RuleChainId ruleChainId); |
76 | 75 | ||
77 | ListenableFuture<List<Edge>> findEdgesByTenantIdAndDashboardId(TenantId tenantId, DashboardId dashboardId); | 76 | ListenableFuture<List<Edge>> findEdgesByTenantIdAndDashboardId(TenantId tenantId, DashboardId dashboardId); |
77 | + | ||
78 | + ListenableFuture<List<EdgeId>> findRelatedEdgeIdsByEntityId(TenantId tenantId, EntityId entityId); | ||
78 | } | 79 | } |
79 | 80 | ||
80 | 81 |
@@ -31,18 +31,22 @@ import org.thingsboard.server.common.data.Customer; | @@ -31,18 +31,22 @@ import org.thingsboard.server.common.data.Customer; | ||
31 | import org.thingsboard.server.common.data.EntitySubtype; | 31 | import org.thingsboard.server.common.data.EntitySubtype; |
32 | import org.thingsboard.server.common.data.EntityType; | 32 | import org.thingsboard.server.common.data.EntityType; |
33 | import org.thingsboard.server.common.data.Tenant; | 33 | import org.thingsboard.server.common.data.Tenant; |
34 | +import org.thingsboard.server.common.data.User; | ||
34 | import org.thingsboard.server.common.data.edge.Edge; | 35 | import org.thingsboard.server.common.data.edge.Edge; |
35 | import org.thingsboard.server.common.data.edge.EdgeSearchQuery; | 36 | import org.thingsboard.server.common.data.edge.EdgeSearchQuery; |
36 | import org.thingsboard.server.common.data.id.CustomerId; | 37 | import org.thingsboard.server.common.data.id.CustomerId; |
37 | import org.thingsboard.server.common.data.id.DashboardId; | 38 | import org.thingsboard.server.common.data.id.DashboardId; |
38 | import org.thingsboard.server.common.data.id.EdgeId; | 39 | import org.thingsboard.server.common.data.id.EdgeId; |
39 | import org.thingsboard.server.common.data.id.EntityId; | 40 | import org.thingsboard.server.common.data.id.EntityId; |
41 | +import org.thingsboard.server.common.data.id.IdBased; | ||
40 | import org.thingsboard.server.common.data.id.RuleChainId; | 42 | import org.thingsboard.server.common.data.id.RuleChainId; |
41 | import org.thingsboard.server.common.data.id.TenantId; | 43 | import org.thingsboard.server.common.data.id.TenantId; |
44 | +import org.thingsboard.server.common.data.id.UserId; | ||
42 | import org.thingsboard.server.common.data.page.TextPageData; | 45 | import org.thingsboard.server.common.data.page.TextPageData; |
43 | import org.thingsboard.server.common.data.page.TextPageLink; | 46 | import org.thingsboard.server.common.data.page.TextPageLink; |
44 | import org.thingsboard.server.common.data.relation.EntityRelation; | 47 | import org.thingsboard.server.common.data.relation.EntityRelation; |
45 | import org.thingsboard.server.common.data.relation.EntitySearchDirection; | 48 | import org.thingsboard.server.common.data.relation.EntitySearchDirection; |
49 | +import org.thingsboard.server.common.data.relation.RelationTypeGroup; | ||
46 | import org.thingsboard.server.common.data.rule.RuleChain; | 50 | import org.thingsboard.server.common.data.rule.RuleChain; |
47 | import org.thingsboard.server.dao.asset.AssetService; | 51 | import org.thingsboard.server.dao.asset.AssetService; |
48 | import org.thingsboard.server.dao.customer.CustomerDao; | 52 | import org.thingsboard.server.dao.customer.CustomerDao; |
@@ -51,12 +55,14 @@ import org.thingsboard.server.dao.device.DeviceService; | @@ -51,12 +55,14 @@ import org.thingsboard.server.dao.device.DeviceService; | ||
51 | import org.thingsboard.server.dao.entity.AbstractEntityService; | 55 | import org.thingsboard.server.dao.entity.AbstractEntityService; |
52 | import org.thingsboard.server.dao.entityview.EntityViewService; | 56 | import org.thingsboard.server.dao.entityview.EntityViewService; |
53 | import org.thingsboard.server.dao.exception.DataValidationException; | 57 | import org.thingsboard.server.dao.exception.DataValidationException; |
58 | +import org.thingsboard.server.dao.model.ModelConstants; | ||
54 | import org.thingsboard.server.dao.relation.RelationService; | 59 | import org.thingsboard.server.dao.relation.RelationService; |
55 | import org.thingsboard.server.dao.rule.RuleChainService; | 60 | import org.thingsboard.server.dao.rule.RuleChainService; |
56 | import org.thingsboard.server.dao.service.DataValidator; | 61 | import org.thingsboard.server.dao.service.DataValidator; |
57 | import org.thingsboard.server.dao.service.PaginatedRemover; | 62 | import org.thingsboard.server.dao.service.PaginatedRemover; |
58 | import org.thingsboard.server.dao.service.Validator; | 63 | import org.thingsboard.server.dao.service.Validator; |
59 | import org.thingsboard.server.dao.tenant.TenantDao; | 64 | import org.thingsboard.server.dao.tenant.TenantDao; |
65 | +import org.thingsboard.server.dao.user.UserService; | ||
60 | 66 | ||
61 | import javax.annotation.Nullable; | 67 | import javax.annotation.Nullable; |
62 | import java.util.ArrayList; | 68 | import java.util.ArrayList; |
@@ -93,6 +99,9 @@ public class EdgeServiceImpl extends AbstractEntityService implements EdgeServic | @@ -93,6 +99,9 @@ public class EdgeServiceImpl extends AbstractEntityService implements EdgeServic | ||
93 | private CustomerDao customerDao; | 99 | private CustomerDao customerDao; |
94 | 100 | ||
95 | @Autowired | 101 | @Autowired |
102 | + private UserService userService; | ||
103 | + | ||
104 | + @Autowired | ||
96 | private CacheManager cacheManager; | 105 | private CacheManager cacheManager; |
97 | 106 | ||
98 | @Autowired | 107 | @Autowired |
@@ -430,4 +439,47 @@ public class EdgeServiceImpl extends AbstractEntityService implements EdgeServic | @@ -430,4 +439,47 @@ public class EdgeServiceImpl extends AbstractEntityService implements EdgeServic | ||
430 | } | 439 | } |
431 | }; | 440 | }; |
432 | 441 | ||
442 | + @Override | ||
443 | + public ListenableFuture<List<EdgeId>> findRelatedEdgeIdsByEntityId(TenantId tenantId, EntityId entityId) { | ||
444 | + switch (entityId.getEntityType()) { | ||
445 | + case DEVICE: | ||
446 | + case ASSET: | ||
447 | + case ENTITY_VIEW: | ||
448 | + ListenableFuture<List<EntityRelation>> originatorEdgeRelationsFuture = | ||
449 | + relationService.findByToAndTypeAsync(tenantId, entityId, EntityRelation.CONTAINS_TYPE, RelationTypeGroup.EDGE); | ||
450 | + return Futures.transform(originatorEdgeRelationsFuture, originatorEdgeRelations -> { | ||
451 | + if (originatorEdgeRelations != null && originatorEdgeRelations.size() > 0) { | ||
452 | + return Collections.singletonList(new EdgeId(originatorEdgeRelations.get(0).getFrom().getId())); | ||
453 | + } else { | ||
454 | + return Collections.emptyList(); | ||
455 | + } | ||
456 | + }, MoreExecutors.directExecutor()); | ||
457 | + case DASHBOARD: | ||
458 | + return convertToEdgeIds(findEdgesByTenantIdAndDashboardId(tenantId, new DashboardId(entityId.getId()))); | ||
459 | + case RULE_CHAIN: | ||
460 | + return convertToEdgeIds(findEdgesByTenantIdAndRuleChainId(tenantId, new RuleChainId(entityId.getId()))); | ||
461 | + case USER: | ||
462 | + User userById = userService.findUserById(tenantId, new UserId(entityId.getId())); | ||
463 | + TextPageData<Edge> edges; | ||
464 | + if (userById.getCustomerId() == null || userById.getCustomerId().isNullUid()) { | ||
465 | + edges = findEdgesByTenantId(tenantId, new TextPageLink(Integer.MAX_VALUE)); | ||
466 | + } else { | ||
467 | + edges = findEdgesByTenantIdAndCustomerId(tenantId, new CustomerId(entityId.getId()), new TextPageLink(Integer.MAX_VALUE)); | ||
468 | + } | ||
469 | + return convertToEdgeIds(Futures.immediateFuture(edges.getData())); | ||
470 | + default: | ||
471 | + return Futures.immediateFuture(Collections.emptyList()); | ||
472 | + } | ||
473 | + } | ||
474 | + | ||
475 | + private ListenableFuture<List<EdgeId>> convertToEdgeIds(ListenableFuture<List<Edge>> future) { | ||
476 | + return Futures.transform(future, edges -> { | ||
477 | + if (edges != null && !edges.isEmpty()) { | ||
478 | + return edges.stream().map(IdBased::getId).collect(Collectors.toList()); | ||
479 | + } else { | ||
480 | + return Collections.emptyList(); | ||
481 | + } | ||
482 | + }, MoreExecutors.directExecutor()); | ||
483 | + } | ||
484 | + | ||
433 | } | 485 | } |
@@ -232,14 +232,7 @@ public class TbMsgPushToEdgeNode implements TbNode { | @@ -232,14 +232,7 @@ public class TbMsgPushToEdgeNode implements TbNode { | ||
232 | TextPageData<Edge> edgesByTenantId = ctx.getEdgeService().findEdgesByTenantId(tenantId, new TextPageLink(Integer.MAX_VALUE)); | 232 | TextPageData<Edge> edgesByTenantId = ctx.getEdgeService().findEdgesByTenantId(tenantId, new TextPageLink(Integer.MAX_VALUE)); |
233 | return Futures.immediateFuture(edgesByTenantId.getData().stream().map(IdBased::getId).collect(Collectors.toList())); | 233 | return Futures.immediateFuture(edgesByTenantId.getData().stream().map(IdBased::getId).collect(Collectors.toList())); |
234 | } else { | 234 | } else { |
235 | - ListenableFuture<List<EntityRelation>> future = ctx.getRelationService().findByToAndTypeAsync(tenantId, originatorId, EntityRelation.CONTAINS_TYPE, RelationTypeGroup.EDGE); | ||
236 | - return Futures.transform(future, relations -> { | ||
237 | - List<EdgeId> result = new ArrayList<>(); | ||
238 | - if (relations != null && relations.size() > 0) { | ||
239 | - result.add(new EdgeId(relations.get(0).getFrom().getId())); | ||
240 | - } | ||
241 | - return result; | ||
242 | - }, ctx.getDbCallbackExecutor()); | 235 | + return ctx.getEdgeService().findRelatedEdgeIdsByEntityId(tenantId, originatorId); |
243 | } | 236 | } |
244 | } | 237 | } |
245 | 238 |
@@ -284,13 +284,6 @@ function DashboardService($rootScope, $http, $q, $location, $filter) { | @@ -284,13 +284,6 @@ function DashboardService($rootScope, $http, $q, $location, $filter) { | ||
284 | } | 284 | } |
285 | dashboard.assignedCustomersText = assignedCustomersTitles.join(', '); | 285 | dashboard.assignedCustomersText = assignedCustomersTitles.join(', '); |
286 | } | 286 | } |
287 | - dashboard.assignedEdgesIds = []; | ||
288 | - if (dashboard.assignedEdges && dashboard.assignedEdges.length) { | ||
289 | - for (var j = 0; j < dashboard.assignedEdges.length; j++) { | ||
290 | - var assignedEdge = dashboard.assignedEdges[j]; | ||
291 | - dashboard.assignedEdgesIds.push(assignedEdge.edgeId.id); | ||
292 | - } | ||
293 | - } | ||
294 | return dashboard; | 287 | return dashboard; |
295 | } | 288 | } |
296 | 289 | ||
@@ -298,7 +291,6 @@ function DashboardService($rootScope, $http, $q, $location, $filter) { | @@ -298,7 +291,6 @@ function DashboardService($rootScope, $http, $q, $location, $filter) { | ||
298 | delete dashboard.publicCustomerId; | 291 | delete dashboard.publicCustomerId; |
299 | delete dashboard.assignedCustomersText; | 292 | delete dashboard.assignedCustomersText; |
300 | delete dashboard.assignedCustomersIds; | 293 | delete dashboard.assignedCustomersIds; |
301 | - delete dashboard.assignedEdgesIds; | ||
302 | return dashboard; | 294 | return dashboard; |
303 | } | 295 | } |
304 | 296 |
@@ -19,6 +19,7 @@ | @@ -19,6 +19,7 @@ | ||
19 | <md-button ng-click="onManageAssets({event: $event})" ng-show="!isEdit && !isPublic" class="md-raised md-primary">{{ 'customer.manage-assets' | translate }}</md-button> | 19 | <md-button ng-click="onManageAssets({event: $event})" ng-show="!isEdit && !isPublic" class="md-raised md-primary">{{ 'customer.manage-assets' | translate }}</md-button> |
20 | <md-button ng-click="onManageDevices({event: $event})" ng-show="!isEdit" class="md-raised md-primary">{{ 'customer.manage-devices' | translate }}</md-button> | 20 | <md-button ng-click="onManageDevices({event: $event})" ng-show="!isEdit" class="md-raised md-primary">{{ 'customer.manage-devices' | translate }}</md-button> |
21 | <md-button ng-click="onManageDashboards({event: $event})" ng-show="!isEdit" class="md-raised md-primary">{{ 'customer.manage-dashboards' | translate }}</md-button> | 21 | <md-button ng-click="onManageDashboards({event: $event})" ng-show="!isEdit" class="md-raised md-primary">{{ 'customer.manage-dashboards' | translate }}</md-button> |
22 | +<md-button ng-click="onManageEdges({event: $event})" ng-show="!isEdit && !isPublic" class="md-raised md-primary">{{ 'customer.manage-edges' | translate }}</md-button> | ||
22 | <md-button ng-click="onDeleteCustomer({event: $event})" ng-show="!isEdit && !isPublic" class="md-raised md-primary">{{ 'customer.delete' | translate }}</md-button> | 23 | <md-button ng-click="onDeleteCustomer({event: $event})" ng-show="!isEdit && !isPublic" class="md-raised md-primary">{{ 'customer.delete' | translate }}</md-button> |
23 | 24 | ||
24 | <div layout="row"> | 25 | <div layout="row"> |
@@ -79,6 +79,20 @@ export default function CustomerController(customerService, $state, $stateParams | @@ -79,6 +79,20 @@ export default function CustomerController(customerService, $state, $stateParams | ||
79 | }, | 79 | }, |
80 | { | 80 | { |
81 | onAction: function ($event, item) { | 81 | onAction: function ($event, item) { |
82 | + openCustomerEdges($event, item); | ||
83 | + }, | ||
84 | + name: function() { return $translate.instant('edge.edges') }, | ||
85 | + details: function(customer) { | ||
86 | + if (customer && customer.additionalInfo && customer.additionalInfo.isPublic) { | ||
87 | + return $translate.instant('customer.manage-public-edges') | ||
88 | + } else { | ||
89 | + return $translate.instant('customer.manage-customer-edges') | ||
90 | + } | ||
91 | + }, | ||
92 | + icon: "router" | ||
93 | + }, | ||
94 | + { | ||
95 | + onAction: function ($event, item) { | ||
82 | vm.grid.deleteItem($event, item); | 96 | vm.grid.deleteItem($event, item); |
83 | }, | 97 | }, |
84 | name: function() { return $translate.instant('action.delete') }, | 98 | name: function() { return $translate.instant('action.delete') }, |
@@ -147,6 +161,7 @@ export default function CustomerController(customerService, $state, $stateParams | @@ -147,6 +161,7 @@ export default function CustomerController(customerService, $state, $stateParams | ||
147 | vm.openCustomerAssets = openCustomerAssets; | 161 | vm.openCustomerAssets = openCustomerAssets; |
148 | vm.openCustomerDevices = openCustomerDevices; | 162 | vm.openCustomerDevices = openCustomerDevices; |
149 | vm.openCustomerDashboards = openCustomerDashboards; | 163 | vm.openCustomerDashboards = openCustomerDashboards; |
164 | + vm.openCustomerEdges = openCustomerEdges; | ||
150 | 165 | ||
151 | function deleteCustomerTitle(customer) { | 166 | function deleteCustomerTitle(customer) { |
152 | return $translate.instant('customer.delete-customer-title', {customerTitle: customer.title}); | 167 | return $translate.instant('customer.delete-customer-title', {customerTitle: customer.title}); |
@@ -216,4 +231,11 @@ export default function CustomerController(customerService, $state, $stateParams | @@ -216,4 +231,11 @@ export default function CustomerController(customerService, $state, $stateParams | ||
216 | $state.go('home.customers.dashboards', {customerId: customer.id.id}); | 231 | $state.go('home.customers.dashboards', {customerId: customer.id.id}); |
217 | } | 232 | } |
218 | 233 | ||
234 | + function openCustomerEdges($event, customer) { | ||
235 | + if ($event) { | ||
236 | + $event.stopPropagation(); | ||
237 | + } | ||
238 | + $state.go('home.customers.edges', {customerId: customer.id.id}); | ||
239 | + } | ||
240 | + | ||
219 | } | 241 | } |
@@ -55,6 +55,7 @@ export default function CustomerDirective($compile, $templateCache, $translate, | @@ -55,6 +55,7 @@ export default function CustomerDirective($compile, $templateCache, $translate, | ||
55 | onManageAssets: '&', | 55 | onManageAssets: '&', |
56 | onManageDevices: '&', | 56 | onManageDevices: '&', |
57 | onManageDashboards: '&', | 57 | onManageDashboards: '&', |
58 | + onManageEdges: '&', | ||
58 | onDeleteCustomer: '&' | 59 | onDeleteCustomer: '&' |
59 | } | 60 | } |
60 | }; | 61 | }; |
@@ -29,6 +29,7 @@ | @@ -29,6 +29,7 @@ | ||
29 | on-manage-assets="vm.openCustomerAssets(event, vm.grid.detailsConfig.currentItem)" | 29 | on-manage-assets="vm.openCustomerAssets(event, vm.grid.detailsConfig.currentItem)" |
30 | on-manage-devices="vm.openCustomerDevices(event, vm.grid.detailsConfig.currentItem)" | 30 | on-manage-devices="vm.openCustomerDevices(event, vm.grid.detailsConfig.currentItem)" |
31 | on-manage-dashboards="vm.openCustomerDashboards(event, vm.grid.detailsConfig.currentItem)" | 31 | on-manage-dashboards="vm.openCustomerDashboards(event, vm.grid.detailsConfig.currentItem)" |
32 | + on-manage-edges="vm.openCustomerEdges(event, vm.grid.detailsConfig.currentItem)" | ||
32 | on-delete-customer="vm.grid.deleteItem(event, vm.grid.detailsConfig.currentItem)"></tb-customer> | 33 | on-delete-customer="vm.grid.deleteItem(event, vm.grid.detailsConfig.currentItem)"></tb-customer> |
33 | </md-tab> | 34 | </md-tab> |
34 | <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode" md-on-select="vm.grid.triggerResize()" label="{{ 'attribute.attributes' | translate }}"> | 35 | <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode" md-on-select="vm.grid.triggerResize()" label="{{ 'attribute.attributes' | translate }}"> |
@@ -552,7 +552,7 @@ export function EdgeController($rootScope, userService, edgeService, customerSer | @@ -552,7 +552,7 @@ export function EdgeController($rootScope, userService, edgeService, customerSer | ||
552 | $event.stopPropagation(); | 552 | $event.stopPropagation(); |
553 | } | 553 | } |
554 | var pageSize = 10; | 554 | var pageSize = 10; |
555 | - ruleChainService.getRuleChains({limit: pageSize, textSearch: ''}).then( | 555 | + ruleChainService.getEdgesRuleChains({limit: pageSize, textSearch: ''}).then( |
556 | function success(_ruleChains) { | 556 | function success(_ruleChains) { |
557 | var ruleChains = { | 557 | var ruleChains = { |
558 | pageSize: pageSize, | 558 | pageSize: pageSize, |
@@ -161,5 +161,28 @@ export default function EdgeRoutes($stateProvider, types) { | @@ -161,5 +161,28 @@ export default function EdgeRoutes($stateProvider, types) { | ||
161 | ncyBreadcrumb: { | 161 | ncyBreadcrumb: { |
162 | label: '{"icon": "dashboard", "label": "{{ vm.dashboard.title }}", "translate": "false"}' | 162 | label: '{"icon": "dashboard", "label": "{{ vm.dashboard.title }}", "translate": "false"}' |
163 | } | 163 | } |
164 | + }) | ||
165 | + .state('home.customers.edges', { | ||
166 | + url: '/:customerId/edges', | ||
167 | + params: {'topIndex': 0}, | ||
168 | + module: 'private', | ||
169 | + auth: ['TENANT_ADMIN'], | ||
170 | + views: { | ||
171 | + "content@home": { | ||
172 | + templateUrl: edgesTemplate, | ||
173 | + controllerAs: 'vm', | ||
174 | + controller: 'EdgeController' | ||
175 | + } | ||
176 | + }, | ||
177 | + data: { | ||
178 | + edgesType: 'customer', | ||
179 | + searchEnabled: true, | ||
180 | + searchByEntitySubtype: true, | ||
181 | + searchEntityType: types.entityType.edge, | ||
182 | + pageTitle: 'customer.edges' | ||
183 | + }, | ||
184 | + ncyBreadcrumb: { | ||
185 | + label: '{"icon": "router", "label": "{{ vm.customerEdgesTitle }}", "translate": "false"}' | ||
186 | + } | ||
164 | }); | 187 | }); |
165 | } | 188 | } |
@@ -53,7 +53,7 @@ export default function SetRootRuleChainToEdgesController(ruleChainService, edge | @@ -53,7 +53,7 @@ export default function SetRootRuleChainToEdgesController(ruleChainService, edge | ||
53 | fetchMoreItems_: function () { | 53 | fetchMoreItems_: function () { |
54 | if (vm.ruleChains.hasNext && !vm.ruleChains.pending) { | 54 | if (vm.ruleChains.hasNext && !vm.ruleChains.pending) { |
55 | vm.ruleChains.pending = true; | 55 | vm.ruleChains.pending = true; |
56 | - ruleChainService.getRuleChains(vm.ruleChains.nextPageLink).then( | 56 | + ruleChainService.getEdgesRuleChains(vm.ruleChains.nextPageLink).then( |
57 | function success(ruleChains) { | 57 | function success(ruleChains) { |
58 | vm.ruleChains.data = vm.ruleChains.data.concat(ruleChains.data); | 58 | vm.ruleChains.data = vm.ruleChains.data.concat(ruleChains.data); |
59 | vm.ruleChains.nextPageLink = ruleChains.nextPageLink; | 59 | vm.ruleChains.nextPageLink = ruleChains.nextPageLink; |
@@ -441,6 +441,7 @@ | @@ -441,6 +441,7 @@ | ||
441 | "manage-assets": "Manage assets", | 441 | "manage-assets": "Manage assets", |
442 | "manage-devices": "Manage devices", | 442 | "manage-devices": "Manage devices", |
443 | "manage-dashboards": "Manage dashboards", | 443 | "manage-dashboards": "Manage dashboards", |
444 | + "manage-edges": "Manage edges", | ||
444 | "title": "Title", | 445 | "title": "Title", |
445 | "title-required": "Title is required.", | 446 | "title-required": "Title is required.", |
446 | "description": "Description", | 447 | "description": "Description", |
@@ -812,6 +813,8 @@ | @@ -812,6 +813,8 @@ | ||
812 | "assign-edges-text": "Assign { count, plural, 1 {1 edge} other {# edges} } to customer", | 813 | "assign-edges-text": "Assign { count, plural, 1 {1 edge} other {# edges} } to customer", |
813 | "unassign-edge-title": "Are you sure you want to unassign the edge '{{edgeName}}'?", | 814 | "unassign-edge-title": "Are you sure you want to unassign the edge '{{edgeName}}'?", |
814 | "unassign-edge-text": "After the confirmation the edge will be unassigned and won't be accessible by the customer.", | 815 | "unassign-edge-text": "After the confirmation the edge will be unassigned and won't be accessible by the customer.", |
816 | + "unassign-edges-title": "Are you sure you want to unassign { count, plural, 1 {1 edge} other {# edges} }?", | ||
817 | + "unassign-edges-text": "After the confirmation all selected edges will be unassigned and won't be accessible by the customer.", | ||
815 | "make-public": "Make edge public", | 818 | "make-public": "Make edge public", |
816 | "make-public-edge-title": "Are you sure you want to make the edge '{{edgeName}}' public?", | 819 | "make-public-edge-title": "Are you sure you want to make the edge '{{edgeName}}' public?", |
817 | "make-public-edge-text": "After the confirmation the edge and all its data will be made public and accessible by others.", | 820 | "make-public-edge-text": "After the confirmation the edge and all its data will be made public and accessible by others.", |