Commit b5659fd32d06cd090f25c9eefce8898aac1c2e48

Authored by Bohdan Smetaniuk
2 parents 7f848b32 c6e1b471

Merge remote-tracking branch 'upstream/feature/edge' into feature/widgets_bundle_fetch

Showing 25 changed files with 295 additions and 58 deletions
@@ -66,6 +66,7 @@ import org.thingsboard.server.dao.user.UserService; @@ -66,6 +66,7 @@ import org.thingsboard.server.dao.user.UserService;
66 import org.thingsboard.server.queue.discovery.PartitionService; 66 import org.thingsboard.server.queue.discovery.PartitionService;
67 import org.thingsboard.server.queue.discovery.TbServiceInfoProvider; 67 import org.thingsboard.server.queue.discovery.TbServiceInfoProvider;
68 import org.thingsboard.server.service.component.ComponentDiscoveryService; 68 import org.thingsboard.server.service.component.ComponentDiscoveryService;
  69 +import org.thingsboard.server.service.edge.rpc.EdgeRpcService;
69 import org.thingsboard.server.service.encoding.DataDecodingEncodingService; 70 import org.thingsboard.server.service.encoding.DataDecodingEncodingService;
70 import org.thingsboard.server.service.executors.DbCallbackExecutorService; 71 import org.thingsboard.server.service.executors.DbCallbackExecutorService;
71 import org.thingsboard.server.service.executors.ExternalCallExecutorService; 72 import org.thingsboard.server.service.executors.ExternalCallExecutorService;
@@ -254,15 +255,14 @@ public class ActorSystemContext { @@ -254,15 +255,14 @@ public class ActorSystemContext {
254 @Getter 255 @Getter
255 private TbCoreDeviceRpcService tbCoreDeviceRpcService; 256 private TbCoreDeviceRpcService tbCoreDeviceRpcService;
256 257
257 - @Lazy  
258 - @Autowired  
259 - @Getter  
260 - private EdgeService edgeService; 258 + @Autowired(required = false)
  259 + @Getter private EdgeService edgeService;
261 260
262 - @Lazy  
263 - @Autowired  
264 - @Getter  
265 - private EdgeEventService edgeEventService; 261 + @Autowired(required = false)
  262 + @Getter private EdgeEventService edgeEventService;
  263 +
  264 + @Autowired(required = false)
  265 + @Getter private EdgeRpcService edgeRpcService;
266 266
267 @Value("${actors.session.max_concurrent_sessions_per_device:1}") 267 @Value("${actors.session.max_concurrent_sessions_per_device:1}")
268 @Getter 268 @Getter
@@ -31,10 +31,13 @@ import org.thingsboard.server.actors.service.ContextBasedCreator; @@ -31,10 +31,13 @@ import org.thingsboard.server.actors.service.ContextBasedCreator;
31 import org.thingsboard.server.actors.service.DefaultActorService; 31 import org.thingsboard.server.actors.service.DefaultActorService;
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.edge.Edge;
34 import org.thingsboard.server.common.data.id.DeviceId; 35 import org.thingsboard.server.common.data.id.DeviceId;
  36 +import org.thingsboard.server.common.data.id.EdgeId;
35 import org.thingsboard.server.common.data.id.EntityId; 37 import org.thingsboard.server.common.data.id.EntityId;
36 import org.thingsboard.server.common.data.id.RuleChainId; 38 import org.thingsboard.server.common.data.id.RuleChainId;
37 import org.thingsboard.server.common.data.id.TenantId; 39 import org.thingsboard.server.common.data.id.TenantId;
  40 +import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent;
38 import org.thingsboard.server.common.data.rule.RuleChain; 41 import org.thingsboard.server.common.data.rule.RuleChain;
39 import org.thingsboard.server.common.data.rule.RuleChainType; 42 import org.thingsboard.server.common.data.rule.RuleChainType;
40 import org.thingsboard.server.common.msg.MsgType; 43 import org.thingsboard.server.common.msg.MsgType;
@@ -47,6 +50,7 @@ import org.thingsboard.server.common.msg.queue.PartitionChangeMsg; @@ -47,6 +50,7 @@ import org.thingsboard.server.common.msg.queue.PartitionChangeMsg;
47 import org.thingsboard.server.common.msg.queue.QueueToRuleEngineMsg; 50 import org.thingsboard.server.common.msg.queue.QueueToRuleEngineMsg;
48 import org.thingsboard.server.common.msg.queue.RuleEngineException; 51 import org.thingsboard.server.common.msg.queue.RuleEngineException;
49 import org.thingsboard.server.common.msg.queue.ServiceType; 52 import org.thingsboard.server.common.msg.queue.ServiceType;
  53 +import org.thingsboard.server.service.edge.rpc.EdgeRpcService;
50 54
51 import java.util.List; 55 import java.util.List;
52 import java.util.Optional; 56 import java.util.Optional;
@@ -202,7 +206,18 @@ public class TenantActor extends RuleChainManagerActor { @@ -202,7 +206,18 @@ public class TenantActor extends RuleChainManagerActor {
202 } 206 }
203 207
204 private void onComponentLifecycleMsg(ComponentLifecycleMsg msg) { 208 private void onComponentLifecycleMsg(ComponentLifecycleMsg msg) {
205 - if (isRuleEngineForCurrentTenant) { 209 + if (msg.getEntityId().getEntityType() == EntityType.EDGE) {
  210 + EdgeId edgeId = new EdgeId(msg.getEntityId().getId());
  211 + EdgeRpcService edgeRpcService = systemContext.getEdgeRpcService();
  212 + if (msg.getEvent() == ComponentLifecycleEvent.DELETED) {
  213 + edgeRpcService.deleteEdge(edgeId);
  214 + } else {
  215 + Edge edge = systemContext.getEdgeService().findEdgeById(tenantId, edgeId);
  216 + if (msg.getEvent() == ComponentLifecycleEvent.UPDATED) {
  217 + edgeRpcService.updateEdge(edge);
  218 + }
  219 + }
  220 + } else if (isRuleEngineForCurrentTenant) {
206 TbActorRef target = getEntityActorRef(msg.getEntityId()); 221 TbActorRef target = getEntityActorRef(msg.getEntityId());
207 if (target != null) { 222 if (target != null) {
208 if (msg.getEntityId().getEntityType() == EntityType.RULE_CHAIN) { 223 if (msg.getEntityId().getEntityType() == EntityType.RULE_CHAIN) {
@@ -40,6 +40,7 @@ import org.thingsboard.server.common.data.id.RuleChainId; @@ -40,6 +40,7 @@ import org.thingsboard.server.common.data.id.RuleChainId;
40 import org.thingsboard.server.common.data.id.TenantId; 40 import org.thingsboard.server.common.data.id.TenantId;
41 import org.thingsboard.server.common.data.page.TextPageData; 41 import org.thingsboard.server.common.data.page.TextPageData;
42 import org.thingsboard.server.common.data.page.TextPageLink; 42 import org.thingsboard.server.common.data.page.TextPageLink;
  43 +import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent;
43 import org.thingsboard.server.common.data.rule.RuleChain; 44 import org.thingsboard.server.common.data.rule.RuleChain;
44 import org.thingsboard.server.dao.exception.DataValidationException; 45 import org.thingsboard.server.dao.exception.DataValidationException;
45 import org.thingsboard.server.dao.exception.IncorrectParameterException; 46 import org.thingsboard.server.dao.exception.IncorrectParameterException;
@@ -101,6 +102,9 @@ public class EdgeController extends BaseController { @@ -101,6 +102,9 @@ public class EdgeController extends BaseController {
101 edgeService.assignDefaultRuleChainsToEdge(tenantId, savedEdge.getId()); 102 edgeService.assignDefaultRuleChainsToEdge(tenantId, savedEdge.getId());
102 } 103 }
103 104
  105 + tbClusterService.onEntityStateChange(savedEdge.getTenantId(), savedEdge.getId(),
  106 + created ? ComponentLifecycleEvent.CREATED : ComponentLifecycleEvent.UPDATED);
  107 +
104 logEntityAction(savedEdge.getId(), savedEdge, null, created ? ActionType.ADDED : ActionType.UPDATED, null); 108 logEntityAction(savedEdge.getId(), savedEdge, null, created ? ActionType.ADDED : ActionType.UPDATED, null);
105 return savedEdge; 109 return savedEdge;
106 } catch (Exception e) { 110 } catch (Exception e) {
@@ -120,6 +124,9 @@ public class EdgeController extends BaseController { @@ -120,6 +124,9 @@ public class EdgeController extends BaseController {
120 Edge edge = checkEdgeId(edgeId, Operation.DELETE); 124 Edge edge = checkEdgeId(edgeId, Operation.DELETE);
121 edgeService.deleteEdge(getTenantId(), edgeId); 125 edgeService.deleteEdge(getTenantId(), edgeId);
122 126
  127 + tbClusterService.onEntityStateChange(getTenantId(), edgeId,
  128 + ComponentLifecycleEvent.DELETED);
  129 +
123 logEntityAction(edgeId, edge, 130 logEntityAction(edgeId, edge,
124 null, 131 null,
125 ActionType.DELETED, null, strEdgeId); 132 ActionType.DELETED, null, strEdgeId);
@@ -284,6 +291,8 @@ public class EdgeController extends BaseController { @@ -284,6 +291,8 @@ public class EdgeController extends BaseController {
284 291
285 Edge updatedEdge = edgeNotificationService.setEdgeRootRuleChain(getTenantId(), edge, ruleChainId); 292 Edge updatedEdge = edgeNotificationService.setEdgeRootRuleChain(getTenantId(), edge, ruleChainId);
286 293
  294 + tbClusterService.onEntityStateChange(updatedEdge.getTenantId(), updatedEdge.getId(), ComponentLifecycleEvent.UPDATED);
  295 +
287 logEntityAction(updatedEdge.getId(), updatedEdge, null, ActionType.UPDATED, null); 296 logEntityAction(updatedEdge.getId(), updatedEdge, null, ActionType.UPDATED, null);
288 297
289 return updatedEdge; 298 return updatedEdge;
@@ -61,7 +61,7 @@ public class EdgeEventController extends BaseController { @@ -61,7 +61,7 @@ public class EdgeEventController extends BaseController {
61 EdgeId edgeId = new EdgeId(toUUID(strEdgeId)); 61 EdgeId edgeId = new EdgeId(toUUID(strEdgeId));
62 checkEdgeId(edgeId, Operation.READ); 62 checkEdgeId(edgeId, Operation.READ);
63 TimePageLink pageLink = createPageLink(limit, startTime, endTime, ascOrder, offset); 63 TimePageLink pageLink = createPageLink(limit, startTime, endTime, ascOrder, offset);
64 - return checkNotNull(edgeEventService.findEdgeEvents(tenantId, edgeId, pageLink)); 64 + return checkNotNull(edgeEventService.findEdgeEvents(tenantId, edgeId, pageLink, false));
65 } catch (Exception e) { 65 } catch (Exception e) {
66 throw handleException(e); 66 throw handleException(e);
67 } 67 }
@@ -111,7 +111,7 @@ public class DefaultEdgeNotificationService implements EdgeNotificationService { @@ -111,7 +111,7 @@ public class DefaultEdgeNotificationService implements EdgeNotificationService {
111 111
112 @Override 112 @Override
113 public TimePageData<EdgeEvent> findEdgeEvents(TenantId tenantId, EdgeId edgeId, TimePageLink pageLink) { 113 public TimePageData<EdgeEvent> findEdgeEvents(TenantId tenantId, EdgeId edgeId, TimePageLink pageLink) {
114 - return edgeEventService.findEdgeEvents(tenantId, edgeId, pageLink); 114 + return edgeEventService.findEdgeEvents(tenantId, edgeId, pageLink, true);
115 } 115 }
116 116
117 @Override 117 @Override
@@ -27,6 +27,7 @@ import org.springframework.beans.factory.annotation.Value; @@ -27,6 +27,7 @@ import org.springframework.beans.factory.annotation.Value;
27 import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; 27 import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
28 import org.springframework.stereotype.Service; 28 import org.springframework.stereotype.Service;
29 import org.thingsboard.server.common.data.DataConstants; 29 import org.thingsboard.server.common.data.DataConstants;
  30 +import org.thingsboard.server.common.data.edge.Edge;
30 import org.thingsboard.server.common.data.id.EdgeId; 31 import org.thingsboard.server.common.data.id.EdgeId;
31 import org.thingsboard.server.common.data.id.TenantId; 32 import org.thingsboard.server.common.data.id.TenantId;
32 import org.thingsboard.server.common.data.kv.BasicTsKvEntry; 33 import org.thingsboard.server.common.data.kv.BasicTsKvEntry;
@@ -52,7 +53,7 @@ import java.util.concurrent.Executors; @@ -52,7 +53,7 @@ import java.util.concurrent.Executors;
52 @Service 53 @Service
53 @Slf4j 54 @Slf4j
54 @ConditionalOnProperty(prefix = "edges.rpc", value = "enabled", havingValue = "true") 55 @ConditionalOnProperty(prefix = "edges.rpc", value = "enabled", havingValue = "true")
55 -public class EdgeGrpcService extends EdgeRpcServiceGrpc.EdgeRpcServiceImplBase { 56 +public class EdgeGrpcService extends EdgeRpcServiceGrpc.EdgeRpcServiceImplBase implements EdgeRpcService {
56 57
57 private final Map<EdgeId, EdgeGrpcSession> sessions = new ConcurrentHashMap<>(); 58 private final Map<EdgeId, EdgeGrpcSession> sessions = new ConcurrentHashMap<>();
58 private static final ObjectMapper mapper = new ObjectMapper(); 59 private static final ObjectMapper mapper = new ObjectMapper();
@@ -117,6 +118,23 @@ public class EdgeGrpcService extends EdgeRpcServiceGrpc.EdgeRpcServiceImplBase { @@ -117,6 +118,23 @@ public class EdgeGrpcService extends EdgeRpcServiceGrpc.EdgeRpcServiceImplBase {
117 return new EdgeGrpcSession(ctx, outputStream, this::onEdgeConnect, this::onEdgeDisconnect, mapper).getInputStream(); 118 return new EdgeGrpcSession(ctx, outputStream, this::onEdgeConnect, this::onEdgeDisconnect, mapper).getInputStream();
118 } 119 }
119 120
  121 + @Override
  122 + public void updateEdge(Edge edge) {
  123 + EdgeGrpcSession session = sessions.get(edge.getId());
  124 + if (session != null && session.isConnected()) {
  125 + session.onConfigurationUpdate(edge);
  126 + }
  127 + }
  128 +
  129 + @Override
  130 + public void deleteEdge(EdgeId edgeId) {
  131 + EdgeGrpcSession session = sessions.get(edgeId);
  132 + if (session != null && session.isConnected()) {
  133 + session.close();
  134 + sessions.remove(edgeId);
  135 + }
  136 + }
  137 +
120 private void onEdgeConnect(EdgeId edgeId, EdgeGrpcSession edgeGrpcSession) { 138 private void onEdgeConnect(EdgeId edgeId, EdgeGrpcSession edgeGrpcSession) {
121 sessions.put(edgeId, edgeGrpcSession); 139 sessions.put(edgeId, edgeGrpcSession);
122 save(edgeId, DefaultDeviceStateService.ACTIVITY_STATE, true); 140 save(edgeId, DefaultDeviceStateService.ACTIVITY_STATE, true);
@@ -198,6 +198,20 @@ public final class EdgeGrpcSession implements Closeable { @@ -198,6 +198,20 @@ public final class EdgeGrpcSession implements Closeable {
198 }; 198 };
199 } 199 }
200 200
  201 + void onConfigurationUpdate(Edge edge) {
  202 + try {
  203 + this.edge = edge;
  204 + // TODO: voba - push edge configuration update to edge
  205 +// outputStream.onNext(org.thingsboard.server.gen.integration.ResponseMsg.newBuilder()
  206 +// .setIntegrationUpdateMsg(IntegrationUpdateMsg.newBuilder()
  207 +// .setConfiguration(constructIntegrationConfigProto(configuration, defaultConverterProto, downLinkConverterProto))
  208 +// .build())
  209 +// .build());
  210 + } catch (Exception e) {
  211 + log.error("Failed to construct proto objects!", e);
  212 + }
  213 + }
  214 +
201 void processHandleMessages() throws ExecutionException, InterruptedException { 215 void processHandleMessages() throws ExecutionException, InterruptedException {
202 Long queueStartTs = getQueueStartTs().get(); 216 Long queueStartTs = getQueueStartTs().get();
203 TimePageLink pageLink = new TimePageLink(ctx.getEdgeEventStorageSettings().getMaxReadRecordsCount(), queueStartTs, null, true); 217 TimePageLink pageLink = new TimePageLink(ctx.getEdgeEventStorageSettings().getMaxReadRecordsCount(), queueStartTs, null, true);
  1 +/**
  2 + * Copyright © 2016-2020 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.service.edge.rpc;
  17 +
  18 +import org.thingsboard.server.common.data.edge.Edge;
  19 +import org.thingsboard.server.common.data.id.EdgeId;
  20 +
  21 +public interface EdgeRpcService {
  22 +
  23 + void updateEdge(Edge edge);
  24 +
  25 + void deleteEdge(EdgeId edgeId);
  26 +}
@@ -16,9 +16,7 @@ @@ -16,9 +16,7 @@
16 package org.thingsboard.server.dao.edge; 16 package org.thingsboard.server.dao.edge;
17 17
18 import com.google.common.util.concurrent.ListenableFuture; 18 import com.google.common.util.concurrent.ListenableFuture;
19 -import org.thingsboard.server.common.data.EntityType;  
20 import org.thingsboard.server.common.data.edge.EdgeEvent; 19 import org.thingsboard.server.common.data.edge.EdgeEvent;
21 -import org.thingsboard.server.common.data.edge.EdgeEventType;  
22 import org.thingsboard.server.common.data.id.EdgeId; 20 import org.thingsboard.server.common.data.id.EdgeId;
23 import org.thingsboard.server.common.data.id.TenantId; 21 import org.thingsboard.server.common.data.id.TenantId;
24 import org.thingsboard.server.common.data.page.TimePageData; 22 import org.thingsboard.server.common.data.page.TimePageData;
@@ -28,6 +26,5 @@ public interface EdgeEventService { @@ -28,6 +26,5 @@ public interface EdgeEventService {
28 26
29 ListenableFuture<EdgeEvent> saveAsync(EdgeEvent edgeEvent); 27 ListenableFuture<EdgeEvent> saveAsync(EdgeEvent edgeEvent);
30 28
31 - TimePageData<EdgeEvent> findEdgeEvents(TenantId tenantId, EdgeId edgeId, TimePageLink pageLink);  
32 - 29 + TimePageData<EdgeEvent> findEdgeEvents(TenantId tenantId, EdgeId edgeId, TimePageLink pageLink, boolean withTsUpdate);
33 } 30 }
@@ -35,7 +35,7 @@ import java.util.List; @@ -35,7 +35,7 @@ import java.util.List;
35 public class BaseEdgeEventService implements EdgeEventService { 35 public class BaseEdgeEventService implements EdgeEventService {
36 36
37 @Autowired 37 @Autowired
38 - public EdgeEventDao edgeEventDao; 38 + private EdgeEventDao edgeEventDao;
39 39
40 @Override 40 @Override
41 public ListenableFuture<EdgeEvent> saveAsync(EdgeEvent edgeEvent) { 41 public ListenableFuture<EdgeEvent> saveAsync(EdgeEvent edgeEvent) {
@@ -44,8 +44,8 @@ public class BaseEdgeEventService implements EdgeEventService { @@ -44,8 +44,8 @@ public class BaseEdgeEventService implements EdgeEventService {
44 } 44 }
45 45
46 @Override 46 @Override
47 - public TimePageData<EdgeEvent> findEdgeEvents(TenantId tenantId, EdgeId edgeId, TimePageLink pageLink) {  
48 - List<EdgeEvent> events = edgeEventDao.findEdgeEvents(tenantId.getId(), edgeId, pageLink); 47 + public TimePageData<EdgeEvent> findEdgeEvents(TenantId tenantId, EdgeId edgeId, TimePageLink pageLink, boolean withTsUpdate) {
  48 + List<EdgeEvent> events = edgeEventDao.findEdgeEvents(tenantId.getId(), edgeId, pageLink, withTsUpdate);
49 return new TimePageData<>(events, pageLink); 49 return new TimePageData<>(events, pageLink);
50 } 50 }
51 51
@@ -53,7 +53,7 @@ public class CassandraEdgeEventDao extends CassandraAbstractSearchTimeDao<EdgeEv @@ -53,7 +53,7 @@ public class CassandraEdgeEventDao extends CassandraAbstractSearchTimeDao<EdgeEv
53 } 53 }
54 54
55 @Override 55 @Override
56 - public List<EdgeEvent> findEdgeEvents(UUID tenantId, EdgeId edgeId, TimePageLink pageLink) { 56 + public List<EdgeEvent> findEdgeEvents(UUID tenantId, EdgeId edgeId, TimePageLink pageLink, boolean withTsUpdate) {
57 return null; 57 return null;
58 } 58 }
59 } 59 }
@@ -46,6 +46,6 @@ public interface EdgeEventDao extends Dao<EdgeEvent> { @@ -46,6 +46,6 @@ public interface EdgeEventDao extends Dao<EdgeEvent> {
46 * @param pageLink the pageLink 46 * @param pageLink the pageLink
47 * @return the event list 47 * @return the event list
48 */ 48 */
49 - List<EdgeEvent> findEdgeEvents(UUID tenantId, EdgeId edgeId, TimePageLink pageLink); 49 + List<EdgeEvent> findEdgeEvents(UUID tenantId, EdgeId edgeId, TimePageLink pageLink, boolean withTsUpdate);
50 50
51 } 51 }
@@ -26,6 +26,7 @@ import org.springframework.data.jpa.domain.Specification; @@ -26,6 +26,7 @@ import org.springframework.data.jpa.domain.Specification;
26 import org.springframework.data.repository.CrudRepository; 26 import org.springframework.data.repository.CrudRepository;
27 import org.springframework.stereotype.Component; 27 import org.springframework.stereotype.Component;
28 import org.thingsboard.server.common.data.UUIDConverter; 28 import org.thingsboard.server.common.data.UUIDConverter;
  29 +import org.thingsboard.server.common.data.audit.ActionType;
29 import org.thingsboard.server.common.data.edge.EdgeEvent; 30 import org.thingsboard.server.common.data.edge.EdgeEvent;
30 import org.thingsboard.server.common.data.id.EdgeEventId; 31 import org.thingsboard.server.common.data.id.EdgeEventId;
31 import org.thingsboard.server.common.data.id.EdgeId; 32 import org.thingsboard.server.common.data.id.EdgeId;
@@ -75,9 +76,9 @@ public class JpaBaseEdgeEventDao extends JpaAbstractSearchTimeDao<EdgeEventEntit @@ -75,9 +76,9 @@ public class JpaBaseEdgeEventDao extends JpaAbstractSearchTimeDao<EdgeEventEntit
75 } 76 }
76 77
77 @Override 78 @Override
78 - public List<EdgeEvent> findEdgeEvents(UUID tenantId, EdgeId edgeId, TimePageLink pageLink) { 79 + public List<EdgeEvent> findEdgeEvents(UUID tenantId, EdgeId edgeId, TimePageLink pageLink, boolean withTsUpdate) {
79 Specification<EdgeEventEntity> timeSearchSpec = JpaAbstractSearchTimeDao.getTimeSearchPageSpec(pageLink, "id"); 80 Specification<EdgeEventEntity> timeSearchSpec = JpaAbstractSearchTimeDao.getTimeSearchPageSpec(pageLink, "id");
80 - Specification<EdgeEventEntity> fieldsSpec = getEntityFieldsSpec(tenantId, edgeId); 81 + Specification<EdgeEventEntity> fieldsSpec = getEntityFieldsSpec(tenantId, edgeId, withTsUpdate);
81 Sort.Direction sortDirection = pageLink.isAscOrder() ? Sort.Direction.ASC : Sort.Direction.DESC; 82 Sort.Direction sortDirection = pageLink.isAscOrder() ? Sort.Direction.ASC : Sort.Direction.DESC;
82 Pageable pageable = PageRequest.of(0, pageLink.getLimit(), sortDirection, ID_PROPERTY); 83 Pageable pageable = PageRequest.of(0, pageLink.getLimit(), sortDirection, ID_PROPERTY);
83 return DaoUtil.convertDataList(edgeEventRepository.findAll(Specification.where(timeSearchSpec).and(fieldsSpec), pageable).getContent()); 84 return DaoUtil.convertDataList(edgeEventRepository.findAll(Specification.where(timeSearchSpec).and(fieldsSpec), pageable).getContent());
@@ -95,7 +96,7 @@ public class JpaBaseEdgeEventDao extends JpaAbstractSearchTimeDao<EdgeEventEntit @@ -95,7 +96,7 @@ public class JpaBaseEdgeEventDao extends JpaAbstractSearchTimeDao<EdgeEventEntit
95 return Optional.of(DaoUtil.getData(edgeEventRepository.save(entity))); 96 return Optional.of(DaoUtil.getData(edgeEventRepository.save(entity)));
96 } 97 }
97 98
98 - private Specification<EdgeEventEntity> getEntityFieldsSpec(UUID tenantId, EdgeId edgeId) { 99 + private Specification<EdgeEventEntity> getEntityFieldsSpec(UUID tenantId, EdgeId edgeId, boolean withTsUpdate) {
99 return (root, criteriaQuery, criteriaBuilder) -> { 100 return (root, criteriaQuery, criteriaBuilder) -> {
100 List<Predicate> predicates = new ArrayList<>(); 101 List<Predicate> predicates = new ArrayList<>();
101 if (tenantId != null) { 102 if (tenantId != null) {
@@ -106,6 +107,10 @@ public class JpaBaseEdgeEventDao extends JpaAbstractSearchTimeDao<EdgeEventEntit @@ -106,6 +107,10 @@ public class JpaBaseEdgeEventDao extends JpaAbstractSearchTimeDao<EdgeEventEntit
106 Predicate entityIdPredicate = criteriaBuilder.equal(root.get("edgeId"), UUIDConverter.fromTimeUUID(edgeId.getId())); 107 Predicate entityIdPredicate = criteriaBuilder.equal(root.get("edgeId"), UUIDConverter.fromTimeUUID(edgeId.getId()));
107 predicates.add(entityIdPredicate); 108 predicates.add(entityIdPredicate);
108 } 109 }
  110 + if (!withTsUpdate) {
  111 + Predicate edgeEventActionPredicate = criteriaBuilder.notEqual(root.get("edgeEventAction"), ActionType.TIMESERIES_UPDATED.name());
  112 + predicates.add(edgeEventActionPredicate);
  113 + }
109 return criteriaBuilder.and(predicates.toArray(new Predicate[]{})); 114 return criteriaBuilder.and(predicates.toArray(new Predicate[]{}));
110 }; 115 };
111 } 116 }
@@ -19,6 +19,7 @@ import com.datastax.driver.core.utils.UUIDs; @@ -19,6 +19,7 @@ import com.datastax.driver.core.utils.UUIDs;
19 import org.junit.Assert; 19 import org.junit.Assert;
20 import org.junit.Test; 20 import org.junit.Test;
21 import org.thingsboard.server.common.data.DataConstants; 21 import org.thingsboard.server.common.data.DataConstants;
  22 +import org.thingsboard.server.common.data.audit.ActionType;
22 import org.thingsboard.server.common.data.edge.EdgeEvent; 23 import org.thingsboard.server.common.data.edge.EdgeEvent;
23 import org.thingsboard.server.common.data.edge.EdgeEventType; 24 import org.thingsboard.server.common.data.edge.EdgeEventType;
24 import org.thingsboard.server.common.data.id.DeviceId; 25 import org.thingsboard.server.common.data.id.DeviceId;
@@ -82,7 +83,7 @@ public abstract class BaseEdgeEventServiceTest extends AbstractServiceTest { @@ -82,7 +83,7 @@ public abstract class BaseEdgeEventServiceTest extends AbstractServiceTest {
82 EdgeEvent savedEdgeEvent3 = saveEdgeEventWithProvidedTime(eventTime + 2, edgeId, deviceId, tenantId); 83 EdgeEvent savedEdgeEvent3 = saveEdgeEventWithProvidedTime(eventTime + 2, edgeId, deviceId, tenantId);
83 saveEdgeEventWithProvidedTime(timeAfterEndTime, edgeId, deviceId, tenantId); 84 saveEdgeEventWithProvidedTime(timeAfterEndTime, edgeId, deviceId, tenantId);
84 85
85 - TimePageData<EdgeEvent> edgeEvents = edgeEventService.findEdgeEvents(tenantId, edgeId, new TimePageLink(2, startTime, endTime, false)); 86 + TimePageData<EdgeEvent> edgeEvents = edgeEventService.findEdgeEvents(tenantId, edgeId, new TimePageLink(2, startTime, endTime, false), true);
86 87
87 Assert.assertNotNull(edgeEvents.getData()); 88 Assert.assertNotNull(edgeEvents.getData());
88 Assert.assertTrue(edgeEvents.getData().size() == 2); 89 Assert.assertTrue(edgeEvents.getData().size() == 2);
@@ -91,7 +92,7 @@ public abstract class BaseEdgeEventServiceTest extends AbstractServiceTest { @@ -91,7 +92,7 @@ public abstract class BaseEdgeEventServiceTest extends AbstractServiceTest {
91 Assert.assertTrue(edgeEvents.hasNext()); 92 Assert.assertTrue(edgeEvents.hasNext());
92 Assert.assertNotNull(edgeEvents.getNextPageLink()); 93 Assert.assertNotNull(edgeEvents.getNextPageLink());
93 94
94 - edgeEvents = edgeEventService.findEdgeEvents(tenantId, edgeId, edgeEvents.getNextPageLink()); 95 + edgeEvents = edgeEventService.findEdgeEvents(tenantId, edgeId, edgeEvents.getNextPageLink(), true);
95 96
96 Assert.assertNotNull(edgeEvents.getData()); 97 Assert.assertNotNull(edgeEvents.getData());
97 Assert.assertTrue(edgeEvents.getData().size() == 1); 98 Assert.assertTrue(edgeEvents.getData().size() == 1);
@@ -100,6 +101,26 @@ public abstract class BaseEdgeEventServiceTest extends AbstractServiceTest { @@ -100,6 +101,26 @@ public abstract class BaseEdgeEventServiceTest extends AbstractServiceTest {
100 Assert.assertNull(edgeEvents.getNextPageLink()); 101 Assert.assertNull(edgeEvents.getNextPageLink());
101 } 102 }
102 103
  104 + @Test
  105 + public void findEdgeEventsWithTsUpdateAndWithout() throws Exception {
  106 + EdgeId edgeId = new EdgeId(UUIDs.timeBased());
  107 + DeviceId deviceId = new DeviceId(UUIDs.timeBased());
  108 + TenantId tenantId = new TenantId(UUIDs.timeBased());
  109 + TimePageLink pageLink = new TimePageLink(1);
  110 +
  111 + EdgeEvent edgeEventWithTsUpdate = generateEdgeEvent(tenantId, edgeId, deviceId, ActionType.TIMESERIES_UPDATED.name());
  112 + edgeEventService.saveAsync(edgeEventWithTsUpdate);
  113 +
  114 + TimePageData<EdgeEvent> allEdgeEvents = edgeEventService.findEdgeEvents(tenantId, edgeId, pageLink, true);
  115 + TimePageData<EdgeEvent> edgeEventsWithoutTsUpdate = edgeEventService.findEdgeEvents(tenantId, edgeId, pageLink, false);
  116 +
  117 + Assert.assertNotNull(allEdgeEvents.getData());
  118 + Assert.assertNotNull(edgeEventsWithoutTsUpdate.getData());
  119 + Assert.assertEquals(1, allEdgeEvents.getData().size());
  120 + Assert.assertEquals(allEdgeEvents.getData().get(0).getUuidId(), edgeEventWithTsUpdate.getUuidId());
  121 + Assert.assertTrue(edgeEventsWithoutTsUpdate.getData().isEmpty());
  122 + }
  123 +
103 private EdgeEvent saveEdgeEventWithProvidedTime(long time, EdgeId edgeId, EntityId entityId, TenantId tenantId) throws Exception { 124 private EdgeEvent saveEdgeEventWithProvidedTime(long time, EdgeId edgeId, EntityId entityId, TenantId tenantId) throws Exception {
104 EdgeEvent edgeEvent = generateEdgeEvent(tenantId, edgeId, entityId, DataConstants.ENTITY_CREATED); 125 EdgeEvent edgeEvent = generateEdgeEvent(tenantId, edgeId, entityId, DataConstants.ENTITY_CREATED);
105 edgeEvent.setId(new EdgeEventId(UUIDs.startOf(time))); 126 edgeEvent.setId(new EdgeEventId(UUIDs.startOf(time)));
@@ -56,7 +56,7 @@ function EdgeService($http, $q, customerService) { @@ -56,7 +56,7 @@ function EdgeService($http, $q, customerService) {
56 deferred.reject(); 56 deferred.reject();
57 }); 57 });
58 return deferred.promise; 58 return deferred.promise;
59 - } // TODO: deaflynx: check usage in UI 59 + }
60 60
61 function getEdgesByIds(edgeIds, config) { 61 function getEdgesByIds(edgeIds, config) {
62 var deferred = $q.defer(); 62 var deferred = $q.defer();
@@ -389,6 +389,25 @@ export default angular.module('thingsboard.types', []) @@ -389,6 +389,25 @@ export default angular.module('thingsboard.types', [])
389 customer: "CUSTOMER", 389 customer: "CUSTOMER",
390 relation: "RELATION" 390 relation: "RELATION"
391 }, 391 },
  392 + edgeEventAction: {
  393 + updated: "UPDATED",
  394 + added: "ADDED",
  395 + assignedToEdge: "ASSIGNED_TO_EDGE",
  396 + deleted: "DELETED",
  397 + unassignedFromEdge: "UNASSIGNED_FROM_EDGE",
  398 + alarmAck: "ALARM_ACK",
  399 + alarmClear: "ALARM_CLEAR",
  400 + credentialsUpdated: "CREDENTIALS_UPDATED",
  401 + attributesUpdated: "ATTRIBUTES_UPDATED",
  402 + attributesDeleted: "ATTRIBUTES_DELETED",
  403 + timeseriesUpdated: "TIMESERIES_UPDATED"
  404 + },
  405 + edgeAttributeKeys: {
  406 + active: "active",
  407 + lastConnectTime: "lastConnectTime",
  408 + lastDisconnectTime: "lastDisconnectTime",
  409 + queueStartTs: "queueStartTs"
  410 + },
392 importEntityColumnType: { 411 importEntityColumnType: {
393 name: { 412 name: {
394 name: 'import.column-type.name', 413 name: 'import.column-type.name',
@@ -21,6 +21,21 @@ @@ -21,6 +21,21 @@
21 <md-button ng-click="onUnassignFromCustomer({event: $event, isPublic: isPublic})" 21 <md-button ng-click="onUnassignFromCustomer({event: $event, isPublic: isPublic})"
22 ng-show="!isEdit && (edgeScope === 'customer' || edgeScope === 'tenant') && isAssignedToCustomer" 22 ng-show="!isEdit && (edgeScope === 'customer' || edgeScope === 'tenant') && isAssignedToCustomer"
23 class="md-raised md-primary">{{ isPublic ? 'edge.make-private' : 'edge.unassign-from-customer' | translate }}</md-button> 23 class="md-raised md-primary">{{ isPublic ? 'edge.make-private' : 'edge.unassign-from-customer' | translate }}</md-button>
  24 +<md-button ng-click="onManageEdgeAssets({event: $event})"
  25 + ng-show="!isEdit && edgeScope === 'tenant'"
  26 + class="md-raised md-primary">{{ 'edge.manage-edge-assets' | translate }}</md-button>
  27 +<md-button ng-click="onManageEdgeDevices({event: $event})"
  28 + ng-show="!isEdit && edgeScope === 'tenant'"
  29 + class="md-raised md-primary">{{ 'edge.manage-edge-devices' | translate }}</md-button>
  30 +<md-button ng-click="onManageEdgeEntityViews({event: $event})"
  31 + ng-show="!isEdit && edgeScope === 'tenant'"
  32 + class="md-raised md-primary">{{ 'edge.manage-edge-entity-views' | translate }}</md-button>
  33 +<md-button ng-click="onManageEdgeDashboards({event: $event})"
  34 + ng-show="!isEdit && edgeScope === 'tenant'"
  35 + class="md-raised md-primary">{{ 'edge.manage-edge-dashboards' | translate }}</md-button>
  36 +<md-button ng-click="onManageEdgeRuleChains({event: $event})"
  37 + ng-show="!isEdit && edgeScope === 'tenant'"
  38 + class="md-raised md-primary">{{ 'edge.manage-edge-rulechains' | translate }}</md-button>
24 <md-button ng-click="onDeleteEdge({event: $event})" 39 <md-button ng-click="onDeleteEdge({event: $event})"
25 ng-show="!isEdit && edgeScope === 'tenant'" 40 ng-show="!isEdit && edgeScope === 'tenant'"
26 class="md-raised md-primary">{{ 'edge.delete' | translate }}</md-button> 41 class="md-raised md-primary">{{ 'edge.delete' | translate }}</md-button>
@@ -129,6 +129,11 @@ export function EdgeController($rootScope, userService, edgeService, customerSer @@ -129,6 +129,11 @@ export function EdgeController($rootScope, userService, edgeService, customerSer
129 vm.assignToCustomer = assignToCustomer; 129 vm.assignToCustomer = assignToCustomer;
130 vm.makePublic = makePublic; 130 vm.makePublic = makePublic;
131 vm.unassignFromCustomer = unassignFromCustomer; 131 vm.unassignFromCustomer = unassignFromCustomer;
  132 + vm.openEdgeAssets = openEdgeAssets;
  133 + vm.openEdgeDevices = openEdgeDevices;
  134 + vm.openEdgeEntityViews = openEdgeEntityViews;
  135 + vm.openEdgeDashboards = openEdgeDashboards;
  136 + vm.openEdgeRuleChains = openEdgeRuleChains;
132 137
133 initController(); 138 initController();
134 139
@@ -96,6 +96,11 @@ export default function EdgeDirective($compile, $templateCache, $translate, $mdD @@ -96,6 +96,11 @@ export default function EdgeDirective($compile, $templateCache, $translate, $mdD
96 onAssignToCustomer: '&', 96 onAssignToCustomer: '&',
97 onMakePublic: '&', 97 onMakePublic: '&',
98 onUnassignFromCustomer: '&', 98 onUnassignFromCustomer: '&',
  99 + onManageEdgeAssets: '&',
  100 + onManageEdgeDevices: '&',
  101 + onManageEdgeEntityViews: '&',
  102 + onManageEdgeDashboards: '&',
  103 + onManageEdgeRuleChains: '&',
99 onDeleteEdge: '&' 104 onDeleteEdge: '&'
100 } 105 }
101 }; 106 };
@@ -29,6 +29,11 @@ @@ -29,6 +29,11 @@
29 on-assign-to-customer="vm.assignToCustomer(event, [ vm.grid.detailsConfig.currentItem.id.id ])" 29 on-assign-to-customer="vm.assignToCustomer(event, [ vm.grid.detailsConfig.currentItem.id.id ])"
30 on-make-public="vm.makePublic(event, vm.grid.detailsConfig.currentItem)" 30 on-make-public="vm.makePublic(event, vm.grid.detailsConfig.currentItem)"
31 on-unassign-from-customer="vm.unassignFromCustomer(event, vm.grid.detailsConfig.currentItem, isPublic)" 31 on-unassign-from-customer="vm.unassignFromCustomer(event, vm.grid.detailsConfig.currentItem, isPublic)"
  32 + on-manage-edge-assets="vm.openEdgeAssets(event, vm.grid.detailsConfig.currentItem)"
  33 + on-manage-edge-devices="vm.openEdgeDevices(event, vm.grid.detailsConfig.currentItem)"
  34 + on-manage-edge-entity-views="vm.openEdgeEntityViews(event, vm.grid.detailsConfig.currentItem)"
  35 + on-manage-edge-dashboards="vm.openEdgeDashboards(event, vm.grid.detailsConfig.currentItem)"
  36 + on-manage-edge-rule-chains="vm.openEdgeRuleChains(event, vm.grid.detailsConfig.currentItem)"
32 on-delete-edge="vm.grid.deleteItem(event, vm.grid.detailsConfig.currentItem)"></tb-edge> 37 on-delete-edge="vm.grid.deleteItem(event, vm.grid.detailsConfig.currentItem)"></tb-edge>
33 </md-tab> 38 </md-tab>
34 <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode" md-on-select="vm.grid.triggerResize()" label="{{ 'attribute.attributes' | translate }}"> 39 <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode" md-on-select="vm.grid.triggerResize()" label="{{ 'attribute.attributes' | translate }}">
@@ -17,6 +17,7 @@ @@ -17,6 +17,7 @@
17 --> 17 -->
18 <div translate class="tb-cell" flex="20">event.event-time</div> 18 <div translate class="tb-cell" flex="20">event.event-time</div>
19 <div translate class="tb-cell" flex="20">event.event-type</div> 19 <div translate class="tb-cell" flex="20">event.event-type</div>
20 -<div translate class="tb-cell" flex="20">edge.event-action</div>  
21 -<div translate class="tb-cell" flex="30">edge.entity-id</div>  
22 -<div translate class="tb-cell" flex="20">edge.entity-info</div> 20 +<div translate class="tb-cell" flex="40">edge.event-action</div>
  21 +<div translate class="tb-cell" flex="20">edge.entity-id</div>
  22 +<div translate class="tb-cell" flex="15">edge.status</div>
  23 +<div translate class="tb-cell" flex="10">edge.entity-info</div>
@@ -15,11 +15,12 @@ @@ -15,11 +15,12 @@
15 limitations under the License. 15 limitations under the License.
16 16
17 --> 17 -->
18 -<div class="tb-cell" flex="20">{{event.createdTime | date : 'yyyy-MM-dd HH:mm:ss'}}</div>  
19 -<div class="tb-cell" flex="20">{{event.edgeEventType}}</div>  
20 -<div class="tb-cell" flex="20">{{event.edgeEventAction}}</div>  
21 -<div class="tb-cell" flex="30">{{event.entityId}}</div>  
22 -<div class="tb-cell" flex="20"> 18 +<div class="tb-cell" flex="20">{{ event.createdTime | date : 'yyyy-MM-dd HH:mm:ss' }}</div>
  19 +<div class="tb-cell" flex="20">{{ event.edgeEventType }}</div>
  20 +<div class="tb-cell" flex="40">{{ event.edgeEventAction }}</div>
  21 +<div class="tb-cell" flex="20">{{ event.entityId }}</div>
  22 +<div class="tb-cell" flex="15" ng-style="isPending ? {'color': 'rgba(0, 0, 0, .38)'} : {'color': '#000'}">{{ updateStatus(event.createdTime) | translate }}</div>
  23 +<div class="tb-cell" flex="10">
23 <md-button class="md-icon-button md-primary" 24 <md-button class="md-icon-button md-primary"
24 ng-click="showEdgeEntityContent($event, 'edge.entity-info', 'JSON')" 25 ng-click="showEdgeEntityContent($event, 'edge.entity-info', 'JSON')"
25 aria-label="{{ 'action.view' | translate }}"> 26 aria-label="{{ 'action.view' | translate }}">
@@ -33,3 +34,4 @@ @@ -33,3 +34,4 @@
33 </md-button> 34 </md-button>
34 </div> 35 </div>
35 36
  37 +
@@ -102,37 +102,45 @@ export default function EventRowDirective($compile, $templateCache, $mdDialog, $ @@ -102,37 +102,45 @@ export default function EventRowDirective($compile, $templateCache, $mdDialog, $
102 switch(scope.event.edgeEventType) { 102 switch(scope.event.edgeEventType) {
103 case types.edgeEventType.relation: 103 case types.edgeEventType.relation:
104 content = angular.toJson(scope.event.entityBody); 104 content = angular.toJson(scope.event.entityBody);
  105 + showDialog();
105 break; 106 break;
106 case types.edgeEventType.ruleChainMetaData: 107 case types.edgeEventType.ruleChainMetaData:
107 - content = ruleChainService.getRuleChainMetaData(scope.event.entityId, {}).then( 108 + content = ruleChainService.getRuleChainMetaData(scope.event.entityId, {ignoreErrors: true}).then(
108 function success(info) { 109 function success(info) {
  110 + showDialog();
109 return angular.toJson(info); 111 return angular.toJson(info);
110 }, function fail() { 112 }, function fail() {
111 - toast.showError($translate.instant('edge.load-entity-error')); 113 + showError();
112 }); 114 });
113 break; 115 break;
114 default: 116 default:
115 - content = entityService.getEntity(scope.event.edgeEventType, scope.event.entityId, {}).then( 117 + content = entityService.getEntity(scope.event.edgeEventType, scope.event.entityId, {ignoreErrors: true}).then(
116 function success(info) { 118 function success(info) {
  119 + showDialog();
117 return angular.toJson(info); 120 return angular.toJson(info);
118 }, function fail() { 121 }, function fail() {
119 - toast.showError($translate.instant('edge.load-entity-error')); 122 + showError();
120 }); 123 });
121 break; 124 break;
122 } 125 }
123 - $mdDialog.show({  
124 - controller: 'EventContentDialogController',  
125 - controllerAs: 'vm',  
126 - templateUrl: eventErrorDialogTemplate,  
127 - locals: {content: content, title: title, contentType: contentType, showingCallback: onShowingCallback},  
128 - parent: angular.element($document[0].body),  
129 - fullscreen: true,  
130 - targetEvent: $event,  
131 - multiple: true,  
132 - onShowing: function(scope, element) {  
133 - onShowingCallback.onShowing(scope, element);  
134 - }  
135 - }); 126 + function showDialog() {
  127 + $mdDialog.show({
  128 + controller: 'EventContentDialogController',
  129 + controllerAs: 'vm',
  130 + templateUrl: eventErrorDialogTemplate,
  131 + locals: {content: content, title: title, contentType: contentType, showingCallback: onShowingCallback},
  132 + parent: angular.element($document[0].body),
  133 + fullscreen: true,
  134 + targetEvent: $event,
  135 + multiple: true,
  136 + onShowing: function(scope, element) {
  137 + onShowingCallback.onShowing(scope, element);
  138 + }
  139 + });
  140 + }
  141 + function showError() {
  142 + toast.showError($translate.instant('edge.load-entity-error'));
  143 + }
136 } 144 }
137 145
138 scope.checkTooltip = function($event) { 146 scope.checkTooltip = function($event) {
@@ -144,6 +152,20 @@ export default function EventRowDirective($compile, $templateCache, $mdDialog, $ @@ -144,6 +152,20 @@ export default function EventRowDirective($compile, $templateCache, $mdDialog, $
144 } 152 }
145 153
146 $compile(element.contents())(scope); 154 $compile(element.contents())(scope);
  155 +
  156 + scope.updateStatus = function(eventCreatedTime) {
  157 + if (scope.queueStartTs) {
  158 + var status;
  159 + if (eventCreatedTime < scope.queueStartTs) {
  160 + status = $translate.instant('edge.success');
  161 + scope.isPending = false;
  162 + } else {
  163 + status = $translate.instant('edge.failed');
  164 + scope.isPending = true;
  165 + }
  166 + return status;
  167 + }
  168 + }
147 } 169 }
148 170
149 return { 171 return {
@@ -22,7 +22,8 @@ import eventTableTemplate from './event-table.tpl.html'; @@ -22,7 +22,8 @@ import eventTableTemplate from './event-table.tpl.html';
22 /* eslint-enable import/no-unresolved, import/default */ 22 /* eslint-enable import/no-unresolved, import/default */
23 23
24 /*@ngInject*/ 24 /*@ngInject*/
25 -export default function EventTableDirective($compile, $templateCache, $rootScope, types, eventService, edgeService) { 25 +export default function EventTableDirective($compile, $templateCache, $rootScope, types,
  26 + eventService, edgeService, attributeService) {
26 27
27 var linker = function (scope, element, attrs) { 28 var linker = function (scope, element, attrs) {
28 29
@@ -30,11 +31,16 @@ export default function EventTableDirective($compile, $templateCache, $rootScope @@ -30,11 +31,16 @@ export default function EventTableDirective($compile, $templateCache, $rootScope
30 31
31 element.html(template); 32 element.html(template);
32 33
  34 + scope.eventTypeScope = angular.copy(types.eventType);
  35 + if (scope.entityType !== types.entityType.edge) {
  36 + delete scope.eventTypeScope.edgeEvent;
  37 + }
  38 +
33 if (attrs.disabledEventTypes) { 39 if (attrs.disabledEventTypes) {
34 var disabledEventTypes = attrs.disabledEventTypes.split(','); 40 var disabledEventTypes = attrs.disabledEventTypes.split(',');
35 scope.eventTypes = {}; 41 scope.eventTypes = {};
36 - for (var type in types.eventType) {  
37 - var eventType = types.eventType[type]; 42 + for (var type in scope.eventTypeScope) {
  43 + var eventType = scope.eventTypeScope[type];
38 var enabled = true; 44 var enabled = true;
39 for (var i=0;i<disabledEventTypes.length;i++) { 45 for (var i=0;i<disabledEventTypes.length;i++) {
40 if (eventType.value === disabledEventTypes[i]) { 46 if (eventType.value === disabledEventTypes[i]) {
@@ -47,7 +53,7 @@ export default function EventTableDirective($compile, $templateCache, $rootScope @@ -47,7 +53,7 @@ export default function EventTableDirective($compile, $templateCache, $rootScope
47 } 53 }
48 } 54 }
49 } else { 55 } else {
50 - scope.eventTypes = angular.copy(types.eventType); 56 + scope.eventTypes = angular.copy(scope.eventTypeScope);
51 } 57 }
52 58
53 if (attrs.debugEventTypes) { 59 if (attrs.debugEventTypes) {
@@ -106,6 +112,7 @@ export default function EventTableDirective($compile, $templateCache, $rootScope @@ -106,6 +112,7 @@ export default function EventTableDirective($compile, $templateCache, $rootScope
106 scope.eventType, scope.tenantId, scope.events.nextPageLink); 112 scope.eventType, scope.tenantId, scope.events.nextPageLink);
107 } else { 113 } else {
108 promise = edgeService.getEdgeEvents(scope.entityId, scope.events.nextPageLink); 114 promise = edgeService.getEdgeEvents(scope.entityId, scope.events.nextPageLink);
  115 + scope.loadEdgeInfo();
109 } 116 }
110 if (promise) { 117 if (promise) {
111 scope.events.pending = true; 118 scope.events.pending = true;
@@ -135,6 +142,7 @@ export default function EventTableDirective($compile, $templateCache, $rootScope @@ -135,6 +142,7 @@ export default function EventTableDirective($compile, $templateCache, $rootScope
135 142
136 scope.$watch("entityId", function(newVal, prevVal) { 143 scope.$watch("entityId", function(newVal, prevVal) {
137 if (newVal && !angular.equals(newVal, prevVal)) { 144 if (newVal && !angular.equals(newVal, prevVal)) {
  145 + scope.loadEdgeInfo();
138 scope.resetFilter(); 146 scope.resetFilter();
139 scope.reload(); 147 scope.reload();
140 } 148 }
@@ -212,6 +220,53 @@ export default function EventTableDirective($compile, $templateCache, $rootScope @@ -212,6 +220,53 @@ export default function EventTableDirective($compile, $templateCache, $rootScope
212 return false; 220 return false;
213 } 221 }
214 222
  223 + scope.subscriptionId = null;
  224 + scope.queueStartTs;
  225 +
  226 + scope.loadEdgeInfo = function() {
  227 + attributeService.getEntityAttributesValues(scope.entityType, scope.entityId, types.attributesScope.server.value,
  228 + types.edgeAttributeKeys.queueStartTs, {})
  229 + .then(function success(attributes) {
  230 + scope.onUpdate(attributes);
  231 + });
  232 +
  233 + scope.checkSubscription();
  234 +
  235 + attributeService.getEntityAttributes(scope.entityType, scope.entityId, types.attributesScope.server.value, {order: '', limit: 1, page: 1, search: ''},
  236 + function (attributes) {
  237 + if (attributes && attributes.data) {
  238 + scope.onUpdate(attributes.data);
  239 + }
  240 + });
  241 + }
  242 +
  243 + scope.onUpdate = function(attributes) {
  244 + let edge = attributes.reduce(function (map, attribute) {
  245 + map[attribute.key] = attribute;
  246 + return map;
  247 + }, {});
  248 + if (edge.queueStartTs) {
  249 + scope.queueStartTs = edge.queueStartTs.lastUpdateTs;
  250 + }
  251 + }
  252 +
  253 + scope.checkSubscription = function() {
  254 + var newSubscriptionId = null;
  255 + if (scope.entityId && scope.entityType && types.attributesScope.server.value) {
  256 + newSubscriptionId = attributeService.subscribeForEntityAttributes(scope.entityType, scope.entityId, types.attributesScope.server.value);
  257 + }
  258 + if (scope.subscriptionId && scope.subscriptionId != newSubscriptionId) {
  259 + attributeService.unsubscribeForEntityAttributes(scope.subscriptionId);
  260 + }
  261 + scope.subscriptionId = newSubscriptionId;
  262 + }
  263 +
  264 + scope.$on('$destroy', function () {
  265 + if (scope.subscriptionId) {
  266 + attributeService.unsubscribeForEntityAttributes(scope.subscriptionId);
  267 + }
  268 + });
  269 +
215 scope.reload(); 270 scope.reload();
216 271
217 $compile(element.contents())(scope); 272 $compile(element.contents())(scope);
@@ -821,7 +821,7 @@ @@ -821,7 +821,7 @@
821 "make-private-edge-text": "After the confirmation the edge and all its data will be made private and won't be accessible by others.", 821 "make-private-edge-text": "After the confirmation the edge and all its data will be made private and won't be accessible by others.",
822 "import": "Import edge", 822 "import": "Import edge",
823 "label": "Label", 823 "label": "Label",
824 - "load-entity-error": "Could not load entity info", 824 + "load-entity-error": "Entity not found. Failed to load info",
825 "assign-new-edge": "Assign new edge", 825 "assign-new-edge": "Assign new edge",
826 "manage-edge-dashboards": "Manage edge dashboards", 826 "manage-edge-dashboards": "Manage edge dashboards",
827 "unassign-from-edge": "Unassign from edge", 827 "unassign-from-edge": "Unassign from edge",
@@ -843,7 +843,10 @@ @@ -843,7 +843,10 @@
843 "entity-views": "Edge entity views", 843 "entity-views": "Edge entity views",
844 "set-root-rule-chain-text": "Please select root rule chain for edge(s)", 844 "set-root-rule-chain-text": "Please select root rule chain for edge(s)",
845 "set-root-rule-chain-to-edges": "Set root rule chain for Edge(s)", 845 "set-root-rule-chain-to-edges": "Set root rule chain for Edge(s)",
846 - "set-root-rule-chain-to-edges-text": "Set root rule chain for { count, plural, 1 {1 edge} other {# edges} }" 846 + "set-root-rule-chain-to-edges-text": "Set root rule chain for { count, plural, 1 {1 edge} other {# edges} }",
  847 + "status": "Received by edge",
  848 + "success": "Deployed",
  849 + "failed": "Pending"
847 }, 850 },
848 "error": { 851 "error": {
849 "unable-to-connect": "Unable to connect to the server! Please check your internet connection.", 852 "unable-to-connect": "Unable to connect to the server! Please check your internet connection.",