Commit b45bee7843a428d3401ad22b4200a2e754201f75

Authored by Volodymyr Babak
2 parents e32dfcfb 773d3806

Merge remote-tracking branch 'origin/develop/2.6-edge' into develop/3.3-edge

Showing 36 changed files with 161 additions and 3409 deletions
@@ -18,6 +18,7 @@ package org.thingsboard.server.service.edge.rpc; @@ -18,6 +18,7 @@ package org.thingsboard.server.service.edge.rpc;
18 import com.datastax.oss.driver.api.core.uuid.Uuids; 18 import com.datastax.oss.driver.api.core.uuid.Uuids;
19 import com.fasterxml.jackson.core.JsonProcessingException; 19 import com.fasterxml.jackson.core.JsonProcessingException;
20 import com.fasterxml.jackson.databind.ObjectMapper; 20 import com.fasterxml.jackson.databind.ObjectMapper;
  21 +import com.fasterxml.jackson.databind.node.ObjectNode;
21 import com.google.common.util.concurrent.FutureCallback; 22 import com.google.common.util.concurrent.FutureCallback;
22 import com.google.common.util.concurrent.Futures; 23 import com.google.common.util.concurrent.Futures;
23 import com.google.common.util.concurrent.ListenableFuture; 24 import com.google.common.util.concurrent.ListenableFuture;
@@ -342,8 +343,8 @@ public final class EdgeGrpcSession implements Closeable { @@ -342,8 +343,8 @@ public final class EdgeGrpcSession implements Closeable {
342 case CREDENTIALS_REQUEST: 343 case CREDENTIALS_REQUEST:
343 downlinkMsg = processCredentialsRequestMessage(edgeEvent); 344 downlinkMsg = processCredentialsRequestMessage(edgeEvent);
344 break; 345 break;
345 - case ENTITY_EXISTS_REQUEST:  
346 - downlinkMsg = processEntityExistsRequestMessage(edgeEvent); 346 + case ENTITY_MERGE_REQUEST:
  347 + downlinkMsg = processEntityMergeRequestMessage(edgeEvent);
347 break; 348 break;
348 case RPC_CALL: 349 case RPC_CALL:
349 downlinkMsg = processRpcCallMsg(edgeEvent); 350 downlinkMsg = processRpcCallMsg(edgeEvent);
@@ -359,13 +360,18 @@ public final class EdgeGrpcSession implements Closeable { @@ -359,13 +360,18 @@ public final class EdgeGrpcSession implements Closeable {
359 return result; 360 return result;
360 } 361 }
361 362
362 - private DownlinkMsg processEntityExistsRequestMessage(EdgeEvent edgeEvent) { 363 + private DownlinkMsg processEntityMergeRequestMessage(EdgeEvent edgeEvent) {
363 DownlinkMsg downlinkMsg = null; 364 DownlinkMsg downlinkMsg = null;
364 if (EdgeEventType.DEVICE.equals(edgeEvent.getType())) { 365 if (EdgeEventType.DEVICE.equals(edgeEvent.getType())) {
365 DeviceId deviceId = new DeviceId(edgeEvent.getEntityId()); 366 DeviceId deviceId = new DeviceId(edgeEvent.getEntityId());
366 Device device = ctx.getDeviceService().findDeviceById(edge.getTenantId(), deviceId); 367 Device device = ctx.getDeviceService().findDeviceById(edge.getTenantId(), deviceId);
367 CustomerId customerId = getCustomerIdIfEdgeAssignedToCustomer(device); 368 CustomerId customerId = getCustomerIdIfEdgeAssignedToCustomer(device);
368 - DeviceUpdateMsg d = ctx.getDeviceMsgConstructor().constructDeviceUpdatedMsg(UpdateMsgType.DEVICE_CONFLICT_RPC_MESSAGE, device, customerId); 369 + String conflictName = null;
  370 + if(edgeEvent.getBody() != null) {
  371 + conflictName = edgeEvent.getBody().get("conflictName").asText();
  372 + }
  373 + DeviceUpdateMsg d = ctx.getDeviceMsgConstructor()
  374 + .constructDeviceUpdatedMsg(UpdateMsgType.ENTITY_MERGE_RPC_MESSAGE, device, customerId, conflictName);
369 downlinkMsg = DownlinkMsg.newBuilder() 375 downlinkMsg = DownlinkMsg.newBuilder()
370 .addAllDeviceUpdateMsg(Collections.singletonList(d)) 376 .addAllDeviceUpdateMsg(Collections.singletonList(d))
371 .build(); 377 .build();
@@ -504,7 +510,7 @@ public final class EdgeGrpcSession implements Closeable { @@ -504,7 +510,7 @@ public final class EdgeGrpcSession implements Closeable {
504 if (device != null) { 510 if (device != null) {
505 CustomerId customerId = getCustomerIdIfEdgeAssignedToCustomer(device); 511 CustomerId customerId = getCustomerIdIfEdgeAssignedToCustomer(device);
506 DeviceUpdateMsg deviceUpdateMsg = 512 DeviceUpdateMsg deviceUpdateMsg =
507 - ctx.getDeviceMsgConstructor().constructDeviceUpdatedMsg(msgType, device, customerId); 513 + ctx.getDeviceMsgConstructor().constructDeviceUpdatedMsg(msgType, device, customerId, null);
508 downlinkMsg = DownlinkMsg.newBuilder() 514 downlinkMsg = DownlinkMsg.newBuilder()
509 .addAllDeviceUpdateMsg(Collections.singletonList(deviceUpdateMsg)) 515 .addAllDeviceUpdateMsg(Collections.singletonList(deviceUpdateMsg))
510 .build(); 516 .build();
@@ -38,7 +38,7 @@ public class DeviceMsgConstructor { @@ -38,7 +38,7 @@ public class DeviceMsgConstructor {
38 38
39 protected static final ObjectMapper mapper = new ObjectMapper(); 39 protected static final ObjectMapper mapper = new ObjectMapper();
40 40
41 - public DeviceUpdateMsg constructDeviceUpdatedMsg(UpdateMsgType msgType, Device device, CustomerId customerId) { 41 + public DeviceUpdateMsg constructDeviceUpdatedMsg(UpdateMsgType msgType, Device device, CustomerId customerId, String conflictName) {
42 DeviceUpdateMsg.Builder builder = DeviceUpdateMsg.newBuilder() 42 DeviceUpdateMsg.Builder builder = DeviceUpdateMsg.newBuilder()
43 .setMsgType(msgType) 43 .setMsgType(msgType)
44 .setIdMSB(device.getId().getId().getMostSignificantBits()) 44 .setIdMSB(device.getId().getId().getMostSignificantBits())
@@ -55,6 +55,9 @@ public class DeviceMsgConstructor { @@ -55,6 +55,9 @@ public class DeviceMsgConstructor {
55 if (device.getAdditionalInfo() != null) { 55 if (device.getAdditionalInfo() != null) {
56 builder.setAdditionalInfo(JacksonUtil.toString(device.getAdditionalInfo())); 56 builder.setAdditionalInfo(JacksonUtil.toString(device.getAdditionalInfo()));
57 } 57 }
  58 + if (conflictName != null) {
  59 + builder.setConflictName(conflictName);
  60 + }
58 return builder.build(); 61 return builder.build();
59 } 62 }
60 63
@@ -37,6 +37,7 @@ import org.thingsboard.server.dao.dashboard.DashboardService; @@ -37,6 +37,7 @@ import org.thingsboard.server.dao.dashboard.DashboardService;
37 import org.thingsboard.server.dao.device.DeviceCredentialsService; 37 import org.thingsboard.server.dao.device.DeviceCredentialsService;
38 import org.thingsboard.server.dao.device.DeviceService; 38 import org.thingsboard.server.dao.device.DeviceService;
39 import org.thingsboard.server.dao.edge.EdgeEventService; 39 import org.thingsboard.server.dao.edge.EdgeEventService;
  40 +import org.thingsboard.server.dao.edge.EdgeService;
40 import org.thingsboard.server.dao.entityview.EntityViewService; 41 import org.thingsboard.server.dao.entityview.EntityViewService;
41 import org.thingsboard.server.dao.relation.RelationService; 42 import org.thingsboard.server.dao.relation.RelationService;
42 import org.thingsboard.server.dao.user.UserService; 43 import org.thingsboard.server.dao.user.UserService;
@@ -65,6 +66,9 @@ public abstract class BaseProcessor { @@ -65,6 +66,9 @@ public abstract class BaseProcessor {
65 protected EntityViewService entityViewService; 66 protected EntityViewService entityViewService;
66 67
67 @Autowired 68 @Autowired
  69 + protected EdgeService edgeService;
  70 +
  71 + @Autowired
68 protected CustomerService customerService; 72 protected CustomerService customerService;
69 73
70 @Autowired 74 @Autowired
@@ -17,12 +17,14 @@ package org.thingsboard.server.service.edge.rpc.processor; @@ -17,12 +17,14 @@ package org.thingsboard.server.service.edge.rpc.processor;
17 17
18 import com.fasterxml.jackson.core.JsonProcessingException; 18 import com.fasterxml.jackson.core.JsonProcessingException;
19 import com.fasterxml.jackson.databind.node.ObjectNode; 19 import com.fasterxml.jackson.databind.node.ObjectNode;
  20 +import com.google.common.util.concurrent.FutureCallback;
20 import com.google.common.util.concurrent.Futures; 21 import com.google.common.util.concurrent.Futures;
21 import com.google.common.util.concurrent.ListenableFuture; 22 import com.google.common.util.concurrent.ListenableFuture;
22 import com.google.common.util.concurrent.SettableFuture; 23 import com.google.common.util.concurrent.SettableFuture;
23 import lombok.extern.slf4j.Slf4j; 24 import lombok.extern.slf4j.Slf4j;
24 import org.apache.commons.lang.RandomStringUtils; 25 import org.apache.commons.lang.RandomStringUtils;
25 import org.apache.commons.lang.StringUtils; 26 import org.apache.commons.lang.StringUtils;
  27 +import org.checkerframework.checker.nullness.qual.Nullable;
26 import org.springframework.stereotype.Component; 28 import org.springframework.stereotype.Component;
27 import org.thingsboard.rule.engine.api.RpcError; 29 import org.thingsboard.rule.engine.api.RpcError;
28 import org.thingsboard.server.common.data.DataConstants; 30 import org.thingsboard.server.common.data.DataConstants;
@@ -52,6 +54,7 @@ import org.thingsboard.server.queue.util.TbCoreComponent; @@ -52,6 +54,7 @@ import org.thingsboard.server.queue.util.TbCoreComponent;
52 import org.thingsboard.server.service.rpc.FromDeviceRpcResponse; 54 import org.thingsboard.server.service.rpc.FromDeviceRpcResponse;
53 import org.thingsboard.server.service.rpc.FromDeviceRpcResponseActorMsg; 55 import org.thingsboard.server.service.rpc.FromDeviceRpcResponseActorMsg;
54 56
  57 +import java.util.List;
55 import java.util.UUID; 58 import java.util.UUID;
56 import java.util.concurrent.locks.ReentrantLock; 59 import java.util.concurrent.locks.ReentrantLock;
57 60
@@ -64,38 +67,62 @@ public class DeviceProcessor extends BaseProcessor { @@ -64,38 +67,62 @@ public class DeviceProcessor extends BaseProcessor {
64 67
65 public ListenableFuture<Void> onDeviceUpdate(TenantId tenantId, Edge edge, DeviceUpdateMsg deviceUpdateMsg) { 68 public ListenableFuture<Void> onDeviceUpdate(TenantId tenantId, Edge edge, DeviceUpdateMsg deviceUpdateMsg) {
66 log.trace("[{}] onDeviceUpdate [{}] from edge [{}]", tenantId, deviceUpdateMsg, edge.getName()); 69 log.trace("[{}] onDeviceUpdate [{}] from edge [{}]", tenantId, deviceUpdateMsg, edge.getName());
67 - DeviceId edgeDeviceId = new DeviceId(new UUID(deviceUpdateMsg.getIdMSB(), deviceUpdateMsg.getIdLSB()));  
68 switch (deviceUpdateMsg.getMsgType()) { 70 switch (deviceUpdateMsg.getMsgType()) {
69 case ENTITY_CREATED_RPC_MESSAGE: 71 case ENTITY_CREATED_RPC_MESSAGE:
70 String deviceName = deviceUpdateMsg.getName(); 72 String deviceName = deviceUpdateMsg.getName();
71 Device device = deviceService.findDeviceByTenantIdAndName(tenantId, deviceName); 73 Device device = deviceService.findDeviceByTenantIdAndName(tenantId, deviceName);
72 if (device != null) { 74 if (device != null) {
73 - log.info("[{}] Device with name '{}' already exists on the cloud. Updating id of device entity on the edge", tenantId, deviceName);  
74 - if (!device.getId().equals(edgeDeviceId)) {  
75 - saveEdgeEvent(tenantId, edge.getId(), EdgeEventType.DEVICE, EdgeEventActionType.ENTITY_EXISTS_REQUEST, device.getId(), null);  
76 - }  
77 - } else {  
78 - Device deviceById = deviceService.findDeviceById(edge.getTenantId(), edgeDeviceId);  
79 - if (deviceById != null) {  
80 - log.info("[{}] Device ID [{}] already used by other device on the cloud. Creating new device and replacing device entity on the edge", tenantId, edgeDeviceId.getId());  
81 - device = createDevice(tenantId, edge, deviceUpdateMsg); 75 + ListenableFuture<List<EdgeId>> future = edgeService.findRelatedEdgeIdsByEntityId(tenantId, device.getId());
  76 + SettableFuture<Void> futureToSet = SettableFuture.create();
  77 + Futures.addCallback(future, new FutureCallback<List<EdgeId>>() {
  78 + @Override
  79 + public void onSuccess(@Nullable List<EdgeId> edgeIds) {
  80 + boolean update = false;
  81 + if (edgeIds != null && !edgeIds.isEmpty()) {
  82 + if (edgeIds.contains(edge.getId())) {
  83 + update = true;
  84 + }
  85 + }
  86 + Device device;
  87 + if (update) {
  88 + log.info("[{}] Device with name '{}' already exists on the cloud, and related to this edge [{}]. " +
  89 + "deviceUpdateMsg [{}], Updating device", tenantId, deviceName, edge.getId(), deviceUpdateMsg);
  90 + updateDevice(tenantId, edge, deviceUpdateMsg);
  91 + } else {
  92 + log.info("[{}] Device with name '{}' already exists on the cloud, but not related to this edge [{}]. deviceUpdateMsg [{}]." +
  93 + "Creating a new device with random prefix and relate to this edge", tenantId, deviceName, edge.getId(), deviceUpdateMsg);
  94 + String newDeviceName = deviceUpdateMsg.getName() + "_" + RandomStringUtils.randomAlphabetic(15);
  95 + device = createDevice(tenantId, edge, deviceUpdateMsg, newDeviceName);
  96 + ObjectNode body = mapper.createObjectNode();
  97 + body.put("conflictName", deviceName);
  98 + saveEdgeEvent(tenantId, edge.getId(), EdgeEventType.DEVICE, EdgeEventActionType.ENTITY_MERGE_REQUEST, device.getId(), body);
  99 + deviceService.assignDeviceToEdge(edge.getTenantId(), device.getId(), edge.getId());
  100 + }
  101 + futureToSet.set(null);
  102 + }
82 103
83 - // TODO: voba - properly handle device credentials from edge to cloud  
84 - saveEdgeEvent(tenantId, edge.getId(), EdgeEventType.DEVICE, EdgeEventActionType.ENTITY_EXISTS_REQUEST, device.getId(), null);  
85 - } else {  
86 - device = createDevice(tenantId, edge, deviceUpdateMsg);  
87 - } 104 + @Override
  105 + public void onFailure(Throwable t) {
  106 + log.error("[{}] Failed to get related edge ids by device id [{}], edge [{}]", tenantId, deviceUpdateMsg, edge.getId(), t);
  107 + futureToSet.setException(t);
  108 + }
  109 + }, dbCallbackExecutorService);
  110 + return futureToSet;
  111 + } else {
  112 + log.info("[{}] Creating new device and replacing device entity on the edge [{}]", tenantId, deviceUpdateMsg);
  113 + device = createDevice(tenantId, edge, deviceUpdateMsg, deviceUpdateMsg.getName());
  114 + saveEdgeEvent(tenantId, edge.getId(), EdgeEventType.DEVICE, EdgeEventActionType.ENTITY_MERGE_REQUEST, device.getId(), null);
  115 + deviceService.assignDeviceToEdge(edge.getTenantId(), device.getId(), edge.getId());
88 } 116 }
89 - // TODO: voba - assign device only in case device is not assigned yet. Missing functionality to check this relation prior assignment  
90 - deviceService.assignDeviceToEdge(edge.getTenantId(), device.getId(), edge.getId());  
91 break; 117 break;
92 case ENTITY_UPDATED_RPC_MESSAGE: 118 case ENTITY_UPDATED_RPC_MESSAGE:
93 updateDevice(tenantId, edge, deviceUpdateMsg); 119 updateDevice(tenantId, edge, deviceUpdateMsg);
94 break; 120 break;
95 case ENTITY_DELETED_RPC_MESSAGE: 121 case ENTITY_DELETED_RPC_MESSAGE:
96 - Device deviceToDelete = deviceService.findDeviceById(tenantId, edgeDeviceId); 122 + DeviceId deviceId = new DeviceId(new UUID(deviceUpdateMsg.getIdMSB(), deviceUpdateMsg.getIdLSB()));
  123 + Device deviceToDelete = deviceService.findDeviceById(tenantId, deviceId);
97 if (deviceToDelete != null) { 124 if (deviceToDelete != null) {
98 - deviceService.unassignDeviceFromEdge(tenantId, edgeDeviceId, edge.getId()); 125 + deviceService.unassignDeviceFromEdge(tenantId, deviceId, edge.getId());
99 } 126 }
100 break; 127 break;
101 case UNRECOGNIZED: 128 case UNRECOGNIZED:
@@ -105,7 +132,6 @@ public class DeviceProcessor extends BaseProcessor { @@ -105,7 +132,6 @@ public class DeviceProcessor extends BaseProcessor {
105 return Futures.immediateFuture(null); 132 return Futures.immediateFuture(null);
106 } 133 }
107 134
108 -  
109 public ListenableFuture<Void> onDeviceCredentialsUpdate(TenantId tenantId, DeviceCredentialsUpdateMsg deviceCredentialsUpdateMsg) { 135 public ListenableFuture<Void> onDeviceCredentialsUpdate(TenantId tenantId, DeviceCredentialsUpdateMsg deviceCredentialsUpdateMsg) {
110 log.debug("Executing onDeviceCredentialsUpdate, deviceCredentialsUpdateMsg [{}]", deviceCredentialsUpdateMsg); 136 log.debug("Executing onDeviceCredentialsUpdate, deviceCredentialsUpdateMsg [{}]", deviceCredentialsUpdateMsg);
111 DeviceId deviceId = new DeviceId(new UUID(deviceCredentialsUpdateMsg.getDeviceIdMSB(), deviceCredentialsUpdateMsg.getDeviceIdLSB())); 137 DeviceId deviceId = new DeviceId(new UUID(deviceCredentialsUpdateMsg.getDeviceIdMSB(), deviceCredentialsUpdateMsg.getDeviceIdLSB()));
@@ -133,37 +159,34 @@ public class DeviceProcessor extends BaseProcessor { @@ -133,37 +159,34 @@ public class DeviceProcessor extends BaseProcessor {
133 private void updateDevice(TenantId tenantId, Edge edge, DeviceUpdateMsg deviceUpdateMsg) { 159 private void updateDevice(TenantId tenantId, Edge edge, DeviceUpdateMsg deviceUpdateMsg) {
134 DeviceId deviceId = new DeviceId(new UUID(deviceUpdateMsg.getIdMSB(), deviceUpdateMsg.getIdLSB())); 160 DeviceId deviceId = new DeviceId(new UUID(deviceUpdateMsg.getIdMSB(), deviceUpdateMsg.getIdLSB()));
135 Device device = deviceService.findDeviceById(tenantId, deviceId); 161 Device device = deviceService.findDeviceById(tenantId, deviceId);
136 - device.setName(deviceUpdateMsg.getName());  
137 - device.setType(deviceUpdateMsg.getType());  
138 - device.setLabel(deviceUpdateMsg.getLabel());  
139 - device.setAdditionalInfo(JacksonUtil.toJsonNode(deviceUpdateMsg.getAdditionalInfo()));  
140 - deviceService.saveDevice(device);  
141 -  
142 - saveEdgeEvent(tenantId, edge.getId(), EdgeEventType.DEVICE, EdgeEventActionType.CREDENTIALS_REQUEST, deviceId, null); 162 + if (device != null) {
  163 + device.setName(deviceUpdateMsg.getName());
  164 + device.setType(deviceUpdateMsg.getType());
  165 + device.setLabel(deviceUpdateMsg.getLabel());
  166 + device.setAdditionalInfo(JacksonUtil.toJsonNode(deviceUpdateMsg.getAdditionalInfo()));
  167 + deviceService.saveDevice(device);
  168 + saveEdgeEvent(tenantId, edge.getId(), EdgeEventType.DEVICE, EdgeEventActionType.CREDENTIALS_REQUEST, deviceId, null);
  169 + } else {
  170 + log.warn("[{}] can't find device [{}], edge [{}]", tenantId, deviceUpdateMsg, edge.getId());
  171 + }
143 } 172 }
144 173
145 - private Device createDevice(TenantId tenantId, Edge edge, DeviceUpdateMsg deviceUpdateMsg) { 174 + private Device createDevice(TenantId tenantId, Edge edge, DeviceUpdateMsg deviceUpdateMsg, String deviceName) {
146 Device device; 175 Device device;
147 try { 176 try {
148 deviceCreationLock.lock(); 177 deviceCreationLock.lock();
149 log.debug("[{}] Creating device entity [{}] from edge [{}]", tenantId, deviceUpdateMsg, edge.getName()); 178 log.debug("[{}] Creating device entity [{}] from edge [{}]", tenantId, deviceUpdateMsg, edge.getName());
150 -// DeviceId deviceId = new DeviceId(new UUID(deviceUpdateMsg.getIdMSB(), deviceUpdateMsg.getIdLSB()));  
151 device = new Device(); 179 device = new Device();
152 -// device.setId(deviceId);  
153 device.setTenantId(edge.getTenantId()); 180 device.setTenantId(edge.getTenantId());
154 device.setCustomerId(edge.getCustomerId()); 181 device.setCustomerId(edge.getCustomerId());
155 - device.setName(deviceUpdateMsg.getName()); 182 + device.setName(deviceName);
156 device.setType(deviceUpdateMsg.getType()); 183 device.setType(deviceUpdateMsg.getType());
157 device.setLabel(deviceUpdateMsg.getLabel()); 184 device.setLabel(deviceUpdateMsg.getLabel());
158 device.setAdditionalInfo(JacksonUtil.toJsonNode(deviceUpdateMsg.getAdditionalInfo())); 185 device.setAdditionalInfo(JacksonUtil.toJsonNode(deviceUpdateMsg.getAdditionalInfo()));
159 device = deviceService.saveDevice(device); 186 device = deviceService.saveDevice(device);
160 - // TODO: voba - is this still required?  
161 -// createDeviceCredentials(device);  
162 createRelationFromEdge(tenantId, edge.getId(), device.getId()); 187 createRelationFromEdge(tenantId, edge.getId(), device.getId());
163 deviceStateService.onDeviceAdded(device); 188 deviceStateService.onDeviceAdded(device);
164 pushDeviceCreatedEventToRuleEngine(tenantId, edge, device); 189 pushDeviceCreatedEventToRuleEngine(tenantId, edge, device);
165 -  
166 - // saveEdgeEvent(tenantId, edge.getId(), EdgeEventType.DEVICE, EdgeEventActionType.CREDENTIALS_REQUEST, deviceId, null);  
167 } finally { 190 } finally {
168 deviceCreationLock.unlock(); 191 deviceCreationLock.unlock();
169 } 192 }
@@ -179,14 +202,6 @@ public class DeviceProcessor extends BaseProcessor { @@ -179,14 +202,6 @@ public class DeviceProcessor extends BaseProcessor {
179 relationService.saveRelation(tenantId, relation); 202 relationService.saveRelation(tenantId, relation);
180 } 203 }
181 204
182 - private void createDeviceCredentials(Device device) {  
183 - DeviceCredentials deviceCredentials = new DeviceCredentials();  
184 - deviceCredentials.setDeviceId(device.getId());  
185 - deviceCredentials.setCredentialsType(DeviceCredentialsType.ACCESS_TOKEN);  
186 - deviceCredentials.setCredentialsId(RandomStringUtils.randomAlphanumeric(20));  
187 - deviceCredentialsService.createDeviceCredentials(device.getTenantId(), deviceCredentials);  
188 - }  
189 -  
190 private void pushDeviceCreatedEventToRuleEngine(TenantId tenantId, Edge edge, Device device) { 205 private void pushDeviceCreatedEventToRuleEngine(TenantId tenantId, Edge edge, Device device) {
191 try { 206 try {
192 DeviceId deviceId = device.getId(); 207 DeviceId deviceId = device.getId();
@@ -26,6 +26,7 @@ import com.google.protobuf.AbstractMessage; @@ -26,6 +26,7 @@ import com.google.protobuf.AbstractMessage;
26 import com.google.protobuf.InvalidProtocolBufferException; 26 import com.google.protobuf.InvalidProtocolBufferException;
27 import com.google.protobuf.MessageLite; 27 import com.google.protobuf.MessageLite;
28 import lombok.extern.slf4j.Slf4j; 28 import lombok.extern.slf4j.Slf4j;
  29 +import org.apache.commons.lang.RandomStringUtils;
29 import org.junit.After; 30 import org.junit.After;
30 import org.junit.Assert; 31 import org.junit.Assert;
31 import org.junit.Before; 32 import org.junit.Before;
@@ -962,6 +963,7 @@ abstract public class BaseEdgeTest extends AbstractControllerTest { @@ -962,6 +963,7 @@ abstract public class BaseEdgeTest extends AbstractControllerTest {
962 private void testSendMessagesToCloud() throws Exception { 963 private void testSendMessagesToCloud() throws Exception {
963 log.info("Sending messages to cloud"); 964 log.info("Sending messages to cloud");
964 sendDevice(); 965 sendDevice();
  966 + sendDeviceWithNameThatAlreadyExistsOnCloud();
965 sendRelationRequest(); 967 sendRelationRequest();
966 sendAlarm(); 968 sendAlarm();
967 sendTelemetry(); 969 sendTelemetry();
@@ -972,8 +974,7 @@ abstract public class BaseEdgeTest extends AbstractControllerTest { @@ -972,8 +974,7 @@ abstract public class BaseEdgeTest extends AbstractControllerTest {
972 sendDeviceCredentialsRequest(); 974 sendDeviceCredentialsRequest();
973 sendDeviceRpcResponse(); 975 sendDeviceRpcResponse();
974 sendDeviceCredentialsUpdate(); 976 sendDeviceCredentialsUpdate();
975 - // TODO: voba - fix this test  
976 - // sendAttributesRequest(); 977 + sendAttributesRequest();
977 log.info("Messages were sent successfully"); 978 log.info("Messages were sent successfully");
978 } 979 }
979 980
@@ -991,17 +992,64 @@ abstract public class BaseEdgeTest extends AbstractControllerTest { @@ -991,17 +992,64 @@ abstract public class BaseEdgeTest extends AbstractControllerTest {
991 uplinkMsgBuilder.addDeviceUpdateMsg(deviceUpdateMsgBuilder.build()); 992 uplinkMsgBuilder.addDeviceUpdateMsg(deviceUpdateMsgBuilder.build());
992 993
993 edgeImitator.expectResponsesAmount(1); 994 edgeImitator.expectResponsesAmount(1);
  995 + edgeImitator.expectMessageAmount(1);
  996 + testAutoGeneratedCodeByProtobuf(uplinkMsgBuilder);
  997 +
  998 + edgeImitator.sendUplinkMsg(uplinkMsgBuilder.build());
  999 +
  1000 + edgeImitator.waitForResponses();
  1001 + edgeImitator.waitForMessages();
  1002 +
  1003 + AbstractMessage latestMessage = edgeImitator.getLatestMessage();
  1004 + Assert.assertTrue(latestMessage instanceof DeviceUpdateMsg);
  1005 + DeviceUpdateMsg latestDeviceUpdateMsg = (DeviceUpdateMsg) latestMessage;
  1006 + Assert.assertEquals("Edge Device 2", latestDeviceUpdateMsg.getName());
  1007 +
  1008 + UUID newDeviceId = new UUID(latestDeviceUpdateMsg.getIdMSB(), latestDeviceUpdateMsg.getIdLSB());
  1009 +
  1010 + Device device = doGet("/api/device/" + newDeviceId, Device.class);
  1011 + Assert.assertNotNull(device);
  1012 + Assert.assertEquals("Edge Device 2", device.getName());
  1013 + }
994 1014
  1015 + private void sendDeviceWithNameThatAlreadyExistsOnCloud() throws Exception {
  1016 + String deviceOnCloudName = RandomStringUtils.randomAlphanumeric(15);
  1017 + Device deviceOnCloud = saveDevice(deviceOnCloudName);
  1018 +
  1019 + UUID uuid = Uuids.timeBased();
  1020 +
  1021 + UplinkMsg.Builder uplinkMsgBuilder = UplinkMsg.newBuilder();
  1022 + DeviceUpdateMsg.Builder deviceUpdateMsgBuilder = DeviceUpdateMsg.newBuilder();
  1023 + deviceUpdateMsgBuilder.setIdMSB(uuid.getMostSignificantBits());
  1024 + deviceUpdateMsgBuilder.setIdLSB(uuid.getLeastSignificantBits());
  1025 + deviceUpdateMsgBuilder.setName(deviceOnCloudName);
  1026 + deviceUpdateMsgBuilder.setType("test");
  1027 + deviceUpdateMsgBuilder.setMsgType(UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE);
  1028 + testAutoGeneratedCodeByProtobuf(deviceUpdateMsgBuilder);
  1029 + uplinkMsgBuilder.addDeviceUpdateMsg(deviceUpdateMsgBuilder.build());
  1030 +
  1031 + edgeImitator.expectResponsesAmount(1);
  1032 + edgeImitator.expectMessageAmount(1);
995 testAutoGeneratedCodeByProtobuf(uplinkMsgBuilder); 1033 testAutoGeneratedCodeByProtobuf(uplinkMsgBuilder);
996 1034
997 edgeImitator.sendUplinkMsg(uplinkMsgBuilder.build()); 1035 edgeImitator.sendUplinkMsg(uplinkMsgBuilder.build());
  1036 +
998 edgeImitator.waitForResponses(); 1037 edgeImitator.waitForResponses();
  1038 + edgeImitator.waitForMessages();
  1039 +
  1040 + AbstractMessage latestMessage = edgeImitator.getLatestMessage();
  1041 + Assert.assertTrue(latestMessage instanceof DeviceUpdateMsg);
  1042 + DeviceUpdateMsg latestDeviceUpdateMsg = (DeviceUpdateMsg) latestMessage;
  1043 + Assert.assertNotEquals(deviceOnCloudName, latestDeviceUpdateMsg.getName());
  1044 + Assert.assertEquals(deviceOnCloudName, latestDeviceUpdateMsg.getConflictName());
999 1045
1000 - // TODO: voba - add proper validation once DeviceProcessor 1046 + UUID newDeviceId = new UUID(latestDeviceUpdateMsg.getIdMSB(), latestDeviceUpdateMsg.getIdLSB());
1001 1047
1002 -// Device device = doGet("/api/device/" + uuid.toString(), Device.class);  
1003 -// Assert.assertNotNull(device);  
1004 -// Assert.assertEquals("Edge Device 2", device.getName()); 1048 + Assert.assertNotEquals(deviceOnCloud.getId().getId(), newDeviceId);
  1049 +
  1050 + Device device = doGet("/api/device/" + newDeviceId, Device.class);
  1051 + Assert.assertNotNull(device);
  1052 + Assert.assertNotEquals(deviceOnCloudName, device.getName());
1005 } 1053 }
1006 1054
1007 private void sendRelationRequest() throws Exception { 1055 private void sendRelationRequest() throws Exception {
@@ -34,5 +34,5 @@ public enum EdgeEventActionType { @@ -34,5 +34,5 @@ public enum EdgeEventActionType {
34 ASSIGNED_TO_EDGE, 34 ASSIGNED_TO_EDGE,
35 UNASSIGNED_FROM_EDGE, 35 UNASSIGNED_FROM_EDGE,
36 CREDENTIALS_REQUEST, 36 CREDENTIALS_REQUEST,
37 - ENTITY_EXISTS_REQUEST 37 + ENTITY_MERGE_REQUEST
38 } 38 }
@@ -97,7 +97,7 @@ enum UpdateMsgType { @@ -97,7 +97,7 @@ enum UpdateMsgType {
97 ENTITY_DELETED_RPC_MESSAGE = 2; 97 ENTITY_DELETED_RPC_MESSAGE = 2;
98 ALARM_ACK_RPC_MESSAGE = 3; 98 ALARM_ACK_RPC_MESSAGE = 3;
99 ALARM_CLEAR_RPC_MESSAGE = 4; 99 ALARM_CLEAR_RPC_MESSAGE = 4;
100 - DEVICE_CONFLICT_RPC_MESSAGE = 5; 100 + ENTITY_MERGE_RPC_MESSAGE = 5;
101 } 101 }
102 102
103 message EntityDataProto { 103 message EntityDataProto {
@@ -182,6 +182,7 @@ message DeviceUpdateMsg { @@ -182,6 +182,7 @@ message DeviceUpdateMsg {
182 string type = 7; 182 string type = 7;
183 string label = 8; 183 string label = 8;
184 string additionalInfo = 9; 184 string additionalInfo = 9;
  185 + string conflictName = 10;
185 } 186 }
186 187
187 message DeviceCredentialsUpdateMsg { 188 message DeviceCredentialsUpdateMsg {
@@ -109,6 +109,7 @@ import org.thingsboard.server.common.data.rule.DefaultRuleChainCreateRequest; @@ -109,6 +109,7 @@ import org.thingsboard.server.common.data.rule.DefaultRuleChainCreateRequest;
109 import org.thingsboard.server.common.data.rule.RuleChain; 109 import org.thingsboard.server.common.data.rule.RuleChain;
110 import org.thingsboard.server.common.data.rule.RuleChainData; 110 import org.thingsboard.server.common.data.rule.RuleChainData;
111 import org.thingsboard.server.common.data.rule.RuleChainMetaData; 111 import org.thingsboard.server.common.data.rule.RuleChainMetaData;
  112 +import org.thingsboard.server.common.data.rule.RuleChainType;
112 import org.thingsboard.server.common.data.security.DeviceCredentials; 113 import org.thingsboard.server.common.data.security.DeviceCredentials;
113 import org.thingsboard.server.common.data.security.DeviceCredentialsType; 114 import org.thingsboard.server.common.data.security.DeviceCredentialsType;
114 import org.thingsboard.server.common.data.security.model.SecuritySettings; 115 import org.thingsboard.server.common.data.security.model.SecuritySettings;
@@ -120,6 +121,7 @@ import org.thingsboard.server.common.data.widget.WidgetsBundle; @@ -120,6 +121,7 @@ import org.thingsboard.server.common.data.widget.WidgetsBundle;
120 import java.io.Closeable; 121 import java.io.Closeable;
121 import java.io.IOException; 122 import java.io.IOException;
122 import java.net.URI; 123 import java.net.URI;
  124 +import java.util.Arrays;
123 import java.util.Collections; 125 import java.util.Collections;
124 import java.util.HashMap; 126 import java.util.HashMap;
125 import java.util.List; 127 import java.util.List;
@@ -700,22 +702,31 @@ public class RestClient implements ClientHttpRequestInterceptor, Closeable { @@ -700,22 +702,31 @@ public class RestClient implements ClientHttpRequestInterceptor, Closeable {
700 } 702 }
701 703
702 public List<ComponentDescriptor> getComponentDescriptorsByType(ComponentType componentType) { 704 public List<ComponentDescriptor> getComponentDescriptorsByType(ComponentType componentType) {
  705 + return getComponentDescriptorsByType(componentType, RuleChainType.CORE);
  706 + }
  707 +
  708 + public List<ComponentDescriptor> getComponentDescriptorsByType(ComponentType componentType, RuleChainType ruleChainType) {
703 return restTemplate.exchange( 709 return restTemplate.exchange(
704 - baseURL + "/api/components?componentType={componentType}", 710 + baseURL + "/api/components/" + componentType.name() + "/?ruleChainType={ruleChainType}",
705 HttpMethod.GET, HttpEntity.EMPTY, 711 HttpMethod.GET, HttpEntity.EMPTY,
706 new ParameterizedTypeReference<List<ComponentDescriptor>>() { 712 new ParameterizedTypeReference<List<ComponentDescriptor>>() {
707 }, 713 },
708 - componentType).getBody(); 714 + ruleChainType).getBody();
709 } 715 }
710 716
711 public List<ComponentDescriptor> getComponentDescriptorsByTypes(List<ComponentType> componentTypes) { 717 public List<ComponentDescriptor> getComponentDescriptorsByTypes(List<ComponentType> componentTypes) {
  718 + return getComponentDescriptorsByTypes(componentTypes, RuleChainType.CORE);
  719 + }
  720 +
  721 + public List<ComponentDescriptor> getComponentDescriptorsByTypes(List<ComponentType> componentTypes, RuleChainType ruleChainType) {
712 return restTemplate.exchange( 722 return restTemplate.exchange(
713 - baseURL + "/api/components?componentTypes={componentTypes}", 723 + baseURL + "/api/components?componentTypes={componentTypes}&ruleChainType={ruleChainType}",
714 HttpMethod.GET, 724 HttpMethod.GET,
715 HttpEntity.EMPTY, 725 HttpEntity.EMPTY,
716 new ParameterizedTypeReference<List<ComponentDescriptor>>() { 726 new ParameterizedTypeReference<List<ComponentDescriptor>>() {
717 }, 727 },
718 - listEnumToString(componentTypes)) 728 + listEnumToString(componentTypes),
  729 + ruleChainType)
719 .getBody(); 730 .getBody();
720 } 731 }
721 732
@@ -1117,6 +1117,7 @@ @@ -1117,6 +1117,7 @@
1117 "edge": { 1117 "edge": {
1118 "edge": "Edge", 1118 "edge": "Edge",
1119 "edges": "Edges", 1119 "edges": "Edges",
  1120 + "edge-file": "Edge file",
1120 "management": "Edge management", 1121 "management": "Edge management",
1121 "no-edges-matching": "No edges matching '{{entity}}' were found.", 1122 "no-edges-matching": "No edges matching '{{entity}}' were found.",
1122 "add": "Add Edge", 1123 "add": "Add Edge",
@@ -1173,17 +1174,19 @@ @@ -1173,17 +1174,19 @@
1173 "make-private-edge-text": "After the confirmation the edge and all its data will be made private and won't be accessible by others.", 1174 "make-private-edge-text": "After the confirmation the edge and all its data will be made private and won't be accessible by others.",
1174 "import": "Import edge", 1175 "import": "Import edge",
1175 "label": "Label", 1176 "label": "Label",
1176 - "load-entity-error": "Entity not found. Failed to load info", 1177 + "load-entity-error": "Failed to load data. Entity not found or has been deleted.",
1177 "assign-new-edge": "Assign new edge", 1178 "assign-new-edge": "Assign new edge",
1178 "manage-edge-dashboards": "Manage edge dashboards", 1179 "manage-edge-dashboards": "Manage edge dashboards",
1179 "unassign-from-edge": "Unassign from edge", 1180 "unassign-from-edge": "Unassign from edge",
1180 "dashboards": "Edge Dashboards", 1181 "dashboards": "Edge Dashboards",
1181 "manage-edge-rulechains": "Manage edge rule chains", 1182 "manage-edge-rulechains": "Manage edge rule chains",
  1183 + "rulechains": "Edge Rule Chains",
  1184 + "rulechain": "Edge Rule Chain",
1182 "edge-key": "Edge key", 1185 "edge-key": "Edge key",
1183 - "copy-edge-key": "Copy Edge key", 1186 + "copy-edge-key": "Copy edge key",
1184 "edge-key-copied-message": "Edge key has been copied to clipboard", 1187 "edge-key-copied-message": "Edge key has been copied to clipboard",
1185 "edge-secret": "Edge secret", 1188 "edge-secret": "Edge secret",
1186 - "copy-edge-secret": "Copy Edge secret", 1189 + "copy-edge-secret": "Copy edge secret",
1187 "edge-secret-copied-message": "Edge secret has been copied to clipboard", 1190 "edge-secret-copied-message": "Edge secret has been copied to clipboard",
1188 "manage-edge-assets": "Manage edge assets", 1191 "manage-edge-assets": "Manage edge assets",
1189 "manage-edge-devices": "Manage edge devices", 1192 "manage-edge-devices": "Manage edge devices",
@@ -1191,22 +1194,23 @@ @@ -1191,22 +1194,23 @@
1191 "assets": "Edge assets", 1194 "assets": "Edge assets",
1192 "devices": "Edge devices", 1195 "devices": "Edge devices",
1193 "entity-views": "Edge entity views", 1196 "entity-views": "Edge entity views",
1194 - "set-root-rulechain-text": "Please select root rule chain for edge(s)",  
1195 - "set-root-rulechain-to-edges": "Set root rule chain for Edge(s)",  
1196 - "set-root-rulechain-to-edges-text": "Set root rule chain for { count, plural, 1 {1 edge} other {# edges} }", 1197 + "set-root-rule-chain-text": "Please select root rule chain for edge(s)",
  1198 + "set-root-rule-chain-to-edges": "Set root rule chain for Edge(s)",
  1199 + "set-root-rule-chain-to-edges-text": "Set root rule chain for { count, plural, 1 {1 edge} other {# edges} }",
1197 "status": "Received by edge", 1200 "status": "Received by edge",
1198 "success": "Deployed", 1201 "success": "Deployed",
1199 "failed": "Pending", 1202 "failed": "Pending",
1200 "search": "Search edges", 1203 "search": "Search edges",
1201 "selected-edges": "{ count, plural, 1 {1 edge} other {# edges} } selected", 1204 "selected-edges": "{ count, plural, 1 {1 edge} other {# edges} } selected",
1202 - "enter-edge-type": "Enter entity view type",  
1203 "any-edge": "Any edge", 1205 "any-edge": "Any edge",
1204 "no-edge-types-matching": "No edge types matching '{{entitySubtype}}' were found.", 1206 "no-edge-types-matching": "No edge types matching '{{entitySubtype}}' were found.",
1205 "edge-type-list-empty": "No device types selected.", 1207 "edge-type-list-empty": "No device types selected.",
1206 "edge-types": "Edge types", 1208 "edge-types": "Edge types",
1207 "dashboard": "Edge dashboard", 1209 "dashboard": "Edge dashboard",
1208 "unassign-edges-action-title": "Unassign { count, plural, 1 {1 edge} other {# edges} } from customer", 1210 "unassign-edges-action-title": "Unassign { count, plural, 1 {1 edge} other {# edges} } from customer",
1209 - "enter-edge-type": "Enter edge type" 1211 + "enter-edge-type": "Enter edge type",
  1212 + "deployed": "Deployed",
  1213 + "pending": "Pending"
1210 }, 1214 },
1211 "error": { 1215 "error": {
1212 "unable-to-connect": "Unable to connect to the server! Please check your internet connection.", 1216 "unable-to-connect": "Unable to connect to the server! Please check your internet connection.",
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 -export default angular.module('thingsboard.api.edge', [])  
17 - .factory('edgeService', EdgeService)  
18 - .name;  
19 -  
20 -/*@ngInject*/  
21 -function EdgeService($http, $q, customerService) {  
22 -  
23 - var service = {  
24 - getEdges: getEdges,  
25 - getEdgesByIds: getEdgesByIds,  
26 - getEdge: getEdge,  
27 - deleteEdge: deleteEdge,  
28 - saveEdge: saveEdge,  
29 - getEdgeTypes: getEdgeTypes,  
30 - getTenantEdges: getTenantEdges,  
31 - getCustomerEdges: getCustomerEdges,  
32 - assignEdgeToCustomer: assignEdgeToCustomer,  
33 - unassignEdgeFromCustomer: unassignEdgeFromCustomer,  
34 - makeEdgePublic: makeEdgePublic,  
35 - setRootRuleChain: setRootRuleChain,  
36 - getEdgeEvents: getEdgeEvents,  
37 - syncEdge: syncEdge  
38 - };  
39 -  
40 - return service;  
41 -  
42 - function getEdges(pageLink, config) {  
43 - var deferred = $q.defer();  
44 - var url = '/api/edges?limit=' + pageLink.limit;  
45 - if (angular.isDefined(pageLink.textSearch)) {  
46 - url += '&textSearch=' + pageLink.textSearch;  
47 - }  
48 - if (angular.isDefined(pageLink.idOffset)) {  
49 - url += '&idOffset=' + pageLink.idOffset;  
50 - }  
51 - if (angular.isDefined(pageLink.textOffset)) {  
52 - url += '&textOffset=' + pageLink.textOffset;  
53 - }  
54 - $http.get(url, config).then(function success(response) {  
55 - deferred.resolve(response.data);  
56 - }, function fail() {  
57 - deferred.reject();  
58 - });  
59 - return deferred.promise;  
60 - }  
61 -  
62 - function getEdgesByIds(edgeIds, config) {  
63 - var deferred = $q.defer();  
64 - var ids = '';  
65 - for (var i=0;i<edgeIds.length;i++) {  
66 - if (i>0) {  
67 - ids += ',';  
68 - }  
69 - ids += edgeIds[i];  
70 - }  
71 - var url = '/api/edges?edgeIds=' + ids;  
72 - $http.get(url, config).then(function success(response) {  
73 - var entities = response.data;  
74 - entities.sort(function (entity1, entity2) {  
75 - var id1 = entity1.id.id;  
76 - var id2 = entity2.id.id;  
77 - var index1 = edgeIds.indexOf(id1);  
78 - var index2 = edgeIds.indexOf(id2);  
79 - return index1 - index2;  
80 - });  
81 - deferred.resolve(entities);  
82 - }, function fail() {  
83 - deferred.reject();  
84 - });  
85 - return deferred.promise;  
86 - }  
87 -  
88 - function getEdge(edgeId, config) {  
89 - var deferred = $q.defer();  
90 - var url = '/api/edge/' + edgeId;  
91 - $http.get(url, config).then(function success(response) {  
92 - deferred.resolve(response.data);  
93 - }, function fail(response) {  
94 - deferred.reject(response.data);  
95 - });  
96 - return deferred.promise;  
97 - }  
98 -  
99 - function saveEdge(edge) {  
100 - var deferred = $q.defer();  
101 - var url = '/api/edge';  
102 - $http.post(url, edge).then(function success(response) {  
103 - deferred.resolve(response.data);  
104 - }, function fail(response) {  
105 - deferred.reject(response.data);  
106 - });  
107 - return deferred.promise;  
108 - }  
109 -  
110 - function deleteEdge(edgeId) {  
111 - var deferred = $q.defer();  
112 - var url = '/api/edge/' + edgeId;  
113 - $http.delete(url).then(function success() {  
114 - deferred.resolve();  
115 - }, function fail(response) {  
116 - deferred.reject(response.data);  
117 - });  
118 - return deferred.promise;  
119 - }  
120 -  
121 - function getEdgeTypes(config) {  
122 - var deferred = $q.defer();  
123 - var url = '/api/edge/types';  
124 - $http.get(url, config).then(function success(response) {  
125 - deferred.resolve(response.data);  
126 - }, function fail() {  
127 - deferred.reject();  
128 - });  
129 - return deferred.promise;  
130 - }  
131 -  
132 - function getTenantEdges(pageLink, applyCustomersInfo, config, type) {  
133 - var deferred = $q.defer();  
134 - var url = '/api/tenant/edges?limit=' + pageLink.limit;  
135 - if (angular.isDefined(pageLink.textSearch)) {  
136 - url += '&textSearch=' + pageLink.textSearch;  
137 - }  
138 - if (angular.isDefined(pageLink.idOffset)) {  
139 - url += '&idOffset=' + pageLink.idOffset;  
140 - }  
141 - if (angular.isDefined(pageLink.textOffset)) {  
142 - url += '&textOffset=' + pageLink.textOffset;  
143 - }  
144 - if (angular.isDefined(type) && type.length) {  
145 - url += '&type=' + type;  
146 - }  
147 - $http.get(url, config).then(function success(response) {  
148 - if (applyCustomersInfo) {  
149 - customerService.applyAssignedCustomersInfo(response.data.data).then(  
150 - function success(data) {  
151 - response.data.data = data;  
152 - deferred.resolve(response.data);  
153 - },  
154 - function fail() {  
155 - deferred.reject();  
156 - }  
157 - );  
158 - } else {  
159 - deferred.resolve(response.data);  
160 - }  
161 - }, function fail() {  
162 - deferred.reject();  
163 - });  
164 - return deferred.promise;  
165 - }  
166 -  
167 - function getCustomerEdges(customerId, pageLink, applyCustomersInfo, config, type) {  
168 - var deferred = $q.defer();  
169 - var url = '/api/customer/' + customerId + '/edges?limit=' + pageLink.limit;  
170 - if (angular.isDefined(pageLink.textSearch)) {  
171 - url += '&textSearch=' + pageLink.textSearch;  
172 - }  
173 - if (angular.isDefined(pageLink.idOffset)) {  
174 - url += '&idOffset=' + pageLink.idOffset;  
175 - }  
176 - if (angular.isDefined(pageLink.textOffset)) {  
177 - url += '&textOffset=' + pageLink.textOffset;  
178 - }  
179 - if (angular.isDefined(type) && type.length) {  
180 - url += '&type=' + type;  
181 - }  
182 - $http.get(url, config).then(function success(response) {  
183 - if (applyCustomersInfo) {  
184 - customerService.applyAssignedCustomerInfo(response.data.data, customerId).then(  
185 - function success(data) {  
186 - response.data.data = data;  
187 - deferred.resolve(response.data);  
188 - },  
189 - function fail() {  
190 - deferred.reject();  
191 - }  
192 - );  
193 - } else {  
194 - deferred.resolve(response.data);  
195 - }  
196 - }, function fail() {  
197 - deferred.reject();  
198 - });  
199 -  
200 - return deferred.promise;  
201 - }  
202 -  
203 - function assignEdgeToCustomer(customerId, edgeId) {  
204 - var deferred = $q.defer();  
205 - var url = '/api/customer/' + customerId + '/edge/' + edgeId;  
206 - $http.post(url, null).then(function success(response) {  
207 - deferred.resolve(response.data);  
208 - }, function fail() {  
209 - deferred.reject();  
210 - });  
211 - return deferred.promise;  
212 - }  
213 -  
214 - function unassignEdgeFromCustomer(edgeId) {  
215 - var deferred = $q.defer();  
216 - var url = '/api/customer/edge/' + edgeId;  
217 - $http.delete(url).then(function success(response) {  
218 - deferred.resolve(response.data);  
219 - }, function fail() {  
220 - deferred.reject();  
221 - });  
222 - return deferred.promise;  
223 - }  
224 -  
225 - function makeEdgePublic(edgeId) {  
226 - var deferred = $q.defer();  
227 - var url = '/api/customer/public/edge/' + edgeId;  
228 - $http.post(url, null).then(function success(response) {  
229 - deferred.resolve(response.data);  
230 - }, function fail() {  
231 - deferred.reject();  
232 - });  
233 - return deferred.promise;  
234 - }  
235 -  
236 - function setRootRuleChain(edgeId, ruleChainId) {  
237 - var deferred = $q.defer();  
238 - var url = '/api/edge/' + edgeId + '/' + ruleChainId + '/root';  
239 - $http.post(url).then(function success(response) {  
240 - deferred.resolve(response.data);  
241 - }, function fail() {  
242 - deferred.reject();  
243 - });  
244 - return deferred.promise;  
245 - }  
246 -  
247 - function getEdgeEvents(edgeId, pageLink) {  
248 - var deferred = $q.defer();  
249 - var url = '/api/edge/' + edgeId + '/events' + '?limit=' + pageLink.limit;  
250 - if (angular.isDefined(pageLink.startTime) && pageLink.startTime != null) {  
251 - url += '&startTime=' + pageLink.startTime;  
252 - }  
253 - if (angular.isDefined(pageLink.endTime) && pageLink.endTime != null) {  
254 - url += '&endTime=' + pageLink.endTime;  
255 - }  
256 - if (angular.isDefined(pageLink.idOffset) && pageLink.idOffset != null) {  
257 - url += '&offset=' + pageLink.idOffset;  
258 - }  
259 - $http.get(url, null).then(function success(response) {  
260 - deferred.resolve(response.data);  
261 - }, function fail(response) {  
262 - deferred.reject(response.data);  
263 - });  
264 - return deferred.promise;  
265 - }  
266 -  
267 - function syncEdge(edgeId) {  
268 - var deferred = $q.defer();  
269 - var url = '/api/edge/sync';  
270 - $http.post(url, edgeId).then(function success(response) {  
271 - deferred.resolve(response);  
272 - }, function fail(response) {  
273 - deferred.reject(response.data);  
274 - });  
275 - return deferred.promise;  
276 - }  
277 -}  
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 -/*@ngInject*/  
17 -export default function AddAssetsToEdgeController(assetService, $mdDialog, $q, edgeId, assets) {  
18 -  
19 - var vm = this;  
20 -  
21 - vm.assets = assets;  
22 - vm.searchText = '';  
23 -  
24 - vm.assign = assign;  
25 - vm.cancel = cancel;  
26 - vm.hasData = hasData;  
27 - vm.noData = noData;  
28 - vm.searchAssetTextUpdated = searchAssetTextUpdated;  
29 - vm.toggleAssetSelection = toggleAssetSelection;  
30 -  
31 - vm.theAssets = {  
32 - getItemAtIndex: function (index) {  
33 - if (index > vm.assets.data.length) {  
34 - vm.theAssets.fetchMoreItems_(index);  
35 - return null;  
36 - }  
37 - var item = vm.assets.data[index];  
38 - if (item) {  
39 - item.indexNumber = index + 1;  
40 - }  
41 - return item;  
42 - },  
43 -  
44 - getLength: function () {  
45 - if (vm.assets.hasNext) {  
46 - return vm.assets.data.length + vm.assets.nextPageLink.limit;  
47 - } else {  
48 - return vm.assets.data.length;  
49 - }  
50 - },  
51 -  
52 - fetchMoreItems_: function () {  
53 - if (vm.assets.hasNext && !vm.assets.pending) {  
54 - vm.assets.pending = true;  
55 - assetService.getTenantAssets(vm.assets.nextPageLink, false).then(  
56 - function success(assets) {  
57 - vm.assets.data = vm.assets.data.concat(assets.data);  
58 - vm.assets.nextPageLink = assets.nextPageLink;  
59 - vm.assets.hasNext = assets.hasNext;  
60 - if (vm.assets.hasNext) {  
61 - vm.assets.nextPageLink.limit = vm.assets.pageSize;  
62 - }  
63 - vm.assets.pending = false;  
64 - },  
65 - function fail() {  
66 - vm.assets.hasNext = false;  
67 - vm.assets.pending = false;  
68 - });  
69 - }  
70 - }  
71 - };  
72 -  
73 - function cancel () {  
74 - $mdDialog.cancel();  
75 - }  
76 -  
77 - function assign() {  
78 - var tasks = [];  
79 - for (var assetId in vm.assets.selections) {  
80 - tasks.push(assetService.assignAssetToEdge(edgeId, assetId));  
81 - }  
82 - $q.all(tasks).then(function () {  
83 - $mdDialog.hide();  
84 - });  
85 - }  
86 -  
87 - function noData() {  
88 - return vm.assets.data.length == 0 && !vm.assets.hasNext;  
89 - }  
90 -  
91 - function hasData() {  
92 - return vm.assets.data.length > 0;  
93 - }  
94 -  
95 - function toggleAssetSelection($event, asset) {  
96 - $event.stopPropagation();  
97 - var selected = angular.isDefined(asset.selected) && asset.selected;  
98 - asset.selected = !selected;  
99 - if (asset.selected) {  
100 - vm.assets.selections[asset.id.id] = true;  
101 - vm.assets.selectedCount++;  
102 - } else {  
103 - delete vm.assets.selections[asset.id.id];  
104 - vm.assets.selectedCount--;  
105 - }  
106 - }  
107 -  
108 - function searchAssetTextUpdated() {  
109 - vm.assets = {  
110 - pageSize: vm.assets.pageSize,  
111 - data: [],  
112 - nextPageLink: {  
113 - limit: vm.assets.pageSize,  
114 - textSearch: vm.searchText  
115 - },  
116 - selections: {},  
117 - selectedCount: 0,  
118 - hasNext: true,  
119 - pending: false  
120 - };  
121 - }  
122 -  
123 -}  
1 -<!--  
2 -  
3 - Copyright © 2016-2020 The Thingsboard Authors  
4 -  
5 - Licensed under the Apache License, Version 2.0 (the "License");  
6 - you may not use this file except in compliance with the License.  
7 - You may obtain a copy of the License at  
8 -  
9 - http://www.apache.org/licenses/LICENSE-2.0  
10 -  
11 - Unless required by applicable law or agreed to in writing, software  
12 - distributed under the License is distributed on an "AS IS" BASIS,  
13 - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  
14 - See the License for the specific language governing permissions and  
15 - limitations under the License.  
16 -  
17 --->  
18 -<md-dialog aria-label="{{ 'edge.assign-to-edge' | translate }}">  
19 - <form name="theForm" ng-submit="vm.assign()">  
20 - <md-toolbar>  
21 - <div class="md-toolbar-tools">  
22 - <h2 translate>asset.assign-asset-to-edge</h2>  
23 - <span flex></span>  
24 - <md-button class="md-icon-button" ng-click="vm.cancel()">  
25 - <ng-md-icon icon="close" aria-label="{{ 'dialog.close' | translate }}"></ng-md-icon>  
26 - </md-button>  
27 - </div>  
28 - </md-toolbar>  
29 - <md-progress-linear class="md-warn" md-mode="indeterminate" ng-disabled="!$root.loading" ng-show="$root.loading"></md-progress-linear>  
30 - <span style="min-height: 5px;" flex="" ng-show="!$root.loading"></span>  
31 - <md-dialog-content>  
32 - <div class="md-dialog-content">  
33 - <fieldset>  
34 - <span translate>asset.assign-asset-to-edge-text</span>  
35 - <md-input-container class="md-block" style='margin-bottom: 0px;'>  
36 - <label>&nbsp;</label>  
37 - <md-icon aria-label="{{ 'action.search' | translate }}" class="material-icons">  
38 - search  
39 - </md-icon>  
40 - <input id="asset-search" autofocus ng-model="vm.searchText"  
41 - ng-change="vm.searchAssetTextUpdated()"  
42 - placeholder="{{ 'common.enter-search' | translate }}"/>  
43 - </md-input-container>  
44 - <div style='min-height: 150px;'>  
45 - <span translate layout-align="center center"  
46 - style="text-transform: uppercase; display: flex; height: 150px;"  
47 - class="md-subhead"  
48 - ng-show="vm.noData()">asset.no-assets-text</span>  
49 - <md-virtual-repeat-container ng-show="vm.hasData()"  
50 - tb-scope-element="repeatContainer" md-top-index="vm.topIndex" flex  
51 - style='min-height: 150px; width: 100%;'>  
52 - <md-list>  
53 - <md-list-item md-virtual-repeat="asset in vm.theAssets" md-on-demand  
54 - class="repeated-item" flex>  
55 - <md-checkbox ng-click="vm.toggleAssetSelection($event, asset)"  
56 - aria-label="{{ 'item.selected' | translate }}"  
57 - ng-checked="asset.selected"></md-checkbox>  
58 - <span> {{ asset.name }} </span>  
59 - </md-list-item>  
60 - </md-list>  
61 - </md-virtual-repeat-container>  
62 - </div>  
63 - </fieldset>  
64 - </div>  
65 - </md-dialog-content>  
66 - <md-dialog-actions layout="row">  
67 - <span flex></span>  
68 - <md-button ng-disabled="$root.loading || vm.assets.selectedCount == 0" type="submit"  
69 - class="md-raised md-primary">  
70 - {{ 'action.assign' | translate }}  
71 - </md-button>  
72 - <md-button ng-disabled="$root.loading" ng-click="vm.cancel()" style="margin-right:20px;">{{ 'action.cancel' |  
73 - translate }}  
74 - </md-button>  
75 - </md-dialog-actions>  
76 - </form>  
77 -</md-dialog>  
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 -/*@ngInject*/  
17 -export default function AddDashboardsToEdgeController(dashboardService, types, $mdDialog, $q, edgeId, dashboards) {  
18 -  
19 - var vm = this;  
20 -  
21 - vm.types = types;  
22 - vm.dashboards = dashboards;  
23 - vm.searchText = '';  
24 -  
25 - vm.assign = assign;  
26 - vm.cancel = cancel;  
27 - vm.hasData = hasData;  
28 - vm.noData = noData;  
29 - vm.searchDashboardTextUpdated = searchDashboardTextUpdated;  
30 - vm.toggleDashboardSelection = toggleDashboardSelection;  
31 -  
32 - vm.theDashboards = {  
33 - getItemAtIndex: function (index) {  
34 - if (index > vm.dashboards.data.length) {  
35 - vm.theDashboards.fetchMoreItems_(index);  
36 - return null;  
37 - }  
38 - var item = vm.dashboards.data[index];  
39 - if (item) {  
40 - item.indexNumber = index + 1;  
41 - }  
42 - return item;  
43 - },  
44 -  
45 - getLength: function () {  
46 - if (vm.dashboards.hasNext) {  
47 - return vm.dashboards.data.length + vm.dashboards.nextPageLink.limit;  
48 - } else {  
49 - return vm.dashboards.data.length;  
50 - }  
51 - },  
52 -  
53 - fetchMoreItems_: function () {  
54 - if (vm.dashboards.hasNext && !vm.dashboards.pending) {  
55 - vm.dashboards.pending = true;  
56 - dashboardService.getTenantDashboards(vm.dashboards.nextPageLink).then(  
57 - function success(dashboards) {  
58 - vm.dashboards.data = vm.dashboards.data.concat(dashboards.data);  
59 - vm.dashboards.nextPageLink = dashboards.nextPageLink;  
60 - vm.dashboards.hasNext = dashboards.hasNext;  
61 - if (vm.dashboards.hasNext) {  
62 - vm.dashboards.nextPageLink.limit = vm.dashboards.pageSize;  
63 - }  
64 - vm.dashboards.pending = false;  
65 - },  
66 - function fail() {  
67 - vm.dashboards.hasNext = false;  
68 - vm.dashboards.pending = false;  
69 - });  
70 - }  
71 - }  
72 - }  
73 -  
74 - function cancel () {  
75 - $mdDialog.cancel();  
76 - }  
77 -  
78 - function assign () {  
79 - var tasks = [];  
80 - for (var dashboardId in vm.dashboards.selections) {  
81 - tasks.push(dashboardService.assignDashboardToEdge(edgeId, dashboardId));  
82 - }  
83 - $q.all(tasks).then(function () {  
84 - $mdDialog.hide();  
85 - });  
86 - }  
87 -  
88 - function noData () {  
89 - return vm.dashboards.data.length == 0 && !vm.dashboards.hasNext;  
90 - }  
91 -  
92 - function hasData () {  
93 - return vm.dashboards.data.length > 0;  
94 - }  
95 -  
96 - function toggleDashboardSelection ($event, dashboard) {  
97 - $event.stopPropagation();  
98 - var selected = angular.isDefined(dashboard.selected) && dashboard.selected;  
99 - dashboard.selected = !selected;  
100 - if (dashboard.selected) {  
101 - vm.dashboards.selections[dashboard.id.id] = true;  
102 - vm.dashboards.selectedCount++;  
103 - } else {  
104 - delete vm.dashboards.selections[dashboard.id.id];  
105 - vm.dashboards.selectedCount--;  
106 - }  
107 - }  
108 -  
109 - function searchDashboardTextUpdated () {  
110 - vm.dashboards = {  
111 - pageSize: vm.dashboards.pageSize,  
112 - data: [],  
113 - nextPageLink: {  
114 - limit: vm.dashboards.pageSize,  
115 - textSearch: vm.searchText  
116 - },  
117 - selections: {},  
118 - selectedCount: 0,  
119 - hasNext: true,  
120 - pending: false  
121 - };  
122 - }  
123 -}  
1 -<!--  
2 -  
3 - Copyright © 2016-2020 The Thingsboard Authors  
4 -  
5 - Licensed under the Apache License, Version 2.0 (the "License");  
6 - you may not use this file except in compliance with the License.  
7 - You may obtain a copy of the License at  
8 -  
9 - http://www.apache.org/licenses/LICENSE-2.0  
10 -  
11 - Unless required by applicable law or agreed to in writing, software  
12 - distributed under the License is distributed on an "AS IS" BASIS,  
13 - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  
14 - See the License for the specific language governing permissions and  
15 - limitations under the License.  
16 -  
17 --->  
18 -<md-dialog aria-label="{{ 'dashboard.assign-dashboard-to-edge' | translate }}">  
19 - <form name="theForm" ng-submit="vm.assign()">  
20 - <md-toolbar>  
21 - <div class="md-toolbar-tools">  
22 - <h2 translate>dashboard.assign-dashboard-to-edge</h2>  
23 - <span flex></span>  
24 - <md-button class="md-icon-button" ng-click="vm.cancel()">  
25 - <ng-md-icon icon="close" aria-label="{{ 'dialog.close' | translate }}"></ng-md-icon>  
26 - </md-button>  
27 - </div>  
28 - </md-toolbar>  
29 - <md-progress-linear class="md-warn" md-mode="indeterminate" ng-disabled="!$root.loading" ng-show="$root.loading"></md-progress-linear>  
30 - <span style="min-height: 5px;" flex="" ng-show="!$root.loading"></span>  
31 - <md-dialog-content>  
32 - <div class="md-dialog-content">  
33 - <fieldset>  
34 - <span translate>dashboard.assign-dashboard-to-edge-text</span>  
35 - <md-input-container class="md-block" style='margin-bottom: 0px;'>  
36 - <label>&nbsp;</label>  
37 - <md-icon aria-label="{{ 'action.search' | translate }}" class="material-icons">  
38 - search  
39 - </md-icon>  
40 - <input id="dashboard-search" autofocus ng-model="vm.searchText"  
41 - ng-change="vm.searchDashboardTextUpdated()"  
42 - placeholder="{{ 'common.enter-search' | translate }}"/>  
43 - </md-input-container>  
44 - <div style='min-height: 150px;'>  
45 - <span translate layout-align="center center"  
46 - style="text-transform: uppercase; display: flex; height: 150px;"  
47 - class="md-subhead"  
48 - ng-show="vm.noData()">dashboard.no-dashboards-text</span>  
49 - <md-virtual-repeat-container ng-show="vm.hasData()"  
50 - tb-scope-element="repeatContainer" md-top-index="vm.topIndex" flex  
51 - style='min-height: 150px; width: 100%;'>  
52 - <md-list>  
53 - <md-list-item md-virtual-repeat="dashboard in vm.theDashboards" md-on-demand  
54 - class="repeated-item" flex>  
55 - <md-checkbox ng-click="vm.toggleDashboardSelection($event, dashboard)"  
56 - aria-label="{{ 'item.selected' | translate }}"  
57 - ng-checked="dashboard.selected"></md-checkbox>  
58 - <span> {{ dashboard.title }} </span>  
59 - </md-list-item>  
60 - </md-list>  
61 - </md-virtual-repeat-container>  
62 - </div>  
63 - </fieldset>  
64 - </div>  
65 - </md-dialog-content>  
66 - <md-dialog-actions layout="row">  
67 - <span flex></span>  
68 - <md-button ng-disabled="$root.loading || vm.dashboards.selectedCount == 0" type="submit"  
69 - class="md-raised md-primary">  
70 - {{ 'action.assign' | translate }}  
71 - </md-button>  
72 - <md-button ng-disabled="$root.loading" ng-click="vm.cancel()" style="margin-right:20px;">{{ 'action.cancel' |  
73 - translate }}  
74 - </md-button>  
75 - </md-dialog-actions>  
76 - </form>  
77 -</md-dialog>  
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 -/*@ngInject*/  
17 -export default function AddDevicesToEdgeController(deviceService, $mdDialog, $q, edgeId, devices) {  
18 -  
19 - var vm = this;  
20 -  
21 - vm.devices = devices;  
22 - vm.searchText = '';  
23 -  
24 - vm.assign = assign;  
25 - vm.cancel = cancel;  
26 - vm.hasData = hasData;  
27 - vm.noData = noData;  
28 - vm.searchDeviceTextUpdated = searchDeviceTextUpdated;  
29 - vm.toggleDeviceSelection = toggleDeviceSelection;  
30 -  
31 - vm.theDevices = {  
32 - getItemAtIndex: function (index) {  
33 - if (index > vm.devices.data.length) {  
34 - vm.theDevices.fetchMoreItems_(index);  
35 - return null;  
36 - }  
37 - var item = vm.devices.data[index];  
38 - if (item) {  
39 - item.indexNumber = index + 1;  
40 - }  
41 - return item;  
42 - },  
43 -  
44 - getLength: function () {  
45 - if (vm.devices.hasNext) {  
46 - return vm.devices.data.length + vm.devices.nextPageLink.limit;  
47 - } else {  
48 - return vm.devices.data.length;  
49 - }  
50 - },  
51 -  
52 - fetchMoreItems_: function () {  
53 - if (vm.devices.hasNext && !vm.devices.pending) {  
54 - vm.devices.pending = true;  
55 - deviceService.getTenantDevices(vm.devices.nextPageLink, false).then(  
56 - function success(devices) {  
57 - vm.devices.data = vm.devices.data.concat(devices.data);  
58 - vm.devices.nextPageLink = devices.nextPageLink;  
59 - vm.devices.hasNext = devices.hasNext;  
60 - if (vm.devices.hasNext) {  
61 - vm.devices.nextPageLink.limit = vm.devices.pageSize;  
62 - }  
63 - vm.devices.pending = false;  
64 - },  
65 - function fail() {  
66 - vm.devices.hasNext = false;  
67 - vm.devices.pending = false;  
68 - });  
69 - }  
70 - }  
71 - };  
72 -  
73 - function cancel () {  
74 - $mdDialog.cancel();  
75 - }  
76 -  
77 - function assign() {  
78 - var tasks = [];  
79 - for (var deviceId in vm.devices.selections) {  
80 - tasks.push(deviceService.assignDeviceToEdge(edgeId, deviceId));  
81 - }  
82 - $q.all(tasks).then(function () {  
83 - $mdDialog.hide();  
84 - });  
85 - }  
86 -  
87 - function noData() {  
88 - return vm.devices.data.length == 0 && !vm.devices.hasNext;  
89 - }  
90 -  
91 - function hasData() {  
92 - return vm.devices.data.length > 0;  
93 - }  
94 -  
95 - function toggleDeviceSelection($event, device) {  
96 - $event.stopPropagation();  
97 - var selected = angular.isDefined(device.selected) && device.selected;  
98 - device.selected = !selected;  
99 - if (device.selected) {  
100 - vm.devices.selections[device.id.id] = true;  
101 - vm.devices.selectedCount++;  
102 - } else {  
103 - delete vm.devices.selections[device.id.id];  
104 - vm.devices.selectedCount--;  
105 - }  
106 - }  
107 -  
108 - function searchDeviceTextUpdated() {  
109 - vm.devices = {  
110 - pageSize: vm.devices.pageSize,  
111 - data: [],  
112 - nextPageLink: {  
113 - limit: vm.devices.pageSize,  
114 - textSearch: vm.searchText  
115 - },  
116 - selections: {},  
117 - selectedCount: 0,  
118 - hasNext: true,  
119 - pending: false  
120 - };  
121 - }  
122 -  
123 -}  
1 -<!--  
2 -  
3 - Copyright © 2016-2020 The Thingsboard Authors  
4 -  
5 - Licensed under the Apache License, Version 2.0 (the "License");  
6 - you may not use this file except in compliance with the License.  
7 - You may obtain a copy of the License at  
8 -  
9 - http://www.apache.org/licenses/LICENSE-2.0  
10 -  
11 - Unless required by applicable law or agreed to in writing, software  
12 - distributed under the License is distributed on an "AS IS" BASIS,  
13 - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  
14 - See the License for the specific language governing permissions and  
15 - limitations under the License.  
16 -  
17 --->  
18 -<md-dialog aria-label="{{ 'edge.assign-to-edge' | translate }}">  
19 - <form name="theForm" ng-submit="vm.assign()">  
20 - <md-toolbar>  
21 - <div class="md-toolbar-tools">  
22 - <h2 translate>device.assign-device-to-edge</h2>  
23 - <span flex></span>  
24 - <md-button class="md-icon-button" ng-click="vm.cancel()">  
25 - <ng-md-icon icon="close" aria-label="{{ 'dialog.close' | translate }}"></ng-md-icon>  
26 - </md-button>  
27 - </div>  
28 - </md-toolbar>  
29 - <md-progress-linear class="md-warn" md-mode="indeterminate" ng-disabled="!$root.loading" ng-show="$root.loading"></md-progress-linear>  
30 - <span style="min-height: 5px;" flex="" ng-show="!$root.loading"></span>  
31 - <md-dialog-content>  
32 - <div class="md-dialog-content">  
33 - <fieldset>  
34 - <span translate>device.assign-device-to-edge-text</span>  
35 - <md-input-container class="md-block" style='margin-bottom: 0px;'>  
36 - <label>&nbsp;</label>  
37 - <md-icon aria-label="{{ 'action.search' | translate }}" class="material-icons">  
38 - search  
39 - </md-icon>  
40 - <input id="device-search" autofocus ng-model="vm.searchText"  
41 - ng-change="vm.searchDeviceTextUpdated()"  
42 - placeholder="{{ 'common.enter-search' | translate }}"/>  
43 - </md-input-container>  
44 - <div style='min-height: 150px;'>  
45 - <span translate layout-align="center center"  
46 - style="text-transform: uppercase; display: flex; height: 150px;"  
47 - class="md-subhead"  
48 - ng-show="vm.noData()">device.no-devices-text</span>  
49 - <md-virtual-repeat-container ng-show="vm.hasData()"  
50 - tb-scope-element="repeatContainer" md-top-index="vm.topIndex" flex  
51 - style='min-height: 150px; width: 100%;'>  
52 - <md-list>  
53 - <md-list-item md-virtual-repeat="device in vm.theDevices" md-on-demand  
54 - class="repeated-item" flex>  
55 - <md-checkbox ng-click="vm.toggleDeviceSelection($event, device)"  
56 - aria-label="{{ 'item.selected' | translate }}"  
57 - ng-checked="device.selected"></md-checkbox>  
58 - <span> {{ device.name }} </span>  
59 - </md-list-item>  
60 - </md-list>  
61 - </md-virtual-repeat-container>  
62 - </div>  
63 - </fieldset>  
64 - </div>  
65 - </md-dialog-content>  
66 - <md-dialog-actions layout="row">  
67 - <span flex></span>  
68 - <md-button ng-disabled="$root.loading || vm.devices.selectedCount == 0" type="submit"  
69 - class="md-raised md-primary">  
70 - {{ 'action.assign' | translate }}  
71 - </md-button>  
72 - <md-button ng-disabled="$root.loading" ng-click="vm.cancel()" style="margin-right:20px;">{{ 'action.cancel' |  
73 - translate }}  
74 - </md-button>  
75 - </md-dialog-actions>  
76 - </form>  
77 -</md-dialog>  
1 -<!--  
2 -  
3 - Copyright © 2016-2020 The Thingsboard Authors  
4 -  
5 - Licensed under the Apache License, Version 2.0 (the "License");  
6 - you may not use this file except in compliance with the License.  
7 - You may obtain a copy of the License at  
8 -  
9 - http://www.apache.org/licenses/LICENSE-2.0  
10 -  
11 - Unless required by applicable law or agreed to in writing, software  
12 - distributed under the License is distributed on an "AS IS" BASIS,  
13 - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  
14 - See the License for the specific language governing permissions and  
15 - limitations under the License.  
16 -  
17 --->  
18 -<md-dialog aria-label="{{ 'edge.add' | translate }}" tb-help="'edges'" help-container-id="help-container" style="width: 600px;">  
19 - <form name="theForm" ng-submit="vm.add()">  
20 - <md-toolbar>  
21 - <div class="md-toolbar-tools">  
22 - <h2 translate>edge.add</h2>  
23 - <span flex></span>  
24 - <div id="help-container"></div>  
25 - <md-button class="md-icon-button" ng-click="vm.cancel()">  
26 - <ng-md-icon icon="close" aria-label="{{ 'dialog.close' | translate }}"></ng-md-icon>  
27 - </md-button>  
28 - </div>  
29 - </md-toolbar>  
30 - <md-progress-linear class="md-warn" md-mode="indeterminate" ng-disabled="!$root.loading" ng-show="$root.loading"></md-progress-linear>  
31 - <span style="min-height: 5px;" flex="" ng-show="!$root.loading"></span>  
32 - <md-dialog-content>  
33 - <div class="md-dialog-content">  
34 - <tb-edge edge="vm.item" is-edit="true" is-create="true" the-form="theForm"></tb-edge>  
35 - </div>  
36 - </md-dialog-content>  
37 - <md-dialog-actions layout="row">  
38 - <span flex></span>  
39 - <md-button ng-disabled="$root.loading || theForm.$invalid || !theForm.$dirty" type="submit" class="md-raised md-primary">  
40 - {{ 'action.add' | translate }}  
41 - </md-button>  
42 - <md-button ng-disabled="$root.loading" ng-click="vm.cancel()" style="margin-right:20px;">{{ 'action.cancel' | translate }}</md-button>  
43 - </md-dialog-actions>  
44 - </form>  
45 -</md-dialog>  
46 -  
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 -/*@ngInject*/  
17 -export default function AddEdgesToCustomerController(edgeService, $mdDialog, $q, customerId, edges) {  
18 -  
19 - var vm = this;  
20 -  
21 - vm.edges = edges;  
22 - vm.searchText = '';  
23 -  
24 - vm.assign = assign;  
25 - vm.cancel = cancel;  
26 - vm.hasData = hasData;  
27 - vm.noData = noData;  
28 - vm.searchEdgeTextUpdated = searchEdgeTextUpdated;  
29 - vm.toggleEdgeSelection = toggleEdgeSelection;  
30 -  
31 - vm.theEdges = {  
32 - getItemAtIndex: function (index) {  
33 - if (index > vm.edges.data.length) {  
34 - vm.theEdges.fetchMoreItems_(index);  
35 - return null;  
36 - }  
37 - var item = vm.edges.data[index];  
38 - if (item) {  
39 - item.indexNumber = index + 1;  
40 - }  
41 - return item;  
42 - },  
43 -  
44 - getLength: function () {  
45 - if (vm.edges.hasNext) {  
46 - return vm.edges.data.length + vm.edges.nextPageLink.limit;  
47 - } else {  
48 - return vm.edges.data.length;  
49 - }  
50 - },  
51 -  
52 - fetchMoreItems_: function () {  
53 - if (vm.edges.hasNext && !vm.edges.pending) {  
54 - vm.edges.pending = true;  
55 - edgeService.getTenantEdges(vm.edges.nextPageLink, false).then(  
56 - function success(edges) {  
57 - vm.edges.data = vm.edges.data.concat(edges.data);  
58 - vm.edges.nextPageLink = edges.nextPageLink;  
59 - vm.edges.hasNext = edges.hasNext;  
60 - if (vm.edges.hasNext) {  
61 - vm.edges.nextPageLink.limit = vm.edges.pageSize;  
62 - }  
63 - vm.edges.pending = false;  
64 - },  
65 - function fail() {  
66 - vm.edges.hasNext = false;  
67 - vm.edges.pending = false;  
68 - });  
69 - }  
70 - }  
71 - };  
72 -  
73 - function cancel () {  
74 - $mdDialog.cancel();  
75 - }  
76 -  
77 - function assign() {  
78 - var tasks = [];  
79 - for (var edgeId in vm.edges.selections) {  
80 - tasks.push(edgeService.assignEdgeToCustomer(customerId, edgeId));  
81 - }  
82 - $q.all(tasks).then(function () {  
83 - $mdDialog.hide();  
84 - });  
85 - }  
86 -  
87 - function noData() {  
88 - return vm.edges.data.length == 0 && !vm.edges.hasNext;  
89 - }  
90 -  
91 - function hasData() {  
92 - return vm.edges.data.length > 0;  
93 - }  
94 -  
95 - function toggleEdgeSelection($event, edge) {  
96 - $event.stopPropagation();  
97 - var selected = angular.isDefined(edge.selected) && edge.selected;  
98 - edge.selected = !selected;  
99 - if (edge.selected) {  
100 - vm.edges.selections[edge.id.id] = true;  
101 - vm.edges.selectedCount++;  
102 - } else {  
103 - delete vm.edges.selections[edge.id.id];  
104 - vm.edges.selectedCount--;  
105 - }  
106 - }  
107 -  
108 - function searchEdgeTextUpdated() {  
109 - vm.edges = {  
110 - pageSize: vm.edges.pageSize,  
111 - data: [],  
112 - nextPageLink: {  
113 - limit: vm.edges.pageSize,  
114 - textSearch: vm.searchText  
115 - },  
116 - selections: {},  
117 - selectedCount: 0,  
118 - hasNext: true,  
119 - pending: false  
120 - };  
121 - }  
122 -  
123 -}  
1 -<!--  
2 -  
3 - Copyright © 2016-2020 The Thingsboard Authors  
4 -  
5 - Licensed under the Apache License, Version 2.0 (the "License");  
6 - you may not use this file except in compliance with the License.  
7 - You may obtain a copy of the License at  
8 -  
9 - http://www.apache.org/licenses/LICENSE-2.0  
10 -  
11 - Unless required by applicable law or agreed to in writing, software  
12 - distributed under the License is distributed on an "AS IS" BASIS,  
13 - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  
14 - See the License for the specific language governing permissions and  
15 - limitations under the License.  
16 -  
17 --->  
18 -<md-dialog aria-label="{{ 'edge.assign-to-customer' | translate }}">  
19 - <form name="theForm" ng-submit="vm.assign()">  
20 - <md-toolbar>  
21 - <div class="md-toolbar-tools">  
22 - <h2 translate>edge.assign-edge-to-customer</h2>  
23 - <span flex></span>  
24 - <md-button class="md-icon-button" ng-click="vm.cancel()">  
25 - <ng-md-icon icon="close" aria-label="{{ 'dialog.close' | translate }}"></ng-md-icon>  
26 - </md-button>  
27 - </div>  
28 - </md-toolbar>  
29 - <md-progress-linear class="md-warn" md-mode="indeterminate" ng-disabled="!$root.loading" ng-show="$root.loading"></md-progress-linear>  
30 - <span style="min-height: 5px;" flex="" ng-show="!$root.loading"></span>  
31 - <md-dialog-content>  
32 - <div class="md-dialog-content">  
33 - <fieldset>  
34 - <span translate>edge.assign-edge-to-customer-text</span>  
35 - <md-input-container class="md-block" style='margin-bottom: 0px;'>  
36 - <label>&nbsp;</label>  
37 - <md-icon aria-label="{{ 'action.search' | translate }}" class="material-icons">  
38 - search  
39 - </md-icon>  
40 - <input id="edge-search" autofocus ng-model="vm.searchText"  
41 - ng-change="vm.searchEdgeTextUpdated()"  
42 - placeholder="{{ 'common.enter-search' | translate }}"/>  
43 - </md-input-container>  
44 - <div style='min-height: 150px;'>  
45 - <span translate layout-align="center center"  
46 - style="text-transform: uppercase; display: flex; height: 150px;"  
47 - class="md-subhead"  
48 - ng-show="vm.noData()">edge.no-edges-text</span>  
49 - <md-virtual-repeat-container ng-show="vm.hasData()"  
50 - tb-scope-element="repeatContainer" md-top-index="vm.topIndex" flex  
51 - style='min-height: 150px; width: 100%;'>  
52 - <md-list>  
53 - <md-list-item md-virtual-repeat="edge in vm.theEdges" md-on-demand  
54 - class="repeated-item" flex>  
55 - <md-checkbox ng-click="vm.toggleEdgeSelection($event, edge)"  
56 - aria-label="{{ 'item.selected' | translate }}"  
57 - ng-checked="edge.selected"></md-checkbox>  
58 - <span> {{ edge.name }} </span>  
59 - </md-list-item>  
60 - </md-list>  
61 - </md-virtual-repeat-container>  
62 - </div>  
63 - </fieldset>  
64 - </div>  
65 - </md-dialog-content>  
66 - <md-dialog-actions layout="row">  
67 - <span flex></span>  
68 - <md-button ng-disabled="$root.loading || vm.edges.selectedCount == 0" type="submit"  
69 - class="md-raised md-primary">  
70 - {{ 'action.assign' | translate }}  
71 - </md-button>  
72 - <md-button ng-disabled="$root.loading" ng-click="vm.cancel()" style="margin-right:20px;">{{ 'action.cancel' |  
73 - translate }}  
74 - </md-button>  
75 - </md-dialog-actions>  
76 - </form>  
77 -</md-dialog>  
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 -/*@ngInject*/  
17 -export default function AssignEdgeToCustomerController(customerService, edgeService, $mdDialog, $q, edgeIds, customers) {  
18 -  
19 - var vm = this;  
20 -  
21 - vm.customers = customers;  
22 - vm.searchText = '';  
23 -  
24 - vm.assign = assign;  
25 - vm.cancel = cancel;  
26 - vm.isCustomerSelected = isCustomerSelected;  
27 - vm.hasData = hasData;  
28 - vm.noData = noData;  
29 - vm.searchCustomerTextUpdated = searchCustomerTextUpdated;  
30 - vm.toggleCustomerSelection = toggleCustomerSelection;  
31 -  
32 - vm.theCustomers = {  
33 - getItemAtIndex: function (index) {  
34 - if (index > vm.customers.data.length) {  
35 - vm.theCustomers.fetchMoreItems_(index);  
36 - return null;  
37 - }  
38 - var item = vm.customers.data[index];  
39 - if (item) {  
40 - item.indexNumber = index + 1;  
41 - }  
42 - return item;  
43 - },  
44 -  
45 - getLength: function () {  
46 - if (vm.customers.hasNext) {  
47 - return vm.customers.data.length + vm.customers.nextPageLink.limit;  
48 - } else {  
49 - return vm.customers.data.length;  
50 - }  
51 - },  
52 -  
53 - fetchMoreItems_: function () {  
54 - if (vm.customers.hasNext && !vm.customers.pending) {  
55 - vm.customers.pending = true;  
56 - customerService.getCustomers(vm.customers.nextPageLink).then(  
57 - function success(customers) {  
58 - vm.customers.data = vm.customers.data.concat(customers.data);  
59 - vm.customers.nextPageLink = customers.nextPageLink;  
60 - vm.customers.hasNext = customers.hasNext;  
61 - if (vm.customers.hasNext) {  
62 - vm.customers.nextPageLink.limit = vm.customers.pageSize;  
63 - }  
64 - vm.customers.pending = false;  
65 - },  
66 - function fail() {  
67 - vm.customers.hasNext = false;  
68 - vm.customers.pending = false;  
69 - });  
70 - }  
71 - }  
72 - };  
73 -  
74 - function cancel() {  
75 - $mdDialog.cancel();  
76 - }  
77 -  
78 - function assign() {  
79 - var tasks = [];  
80 - for (var i=0;i<edgeIds.length;i++) {  
81 - tasks.push(edgeService.assignEdgeToCustomer(vm.customers.selection.id.id, edgeIds[i]));  
82 - }  
83 - $q.all(tasks).then(function () {  
84 - $mdDialog.hide();  
85 - });  
86 - }  
87 -  
88 - function noData() {  
89 - return vm.customers.data.length == 0 && !vm.customers.hasNext;  
90 - }  
91 -  
92 - function hasData() {  
93 - return vm.customers.data.length > 0;  
94 - }  
95 -  
96 - function toggleCustomerSelection($event, customer) {  
97 - $event.stopPropagation();  
98 - if (vm.isCustomerSelected(customer)) {  
99 - vm.customers.selection = null;  
100 - } else {  
101 - vm.customers.selection = customer;  
102 - }  
103 - }  
104 -  
105 - function isCustomerSelected(customer) {  
106 - return vm.customers.selection != null && customer &&  
107 - customer.id.id === vm.customers.selection.id.id;  
108 - }  
109 -  
110 - function searchCustomerTextUpdated() {  
111 - vm.customers = {  
112 - pageSize: vm.customers.pageSize,  
113 - data: [],  
114 - nextPageLink: {  
115 - limit: vm.customers.pageSize,  
116 - textSearch: vm.searchText  
117 - },  
118 - selection: null,  
119 - hasNext: true,  
120 - pending: false  
121 - };  
122 - }  
123 -}  
1 -<!--  
2 -  
3 - Copyright © 2016-2020 The Thingsboard Authors  
4 -  
5 - Licensed under the Apache License, Version 2.0 (the "License");  
6 - you may not use this file except in compliance with the License.  
7 - You may obtain a copy of the License at  
8 -  
9 - http://www.apache.org/licenses/LICENSE-2.0  
10 -  
11 - Unless required by applicable law or agreed to in writing, software  
12 - distributed under the License is distributed on an "AS IS" BASIS,  
13 - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  
14 - See the License for the specific language governing permissions and  
15 - limitations under the License.  
16 -  
17 --->  
18 -<md-dialog aria-label="{{ 'edge.assign-edge-to-customer' | translate }}">  
19 - <form name="theForm" ng-submit="vm.assign()">  
20 - <md-toolbar>  
21 - <div class="md-toolbar-tools">  
22 - <h2 translate>edge.assign-edge-to-customer</h2>  
23 - <span flex></span>  
24 - <md-button class="md-icon-button" ng-click="vm.cancel()">  
25 - <ng-md-icon icon="close" aria-label="{{ 'dialog.close' | translate }}"></ng-md-icon>  
26 - </md-button>  
27 - </div>  
28 - </md-toolbar>  
29 - <md-progress-linear class="md-warn" md-mode="indeterminate" ng-disabled="!$root.loading" ng-show="$root.loading"></md-progress-linear>  
30 - <span style="min-height: 5px;" flex="" ng-show="!$root.loading"></span>  
31 - <md-dialog-content>  
32 - <div class="md-dialog-content">  
33 - <fieldset>  
34 - <span translate>edge.assign-to-customer-text</span>  
35 - <md-input-container class="md-block" style='margin-bottom: 0px;'>  
36 - <label>&nbsp;</label>  
37 - <md-icon aria-label="{{ 'action.search' | translate }}" class="material-icons">  
38 - search  
39 - </md-icon>  
40 - <input id="customer-search" autofocus ng-model="vm.searchText"  
41 - ng-change="vm.searchCustomerTextUpdated()"  
42 - placeholder="{{ 'common.enter-search' | translate }}"/>  
43 - </md-input-container>  
44 - <div style='min-height: 150px;'>  
45 - <span translate layout-align="center center"  
46 - style="text-transform: uppercase; display: flex; height: 150px;"  
47 - class="md-subhead"  
48 - ng-show="vm.noData()">customer.no-customers-text</span>  
49 - <md-virtual-repeat-container ng-show="vm.hasData()"  
50 - tb-scope-element="repeatContainer" md-top-index="vm.topIndex" flex  
51 - style='min-height: 150px; width: 100%;'>  
52 - <md-list>  
53 - <md-list-item md-virtual-repeat="customer in vm.theCustomers" md-on-demand  
54 - class="repeated-item" flex>  
55 - <md-checkbox ng-click="vm.toggleCustomerSelection($event, customer)"  
56 - aria-label="{{ 'item.selected' | translate }}"  
57 - ng-checked="vm.isCustomerSelected(customer)"></md-checkbox>  
58 - <span> {{ customer.title }} </span>  
59 - </md-list-item>  
60 - </md-list>  
61 - </md-virtual-repeat-container>  
62 - </div>  
63 - </fieldset>  
64 - </div>  
65 - </md-dialog-content>  
66 - <md-dialog-actions layout="row">  
67 - <span flex></span>  
68 - <md-button ng-disabled="$root.loading || vm.customers.selection==null" type="submit" class="md-raised md-primary">  
69 - {{ 'action.assign' | translate }}  
70 - </md-button>  
71 - <md-button ng-disabled="$root.loading" ng-click="vm.cancel()" style="margin-right:20px;">{{ 'action.cancel' |  
72 - translate }}  
73 - </md-button>  
74 - </md-dialog-actions>  
75 - </form>  
76 -</md-dialog>  
1 -<!--  
2 -  
3 - Copyright © 2016-2020 The Thingsboard Authors  
4 -  
5 - Licensed under the Apache License, Version 2.0 (the "License");  
6 - you may not use this file except in compliance with the License.  
7 - You may obtain a copy of the License at  
8 -  
9 - http://www.apache.org/licenses/LICENSE-2.0  
10 -  
11 - Unless required by applicable law or agreed to in writing, software  
12 - distributed under the License is distributed on an "AS IS" BASIS,  
13 - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  
14 - See the License for the specific language governing permissions and  
15 - limitations under the License.  
16 -  
17 --->  
18 -<div flex layout="column">  
19 - <div style="text-transform: uppercase; padding-bottom: 5px;">{{vm.item.type}}</div>  
20 - <div class="tb-card-description">{{vm.item.additionalInfo.description}}</div>  
21 - <div style="padding-top: 5px;" class="tb-small" ng-show="vm.isAssignedToCustomer()">{{'edge.assigned-to-customer' | translate}} '{{vm.item.assignedCustomer.title}}'</div>  
22 - <div style="padding-top: 5px;" class="tb-small" ng-show="vm.isPublic()">{{'edge.public' | translate}}</div>  
23 -</div>  
1 -<!--  
2 -  
3 - Copyright © 2016-2020 The Thingsboard Authors  
4 -  
5 - Licensed under the Apache License, Version 2.0 (the "License");  
6 - you may not use this file except in compliance with the License.  
7 - You may obtain a copy of the License at  
8 -  
9 - http://www.apache.org/licenses/LICENSE-2.0  
10 -  
11 - Unless required by applicable law or agreed to in writing, software  
12 - distributed under the License is distributed on an "AS IS" BASIS,  
13 - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  
14 - See the License for the specific language governing permissions and  
15 - limitations under the License.  
16 -  
17 --->  
18 -<md-button ng-click="onAssignToCustomer({event: $event})"  
19 - ng-show="!isEdit && edgeScope === 'tenant' && !isAssignedToCustomer"  
20 - class="md-raised md-primary">{{ 'edge.assign-to-customer' | translate }}</md-button>  
21 -<md-button ng-click="onUnassignFromCustomer({event: $event, isPublic: isPublic})"  
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>  
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>  
39 -<md-button ng-click="onDeleteEdge({event: $event})"  
40 - ng-show="!isEdit && edgeScope === 'tenant'"  
41 - class="md-raised md-primary">{{ 'edge.delete' | translate }}</md-button>  
42 -  
43 -<div layout="row">  
44 - <md-button ngclipboard data-clipboard-action="copy"  
45 - ngclipboard-success="onEdgeIdCopied()"  
46 - data-clipboard-text="{{edge.id.id}}" ng-show="!isEdit"  
47 - class="md-raised">  
48 - <md-icon md-svg-icon="mdi:clipboard-arrow-left"></md-icon>  
49 - <span translate>edge.copy-id</span>  
50 - </md-button>  
51 - <md-button ngclipboard data-clipboard-action="copy"  
52 - ngclipboard-success="onEdgeInfoCopied('key')"  
53 - data-clipboard-text="{{edge.routingKey}}" ng-show="!isEdit"  
54 - class="md-raised">  
55 - <md-icon md-svg-icon="mdi:clipboard-arrow-left"></md-icon>  
56 - <span translate>edge.copy-edge-key</span>  
57 - </md-button>  
58 - <md-button ngclipboard data-clipboard-action="copy"  
59 - ngclipboard-success="onEdgeInfoCopied('secret')"  
60 - data-clipboard-text="{{edge.secret}}" ng-show="!isEdit"  
61 - class="md-raised">  
62 - <md-icon md-svg-icon="mdi:clipboard-arrow-left"></md-icon>  
63 - <span translate>edge.copy-edge-secret</span>  
64 - </md-button>  
65 - <md-button ng-click="onEdgeSync(edge.id)"  
66 - ng-show="!isEdit"  
67 - class="md-raised">  
68 - <md-icon md-svg-icon="mdi:sync"></md-icon>  
69 - <span translate>edge.sync</span>  
70 - </md-button>  
71 -</div>  
72 -  
73 -<md-content class="md-padding" layout="column">  
74 - <md-input-container class="md-block"  
75 - ng-show="!isEdit && isAssignedToCustomer && !isPublic && edgeScope === 'tenant'">  
76 - <label translate>edge.assigned-to-customer</label>  
77 - <input ng-model="assignedCustomer.title" disabled>  
78 - </md-input-container>  
79 - <div class="tb-small" style="padding-bottom: 10px; padding-left: 2px;"  
80 - ng-show="!isEdit && isPublic && (edgeScope === 'customer' || edgeScope === 'tenant')">  
81 - {{ 'edge.edge-public' | translate }}  
82 - </div>  
83 - <fieldset ng-disabled="$root.loading || !isEdit">  
84 - <md-input-container class="md-block">  
85 - <label translate>edge.name</label>  
86 - <input required name="name" ng-model="edge.name">  
87 - <div ng-messages="theForm.name.$error">  
88 - <div translate ng-message="required">edge.name-required</div>  
89 - </div>  
90 - </md-input-container>  
91 - <tb-entity-subtype-autocomplete  
92 - ng-disabled="$root.loading || !isEdit"  
93 - tb-required="true"  
94 - the-form="theForm"  
95 - ng-model="edge.type"  
96 - entity-type="types.entityType.edge">  
97 - </tb-entity-subtype-autocomplete>  
98 - <md-input-container class="md-block">  
99 - <label translate>edge.label</label>  
100 - <input name="label" ng-model="edge.label">  
101 - </md-input-container>  
102 - <md-input-container class="md-block">  
103 - <label translate>edge.description</label>  
104 - <textarea ng-model="edge.additionalInfo.description" rows="2"></textarea>  
105 - </md-input-container>  
106 - <md-input-container class="md-block">  
107 - <label translate>edge.edge-license-key</label>  
108 - <input required name="edgeLicenseKey" ng-model="edge.edgeLicenseKey">  
109 - <div ng-messages="theForm.edgeLicenseKey.$error">  
110 - <div translate ng-message="required">edge.edge-license-key-required</div>  
111 - </div>  
112 - </md-input-container>  
113 - <md-input-container class="md-block">  
114 - <label translate>edge.cloud-endpoint</label>  
115 - <input required name="cloudEndpoint" ng-model="edge.cloudEndpoint">  
116 - <div ng-messages="theForm.cloudEndpoint.$error">  
117 - <div translate ng-message="required">edge.cloud-endpoint-required</div>  
118 - </div>  
119 - </md-input-container>  
120 - </fieldset>  
121 - <div layout="row">  
122 -  
123 - <md-input-container class="md-block" flex>  
124 - <label translate>edge.edge-key</label>  
125 - <input ng-model="edge.routingKey" disabled>  
126 - </md-input-container>  
127 - <md-button class="md-icon-button" style="margin-top: 14px;"  
128 - ngclipboard data-clipboard-action="copy"  
129 - ngclipboard-success="onEdgeInfoCopied('key')"  
130 - data-clipboard-text="{{edge.routingKey}}">  
131 - <md-icon md-svg-icon="mdi:clipboard-arrow-left"></md-icon>  
132 - <md-tooltip md-direction="top">  
133 - {{ 'edge.copy-edge-key' | translate }}  
134 - </md-tooltip>  
135 - </md-button>  
136 - </div>  
137 - <div layout="row">  
138 - <md-input-container class="md-block" flex>  
139 - <label translate>edge.edge-secret</label>  
140 - <input ng-model="edge.secret" disabled>  
141 - </md-input-container>  
142 - <md-button class="md-icon-button" style="margin-top: 14px;"  
143 - ngclipboard data-clipboard-action="copy"  
144 - data-clipboard-text="{{edge.secret}}"  
145 - ngclipboard-success="onEdgeInfoCopied('secret')">  
146 - <md-icon md-svg-icon="mdi:clipboard-arrow-left"></md-icon>  
147 - <md-tooltip md-direction="top">  
148 - {{ 'edge.copy-edge-secret' | translate }}  
149 - </md-tooltip>  
150 - </md-button>  
151 - </div>  
152 -</md-content>  
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 -/* eslint-disable import/no-unresolved, import/default */  
17 -  
18 -import addEdgeTemplate from './add-edge.tpl.html';  
19 -import edgeCard from './edge-card.tpl.html';  
20 -import assignToCustomerTemplate from './assign-to-customer.tpl.html';  
21 -import addEdgesToCustomerTemplate from './add-edges-to-customer.tpl.html';  
22 -import setRootRuleChainToEdgesTemplate from './set-root-rulechain-to-edges.tpl.html';  
23 -  
24 -/* eslint-enable import/no-unresolved, import/default */  
25 -  
26 -/*@ngInject*/  
27 -export function EdgeCardController(types) {  
28 -  
29 - var vm = this;  
30 -  
31 - vm.types = types;  
32 -  
33 - vm.isAssignedToCustomer = function() {  
34 - if (vm.item && vm.item.customerId && vm.parentCtl.edgesScope === 'tenant' &&  
35 - vm.item.customerId.id != vm.types.id.nullUid && !vm.item.assignedCustomer.isPublic) {  
36 - return true;  
37 - }  
38 - return false;  
39 - }  
40 -  
41 - vm.isPublic = function() {  
42 - if (vm.item && vm.item.assignedCustomer && vm.parentCtl.edgesScope === 'tenant' && vm.item.assignedCustomer.isPublic) {  
43 - return true;  
44 - }  
45 - return false;  
46 - }  
47 -}  
48 -  
49 -  
50 -/*@ngInject*/  
51 -export function EdgeController($rootScope, userService, edgeService, customerService, ruleChainService,  
52 - $state, $stateParams, $document, $mdDialog, $q, $translate, types, importExport) {  
53 -  
54 - var customerId = $stateParams.customerId;  
55 -  
56 - var edgeActionsList = [];  
57 -  
58 - var edgeGroupActionsList = [];  
59 -  
60 - var edgeAddItemActionsList = [  
61 - {  
62 - onAction: function ($event) {  
63 - vm.grid.addItem($event);  
64 - },  
65 - name: function() { return $translate.instant('action.add') },  
66 - details: function() { return $translate.instant('edge.add-edge-text') },  
67 - icon: "insert_drive_file"  
68 - },  
69 - {  
70 - onAction: function ($event) {  
71 - importExport.importEntities($event, types.entityType.edge).then(  
72 - function() {  
73 - vm.grid.refreshList();  
74 - }  
75 - );  
76 - },  
77 - name: function() { return $translate.instant('action.import') },  
78 - details: function() { return $translate.instant('edge.import') },  
79 - icon: "file_upload"  
80 - }  
81 - ];  
82 -  
83 - var vm = this;  
84 -  
85 - vm.types = types;  
86 -  
87 - vm.edgeGridConfig = {  
88 - deleteItemTitleFunc: deleteEdgeTitle,  
89 - deleteItemContentFunc: deleteEdgeText,  
90 - deleteItemsTitleFunc: deleteEdgesTitle,  
91 - deleteItemsActionTitleFunc: deleteEdgesActionTitle,  
92 - deleteItemsContentFunc: deleteEdgesText,  
93 -  
94 - saveItemFunc: saveEdge,  
95 -  
96 - getItemTitleFunc: getEdgeTitle,  
97 -  
98 - itemCardController: 'EdgeCardController',  
99 - itemCardTemplateUrl: edgeCard,  
100 - parentCtl: vm,  
101 -  
102 - actionsList: edgeActionsList,  
103 - groupActionsList: edgeGroupActionsList,  
104 - addItemActions: edgeAddItemActionsList,  
105 -  
106 - onGridInited: gridInited,  
107 -  
108 - addItemTemplateUrl: addEdgeTemplate,  
109 -  
110 - addItemText: function() { return $translate.instant('edge.add-edge-text') },  
111 - noItemsText: function() { return $translate.instant('edge.no-edges-text') },  
112 - itemDetailsText: function() { return $translate.instant('edge.edge-details') },  
113 - isDetailsReadOnly: isCustomerUser,  
114 - isSelectionEnabled: function () {  
115 - return !isCustomerUser();  
116 - }  
117 - };  
118 -  
119 - if (angular.isDefined($stateParams.items) && $stateParams.items !== null) {  
120 - vm.edgeGridConfig.items = $stateParams.items;  
121 - }  
122 -  
123 - if (angular.isDefined($stateParams.topIndex) && $stateParams.topIndex > 0) {  
124 - vm.edgeGridConfig.topIndex = $stateParams.topIndex;  
125 - }  
126 -  
127 - vm.edgesScope = $state.$current.data.edgesType;  
128 -  
129 - vm.assignToCustomer = assignToCustomer;  
130 - vm.makePublic = makePublic;  
131 - vm.unassignFromCustomer = unassignFromCustomer;  
132 - vm.openEdgeAssets = openEdgeAssets;  
133 - vm.openEdgeDevices = openEdgeDevices;  
134 - vm.openEdgeEntityViews = openEdgeEntityViews;  
135 - vm.openEdgeDashboards = openEdgeDashboards;  
136 - vm.openEdgeRuleChains = openEdgeRuleChains;  
137 -  
138 - initController();  
139 -  
140 - function initController() {  
141 - var fetchEdgesFunction = null;  
142 - var deleteEdgeFunction = null;  
143 - var refreshEdgesParamsFunction = null;  
144 -  
145 - var user = userService.getCurrentUser();  
146 -  
147 - if (user.authority === 'CUSTOMER_USER') {  
148 - vm.edgesScope = 'customer_user';  
149 - customerId = user.customerId;  
150 - }  
151 - if (customerId) {  
152 - vm.customerEdgesTitle = $translate.instant('customer.edges');  
153 - customerService.getShortCustomerInfo(customerId).then(  
154 - function success(info) {  
155 - if (info.isPublic) {  
156 - vm.customerEdgesTitle = $translate.instant('customer.public-edges');  
157 - }  
158 - }  
159 - );  
160 - }  
161 -  
162 - if (vm.edgesScope === 'tenant') {  
163 - fetchEdgesFunction = function (pageLink, edgeType) {  
164 - return edgeService.getTenantEdges(pageLink, true, null, edgeType);  
165 - };  
166 - deleteEdgeFunction = function (edgeId) {  
167 - return edgeService.deleteEdge(edgeId);  
168 - };  
169 - refreshEdgesParamsFunction = function() {  
170 - return {"topIndex": vm.topIndex};  
171 - };  
172 -  
173 - edgeActionsList.push({  
174 - onAction: function ($event, item) {  
175 - makePublic($event, item);  
176 - },  
177 - name: function() { return $translate.instant('action.share') },  
178 - details: function() { return $translate.instant('edge.make-public') },  
179 - icon: "share",  
180 - isEnabled: function(edge) {  
181 - return edge && (!edge.customerId || edge.customerId.id === types.id.nullUid);  
182 - }  
183 - });  
184 -  
185 - edgeActionsList.push(  
186 - {  
187 - onAction: function ($event, item) {  
188 - assignToCustomer($event, [ item.id.id ]);  
189 - },  
190 - name: function() { return $translate.instant('action.assign') },  
191 - details: function() { return $translate.instant('edge.assign-to-customer') },  
192 - icon: "assignment_ind",  
193 - isEnabled: function(edge) {  
194 - return edge && (!edge.customerId || edge.customerId.id === types.id.nullUid);  
195 - }  
196 - }  
197 - );  
198 -  
199 - edgeActionsList.push(  
200 - {  
201 - onAction: function ($event, item) {  
202 - unassignFromCustomer($event, item, false);  
203 - },  
204 - name: function() { return $translate.instant('action.unassign') },  
205 - details: function() { return $translate.instant('edge.unassign-from-customer') },  
206 - icon: "assignment_return",  
207 - isEnabled: function(edge) {  
208 - return edge && edge.customerId && edge.customerId.id !== types.id.nullUid && !edge.assignedCustomer.isPublic;  
209 - }  
210 - }  
211 - );  
212 -  
213 - edgeActionsList.push({  
214 - onAction: function ($event, item) {  
215 - unassignFromCustomer($event, item, true);  
216 - },  
217 - name: function() { return $translate.instant('action.make-private') },  
218 - details: function() { return $translate.instant('edge.make-private') },  
219 - icon: "reply",  
220 - isEnabled: function(edge) {  
221 - return edge && edge.customerId && edge.customerId.id !== types.id.nullUid && edge.assignedCustomer.isPublic;  
222 - }  
223 - });  
224 -  
225 - edgeActionsList.push(  
226 - {  
227 - onAction: function ($event, item) {  
228 - openEdgeAssets($event, item);  
229 - },  
230 - name: function() { return $translate.instant('asset.assets') },  
231 - details: function() {  
232 - return $translate.instant('edge.manage-edge-assets');  
233 - },  
234 - icon: "domain"  
235 - }  
236 - );  
237 -  
238 - edgeActionsList.push(  
239 - {  
240 - onAction: function ($event, item) {  
241 - openEdgeDevices($event, item);  
242 - },  
243 - name: function() { return $translate.instant('device.devices') },  
244 - details: function() {  
245 - return $translate.instant('edge.manage-edge-devices');  
246 - },  
247 - icon: "devices_other"  
248 - }  
249 - );  
250 -  
251 - edgeActionsList.push(  
252 - {  
253 - onAction: function ($event, item) {  
254 - openEdgeEntityViews($event, item);  
255 - },  
256 - name: function() { return $translate.instant('entity-view.entity-views') },  
257 - details: function() {  
258 - return $translate.instant('edge.manage-edge-entity-views');  
259 - },  
260 - icon: "view_quilt"  
261 - }  
262 - );  
263 -  
264 - edgeActionsList.push(  
265 - {  
266 - onAction: function ($event, item) {  
267 - openEdgeDashboards($event, item);  
268 - },  
269 - name: function() { return $translate.instant('dashboard.dashboards') },  
270 - details: function() {  
271 - return $translate.instant('edge.manage-edge-dashboards');  
272 - },  
273 - icon: "dashboard"  
274 - }  
275 - );  
276 -  
277 - edgeActionsList.push(  
278 - {  
279 - onAction: function ($event, item) {  
280 - openEdgeRuleChains($event, item);  
281 - },  
282 - name: function() { return $translate.instant('rulechain.rulechains') },  
283 - details: function() {  
284 - return $translate.instant('edge.manage-edge-rulechains');  
285 - },  
286 - icon: "code"  
287 - }  
288 - );  
289 -  
290 - edgeActionsList.push(  
291 - {  
292 - onAction: function ($event, item) {  
293 - vm.grid.deleteItem($event, item);  
294 - },  
295 - name: function() { return $translate.instant('action.delete') },  
296 - details: function() { return $translate.instant('edge.delete') },  
297 - icon: "delete"  
298 - }  
299 - );  
300 -  
301 - edgeGroupActionsList.push(  
302 - {  
303 - onAction: function ($event, items) {  
304 - setRootRuleChainToEdges($event, items);  
305 - },  
306 - name: function() { return $translate.instant('edge.set-rootrule-chain-to-edges') },  
307 - details: function(selectedCount) {  
308 - return $translate.instant('edge.set-root-rulechain-to-edges-text', {count: selectedCount}, "messageformat");  
309 - },  
310 - icon: "flag"  
311 - }  
312 - );  
313 -  
314 - edgeGroupActionsList.push(  
315 - {  
316 - onAction: function ($event, items) {  
317 - assignEdgesToCustomer($event, items);  
318 - },  
319 - name: function() { return $translate.instant('edge.assign-edges') },  
320 - details: function(selectedCount) {  
321 - return $translate.instant('edge.assign-edges-text', {count: selectedCount}, "messageformat");  
322 - },  
323 - icon: "assignment_ind"  
324 - }  
325 - );  
326 -  
327 - edgeGroupActionsList.push(  
328 - {  
329 - onAction: function ($event) {  
330 - vm.grid.deleteItems($event);  
331 - },  
332 - name: function() { return $translate.instant('edge.delete-edges') },  
333 - details: deleteEdgesActionTitle,  
334 - icon: "delete"  
335 - }  
336 - );  
337 -  
338 - } else if (vm.edgesScope === 'customer' || vm.edgesScope === 'customer_user') {  
339 - fetchEdgesFunction = function (pageLink, edgeType) {  
340 - return edgeService.getCustomerEdges(customerId, pageLink, true, null, edgeType);  
341 - };  
342 - deleteEdgeFunction = function (edgeId) {  
343 - return edgeService.unassignEdgeFromCustomer(edgeId);  
344 - };  
345 - refreshEdgesParamsFunction = function () {  
346 - return {"customerId": customerId, "topIndex": vm.topIndex};  
347 - };  
348 -  
349 - if (vm.edgesScope === 'customer') {  
350 - edgeActionsList.push(  
351 - {  
352 - onAction: function ($event, item) {  
353 - unassignFromCustomer($event, item, false);  
354 - },  
355 - name: function() { return $translate.instant('action.unassign') },  
356 - details: function() { return $translate.instant('edge.unassign-from-customer') },  
357 - icon: "assignment_return",  
358 - isEnabled: function(edge) {  
359 - return edge && !edge.assignedCustomer.isPublic;  
360 - }  
361 - }  
362 - );  
363 - edgeActionsList.push(  
364 - {  
365 - onAction: function ($event, item) {  
366 - unassignFromCustomer($event, item, true);  
367 - },  
368 - name: function() { return $translate.instant('action.make-private') },  
369 - details: function() { return $translate.instant('edge.make-private') },  
370 - icon: "reply",  
371 - isEnabled: function(edge) {  
372 - return edge && edge.assignedCustomer.isPublic;  
373 - }  
374 - }  
375 - );  
376 -  
377 - edgeGroupActionsList.push(  
378 - {  
379 - onAction: function ($event, items) {  
380 - unassignEdgesFromCustomer($event, items);  
381 - },  
382 - name: function() { return $translate.instant('edge.unassign-edges') },  
383 - details: function(selectedCount) {  
384 - return $translate.instant('edge.unassign-edges-action-title', {count: selectedCount}, "messageformat");  
385 - },  
386 - icon: "assignment_return"  
387 - }  
388 - );  
389 -  
390 - vm.edgeGridConfig.addItemAction = {  
391 - onAction: function ($event) {  
392 - addEdgesToCustomer($event);  
393 - },  
394 - name: function() { return $translate.instant('edge.assign-edges') },  
395 - details: function() { return $translate.instant('edge.assign-new-edge') },  
396 - icon: "add"  
397 - };  
398 -  
399 -  
400 - } else if (vm.edgesScope === 'customer_user') {  
401 - vm.edgeGridConfig.addItemAction = {};  
402 - }  
403 - vm.edgeGridConfig.addItemActions = [];  
404 -  
405 - }  
406 -  
407 - vm.edgeGridConfig.refreshParamsFunc = refreshEdgesParamsFunction;  
408 - vm.edgeGridConfig.fetchItemsFunc = fetchEdgesFunction;  
409 - vm.edgeGridConfig.deleteItemFunc = deleteEdgeFunction;  
410 -  
411 - }  
412 -  
413 - function deleteEdgeTitle(edge) {  
414 - return $translate.instant('edge.delete-edge-title', {edgeName: edge.name});  
415 - }  
416 -  
417 - function deleteEdgeText() {  
418 - return $translate.instant('edge.delete-edge-text');  
419 - }  
420 -  
421 - function deleteEdgesTitle(selectedCount) {  
422 - return $translate.instant('edge.delete-edges-title', {count: selectedCount}, 'messageformat');  
423 - }  
424 -  
425 - function deleteEdgesActionTitle(selectedCount) {  
426 - return $translate.instant('edge.delete-edges-action-title', {count: selectedCount}, 'messageformat');  
427 - }  
428 -  
429 - function deleteEdgesText () {  
430 - return $translate.instant('edge.delete-edges-text');  
431 - }  
432 -  
433 - function gridInited(grid) {  
434 - vm.grid = grid;  
435 - }  
436 -  
437 - function getEdgeTitle(edge) {  
438 - return edge ? edge.name : '';  
439 - }  
440 -  
441 - function saveEdge(edge) {  
442 - var deferred = $q.defer();  
443 - edgeService.saveEdge(edge).then(  
444 - function success(savedEdge) {  
445 - $rootScope.$broadcast('edgeSaved');  
446 - var edges = [ savedEdge ];  
447 - customerService.applyAssignedCustomersInfo(edges).then(  
448 - function success(items) {  
449 - if (items && items.length == 1) {  
450 - deferred.resolve(items[0]);  
451 - } else {  
452 - deferred.reject();  
453 - }  
454 - },  
455 - function fail() {  
456 - deferred.reject();  
457 - }  
458 - );  
459 - },  
460 - function fail() {  
461 - deferred.reject();  
462 - }  
463 - );  
464 - return deferred.promise;  
465 - }  
466 -  
467 - function isCustomerUser() {  
468 - return vm.edgesScope === 'customer_user';  
469 - }  
470 -  
471 - function assignToCustomer($event, edgeIds) {  
472 - if ($event) {  
473 - $event.stopPropagation();  
474 - }  
475 - var pageSize = 10;  
476 - customerService.getCustomers({limit: pageSize, textSearch: ''}).then(  
477 - function success(_customers) {  
478 - var customers = {  
479 - pageSize: pageSize,  
480 - data: _customers.data,  
481 - nextPageLink: _customers.nextPageLink,  
482 - selection: null,  
483 - hasNext: _customers.hasNext,  
484 - pending: false  
485 - };  
486 - if (customers.hasNext) {  
487 - customers.nextPageLink.limit = pageSize;  
488 - }  
489 - $mdDialog.show({  
490 - controller: 'AssignEdgeToCustomerController',  
491 - controllerAs: 'vm',  
492 - templateUrl: assignToCustomerTemplate,  
493 - locals: {edgeIds: edgeIds, customers: customers},  
494 - parent: angular.element($document[0].body),  
495 - fullscreen: true,  
496 - targetEvent: $event  
497 - }).then(function () {  
498 - vm.grid.refreshList();  
499 - }, function () {  
500 - });  
501 - },  
502 - function fail() {  
503 - });  
504 - }  
505 -  
506 - function addEdgesToCustomer($event) {  
507 - if ($event) {  
508 - $event.stopPropagation();  
509 - }  
510 - var pageSize = 10;  
511 - edgeService.getTenantEdges({limit: pageSize, textSearch: ''}, false).then(  
512 - function success(_edges) {  
513 - var edges = {  
514 - pageSize: pageSize,  
515 - data: _edges.data,  
516 - nextPageLink: _edges.nextPageLink,  
517 - selections: {},  
518 - selectedCount: 0,  
519 - hasNext: _edges.hasNext,  
520 - pending: false  
521 - };  
522 - if (edges.hasNext) {  
523 - edges.nextPageLink.limit = pageSize;  
524 - }  
525 - $mdDialog.show({  
526 - controller: 'AddEdgesToCustomerController',  
527 - controllerAs: 'vm',  
528 - templateUrl: addEdgesToCustomerTemplate,  
529 - locals: {customerId: customerId, edges: edges},  
530 - parent: angular.element($document[0].body),  
531 - fullscreen: true,  
532 - targetEvent: $event  
533 - }).then(function () {  
534 - vm.grid.refreshList();  
535 - }, function () {  
536 - });  
537 - },  
538 - function fail() {  
539 - });  
540 - }  
541 -  
542 - function setRootRuleChainToEdges($event, items) {  
543 - var edgeIds = [];  
544 - for (var id in items.selections) {  
545 - edgeIds.push(id);  
546 - }  
547 - setRootRuleChain($event, edgeIds);  
548 - }  
549 -  
550 - function setRootRuleChain($event, edgeIds) {  
551 - if ($event) {  
552 - $event.stopPropagation();  
553 - }  
554 - var pageSize = 10;  
555 - ruleChainService.getEdgesRuleChains({limit: pageSize, textSearch: ''}).then(  
556 - function success(_ruleChains) {  
557 - var ruleChains = {  
558 - pageSize: pageSize,  
559 - data: _ruleChains.data,  
560 - nextPageLink: _ruleChains.nextPageLink,  
561 - selection: null,  
562 - hasNext: _ruleChains.hasNext,  
563 - pending: false  
564 - };  
565 - if (ruleChains.hasNext) {  
566 - ruleChains.nextPageLink.limit = pageSize;  
567 - }  
568 - $mdDialog.show({  
569 - controller: 'SetRootRuleChainToEdgesController',  
570 - controllerAs: 'vm',  
571 - templateUrl: setRootRuleChainToEdgesTemplate,  
572 - locals: {edgeIds: edgeIds, ruleChains: ruleChains},  
573 - parent: angular.element($document[0].body),  
574 - fullscreen: true,  
575 - targetEvent: $event  
576 - }).then(function () {  
577 - vm.grid.refreshList();  
578 - }, function () {  
579 - });  
580 - },  
581 - function fail() {  
582 - });  
583 - }  
584 -  
585 - function assignEdgesToCustomer($event, items) {  
586 - var edgeIds = [];  
587 - for (var id in items.selections) {  
588 - edgeIds.push(id);  
589 - }  
590 - assignToCustomer($event, edgeIds);  
591 - }  
592 -  
593 - function unassignFromCustomer($event, edge, isPublic) {  
594 - if ($event) {  
595 - $event.stopPropagation();  
596 - }  
597 - var title;  
598 - var content;  
599 - var label;  
600 - if (isPublic) {  
601 - title = $translate.instant('edge.make-private-edge-title', {edgeName: edge.name});  
602 - content = $translate.instant('edge.make-private-edge-text');  
603 - label = $translate.instant('edge.make-private');  
604 - } else {  
605 - title = $translate.instant('edge.unassign-edge-title', {edgeName: edge.name});  
606 - content = $translate.instant('edge.unassign-edge-text');  
607 - label = $translate.instant('edge.unassign-edge');  
608 - }  
609 - var confirm = $mdDialog.confirm()  
610 - .targetEvent($event)  
611 - .title(title)  
612 - .htmlContent(content)  
613 - .ariaLabel(label)  
614 - .cancel($translate.instant('action.no'))  
615 - .ok($translate.instant('action.yes'));  
616 - $mdDialog.show(confirm).then(function () {  
617 - edgeService.unassignEdgeFromCustomer(edge.id.id).then(function success() {  
618 - vm.grid.refreshList();  
619 - });  
620 - });  
621 - }  
622 -  
623 - function unassignEdgesFromCustomer($event, items) {  
624 - var confirm = $mdDialog.confirm()  
625 - .targetEvent($event)  
626 - .title($translate.instant('edge.unassign-edges-title', {count: items.selectedCount}, 'messageformat'))  
627 - .htmlContent($translate.instant('edge.unassign-edges-text'))  
628 - .ariaLabel($translate.instant('edge.unassign-edge'))  
629 - .cancel($translate.instant('action.no'))  
630 - .ok($translate.instant('action.yes'));  
631 - $mdDialog.show(confirm).then(function () {  
632 - var tasks = [];  
633 - for (var id in items.selections) {  
634 - tasks.push(edgeService.unassignEdgeFromCustomer(id));  
635 - }  
636 - $q.all(tasks).then(function () {  
637 - vm.grid.refreshList();  
638 - });  
639 - });  
640 - }  
641 -  
642 - function makePublic($event, edge) {  
643 - if ($event) {  
644 - $event.stopPropagation();  
645 - }  
646 - var confirm = $mdDialog.confirm()  
647 - .targetEvent($event)  
648 - .title($translate.instant('edge.make-public-edge-title', {edgeName: edge.name}))  
649 - .htmlContent($translate.instant('edge.make-public-edge-text'))  
650 - .ariaLabel($translate.instant('edge.make-public'))  
651 - .cancel($translate.instant('action.no'))  
652 - .ok($translate.instant('action.yes'));  
653 - $mdDialog.show(confirm).then(function () {  
654 - edgeService.makeEdgePublic(edge.id.id).then(function success() {  
655 - vm.grid.refreshList();  
656 - });  
657 - });  
658 - }  
659 -  
660 - function openEdgeDashboards($event, edge) {  
661 - if ($event) {  
662 - $event.stopPropagation();  
663 - }  
664 - $state.go('home.edges.dashboards', {edgeId: edge.id.id});  
665 - }  
666 -  
667 - function openEdgeRuleChains($event, edge) {  
668 - if ($event) {  
669 - $event.stopPropagation();  
670 - }  
671 - $state.go('home.edges.ruleChains', {edgeId: edge.id.id});  
672 - }  
673 -  
674 - function openEdgeAssets($event, edge) {  
675 - if ($event) {  
676 - $event.stopPropagation();  
677 - }  
678 - $state.go('home.edges.assets', {edgeId: edge.id.id});  
679 - }  
680 -  
681 - function openEdgeDevices($event, edge) {  
682 - if ($event) {  
683 - $event.stopPropagation();  
684 - }  
685 - $state.go('home.edges.devices', {edgeId: edge.id.id});  
686 - }  
687 -  
688 - function openEdgeEntityViews($event, edge) {  
689 - if ($event) {  
690 - $event.stopPropagation();  
691 - }  
692 - $state.go('home.edges.entityViews', {edgeId: edge.id.id});  
693 - }  
694 -  
695 -}  
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 -/* eslint-disable import/no-unresolved, import/default */  
17 -  
18 -import edgeFieldsetTemplate from './edge-fieldset.tpl.html';  
19 -  
20 -/* eslint-enable import/no-unresolved, import/default */  
21 -  
22 -/*@ngInject*/  
23 -export default function EdgeDirective($compile, $templateCache, $translate, $mdDialog, $document, utils, toast, types, customerService, edgeService) {  
24 - var linker = function (scope, element) {  
25 - var template = $templateCache.get(edgeFieldsetTemplate);  
26 - element.html(template);  
27 -  
28 - scope.types = types;  
29 - scope.isAssignedToCustomer = false;  
30 - scope.isPublic = false;  
31 - scope.assignedCustomer = null;  
32 -  
33 - scope.$watch('edge', function(newVal) {  
34 - if (newVal) {  
35 - if (!scope.edge.id) {  
36 - scope.edge.routingKey = utils.guid('');  
37 - scope.edge.secret = generateSecret(20);  
38 - scope.edge.cloudEndpoint = utils.baseUrl();  
39 - }  
40 - if (scope.edge.customerId && scope.edge.customerId.id !== types.id.nullUid) {  
41 - scope.isAssignedToCustomer = true;  
42 - customerService.getShortCustomerInfo(scope.edge.customerId.id).then(  
43 - function success(customer) {  
44 - scope.assignedCustomer = customer;  
45 - scope.isPublic = customer.isPublic;  
46 - }  
47 - );  
48 - } else {  
49 - scope.isAssignedToCustomer = false;  
50 - scope.isPublic = false;  
51 - scope.assignedCustomer = null;  
52 - }  
53 - }  
54 - });  
55 -  
56 - function generateSecret(length) {  
57 - if (angular.isUndefined(length) || length == null) {  
58 - length = 1;  
59 - }  
60 - var l = length > 10 ? 10 : length;  
61 - var str = Math.random().toString(36).substr(2, l);  
62 - if(str.length >= length){  
63 - return str;  
64 - }  
65 - return str.concat(generateSecret(length - str.length));  
66 - }  
67 -  
68 - scope.onEdgeIdCopied = function() {  
69 - toast.showSuccess($translate.instant('edge.id-copied-message'), 750, angular.element(element).parent().parent(), 'bottom left');  
70 - };  
71 -  
72 - scope.onEdgeSync = function (edgeId) {  
73 - edgeService.syncEdge(edgeId).then(  
74 - function success() {  
75 - toast.showSuccess($translate.instant('edge.sync-message'), 750, angular.element(element).parent().parent(), 'bottom left');  
76 - },  
77 - function fail(error) {  
78 - toast.showError(error);  
79 - }  
80 - );  
81 - }  
82 -  
83 - $compile(element.contents())(scope);  
84 -  
85 - scope.onEdgeInfoCopied = function(type) {  
86 - let infoTypeLabel = "";  
87 - switch (type) {  
88 - case 'key':  
89 - infoTypeLabel = "edge.edge-key-copied-message";  
90 - break;  
91 - case 'secret':  
92 - infoTypeLabel = "edge.edge-secret-copied-message";  
93 - break;  
94 - }  
95 - toast.showSuccess($translate.instant(infoTypeLabel), 750, angular.element(element).parent().parent(), 'bottom left');  
96 - };  
97 -  
98 - };  
99 - return {  
100 - restrict: "E",  
101 - link: linker,  
102 - scope: {  
103 - edge: '=',  
104 - isEdit: '=',  
105 - edgeScope: '=',  
106 - theForm: '=',  
107 - onAssignToCustomer: '&',  
108 - onMakePublic: '&',  
109 - onUnassignFromCustomer: '&',  
110 - onManageEdgeAssets: '&',  
111 - onManageEdgeDevices: '&',  
112 - onManageEdgeEntityViews: '&',  
113 - onManageEdgeDashboards: '&',  
114 - onManageEdgeRuleChains: '&',  
115 - onDeleteEdge: '&'  
116 - }  
117 - };  
118 -}  
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 -/* eslint-disable import/no-unresolved, import/default */  
17 -  
18 -import edgesTemplate from './edges.tpl.html';  
19 -import entityViewsTemplate from "../entity-view/entity-views.tpl.html";  
20 -import devicesTemplate from "../device/devices.tpl.html";  
21 -import assetsTemplate from "../asset/assets.tpl.html";  
22 -import dashboardsTemplate from "../dashboard/dashboards.tpl.html";  
23 -import dashboardTemplate from "../dashboard/dashboard.tpl.html";  
24 -import ruleChainsTemplate from "../rulechain/rulechains.tpl.html";  
25 -import ruleChainTemplate from "../rulechain/rulechain.tpl.html";  
26 -  
27 -/* eslint-enable import/no-unresolved, import/default */  
28 -  
29 -/*@ngInject*/  
30 -export default function EdgeRoutes($stateProvider, types) {  
31 - $stateProvider  
32 - .state('home.edges', {  
33 - url: '/edges',  
34 - params: {'topIndex': 0},  
35 - module: 'private',  
36 - auth: ['TENANT_ADMIN', 'CUSTOMER_USER'],  
37 - views: {  
38 - "content@home": {  
39 - templateUrl: edgesTemplate,  
40 - controller: 'EdgeController',  
41 - controllerAs: 'vm'  
42 - }  
43 - },  
44 - data: {  
45 - edgesType: 'tenant',  
46 - searchEnabled: true,  
47 - searchByEntitySubtype: true,  
48 - searchEntityType: types.entityType.edge,  
49 - pageTitle: 'edge.edges'  
50 - },  
51 - ncyBreadcrumb: {  
52 - label: '{"icon": "router", "label": "edge.edges"}'  
53 - }  
54 - }).state('home.edges.entityViews', {  
55 - url: '/:edgeId/entityViews',  
56 - params: {'topIndex': 0},  
57 - module: 'private',  
58 - auth: ['TENANT_ADMIN'],  
59 - views: {  
60 - "content@home": {  
61 - templateUrl: entityViewsTemplate,  
62 - controllerAs: 'vm',  
63 - controller: 'EntityViewController'  
64 - }  
65 - },  
66 - data: {  
67 - entityViewsType: 'edge',  
68 - searchEnabled: true,  
69 - searchByEntitySubtype: true,  
70 - searchEntityType: types.entityType.entityView,  
71 - pageTitle: 'edge.entity-views'  
72 - },  
73 - ncyBreadcrumb: {  
74 - label: '{"icon": "view_quilt", "label": "edge.entity-views"}'  
75 - }  
76 - }).state('home.edges.devices', {  
77 - url: '/:edgeId/devices',  
78 - params: {'topIndex': 0},  
79 - module: 'private',  
80 - auth: ['TENANT_ADMIN'],  
81 - views: {  
82 - "content@home": {  
83 - templateUrl: devicesTemplate,  
84 - controllerAs: 'vm',  
85 - controller: 'DeviceController'  
86 - }  
87 - },  
88 - data: {  
89 - devicesType: 'edge',  
90 - searchEnabled: true,  
91 - searchByEntitySubtype: true,  
92 - searchEntityType: types.entityType.device,  
93 - pageTitle: 'edge.devices'  
94 - },  
95 - ncyBreadcrumb: {  
96 - label: '{"icon": "devices_other", "label": "edge.devices"}'  
97 - }  
98 - }).state('home.edges.assets', {  
99 - url: '/:edgeId/assets',  
100 - params: {'topIndex': 0},  
101 - module: 'private',  
102 - auth: ['TENANT_ADMIN'],  
103 - views: {  
104 - "content@home": {  
105 - templateUrl: assetsTemplate,  
106 - controllerAs: 'vm',  
107 - controller: 'AssetController'  
108 - }  
109 - },  
110 - data: {  
111 - assetsType: 'edge',  
112 - searchEnabled: true,  
113 - searchByEntitySubtype: true,  
114 - searchEntityType: types.entityType.asset,  
115 - pageTitle: 'edge.assets'  
116 - },  
117 - ncyBreadcrumb: {  
118 - label: '{"icon": "domain", "label": "edge.assets"}'  
119 - }  
120 - }).state('home.edges.dashboards', {  
121 - url: '/:edgeId/dashboards',  
122 - params: {'topIndex': 0},  
123 - module: 'private',  
124 - auth: ['TENANT_ADMIN'],  
125 - views: {  
126 - "content@home": {  
127 - templateUrl: dashboardsTemplate,  
128 - controllerAs: 'vm',  
129 - controller: 'DashboardsController'  
130 - }  
131 - },  
132 - data: {  
133 - dashboardsType: 'edge',  
134 - searchEnabled: true,  
135 - pageTitle: 'edge.dashboards'  
136 - },  
137 - ncyBreadcrumb: {  
138 - label: '{"icon": "dashboard", "label": "edge.dashboards"}'  
139 - }  
140 - }).state('home.edges.dashboards.dashboard', {  
141 - url: '/:dashboardId?state',  
142 - reloadOnSearch: false,  
143 - module: 'private',  
144 - auth: ['TENANT_ADMIN', 'CUSTOMER_USER'],  
145 - views: {  
146 - "content@home": {  
147 - templateUrl: dashboardTemplate,  
148 - controller: 'DashboardController',  
149 - controllerAs: 'vm'  
150 - }  
151 - },  
152 - data: {  
153 - widgetEditMode: false,  
154 - searchEnabled: false,  
155 - pageTitle: 'dashboard.dashboard',  
156 - dashboardsType: 'edge',  
157 - },  
158 - ncyBreadcrumb: {  
159 - label: '{"icon": "dashboard", "label": "{{ vm.dashboard.title }}", "translate": "false"}'  
160 - }  
161 - }).state('home.customers.edges', {  
162 - url: '/:customerId/edges',  
163 - params: {'topIndex': 0},  
164 - module: 'private',  
165 - auth: ['TENANT_ADMIN'],  
166 - views: {  
167 - "content@home": {  
168 - templateUrl: edgesTemplate,  
169 - controllerAs: 'vm',  
170 - controller: 'EdgeController'  
171 - }  
172 - },  
173 - data: {  
174 - edgesType: 'customer',  
175 - searchEnabled: true,  
176 - searchByEntitySubtype: true,  
177 - searchEntityType: types.entityType.edge,  
178 - pageTitle: 'customer.edges'  
179 - },  
180 - ncyBreadcrumb: {  
181 - label: '{"icon": "router", "label": "{{ vm.customerEdgesTitle }}", "translate": "false"}'  
182 - }  
183 - }).state('home.edges.ruleChains', {  
184 - url: '/:edgeId/ruleChains',  
185 - params: {'topIndex': 0},  
186 - module: 'private',  
187 - auth: ['TENANT_ADMIN'],  
188 - views: {  
189 - "content@home": {  
190 - templateUrl: ruleChainsTemplate,  
191 - controllerAs: 'vm',  
192 - controller: 'RuleChainsController'  
193 - }  
194 - },  
195 - data: {  
196 - searchEnabled: true,  
197 - pageTitle: 'rulechain.edge-rulechains',  
198 - ruleChainsType: 'edge'  
199 - },  
200 - ncyBreadcrumb: {  
201 - label: '{"icon": "code", "label": "rulechain.edge-rulechains"}'  
202 - }  
203 - }).state('home.edges.ruleChains.ruleChain', {  
204 - url: '/:ruleChainId',  
205 - reloadOnSearch: false,  
206 - module: 'private',  
207 - auth: ['SYS_ADMIN', 'TENANT_ADMIN'],  
208 - views: {  
209 - "content@home": {  
210 - templateUrl: ruleChainTemplate,  
211 - controller: 'RuleChainController',  
212 - controllerAs: 'vm'  
213 - }  
214 - },  
215 - resolve: {  
216 - ruleChain:  
217 - /*@ngInject*/  
218 - function($stateParams, ruleChainService) {  
219 - return ruleChainService.getRuleChain($stateParams.ruleChainId);  
220 - },  
221 - ruleChainMetaData:  
222 - /*@ngInject*/  
223 - function($stateParams, ruleChainService) {  
224 - return ruleChainService.getRuleChainMetaData($stateParams.ruleChainId);  
225 - },  
226 - ruleNodeComponents:  
227 - /*@ngInject*/  
228 - function($stateParams, ruleChainService) {  
229 - return ruleChainService.getRuleNodeComponents(types.ruleChainType.edge);  
230 - }  
231 - },  
232 - data: {  
233 - import: false,  
234 - searchEnabled: false,  
235 - pageTitle: 'edge.rulechain'  
236 - },  
237 - ncyBreadcrumb: {  
238 - label: '{"icon": "code", "label": "{{ vm.ruleChain.name }}", "translate": "false"}'  
239 - }  
240 - });  
241 -}  
1 -<!--  
2 -  
3 - Copyright © 2016-2020 The Thingsboard Authors  
4 -  
5 - Licensed under the Apache License, Version 2.0 (the "License");  
6 - you may not use this file except in compliance with the License.  
7 - You may obtain a copy of the License at  
8 -  
9 - http://www.apache.org/licenses/LICENSE-2.0  
10 -  
11 - Unless required by applicable law or agreed to in writing, software  
12 - distributed under the License is distributed on an "AS IS" BASIS,  
13 - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  
14 - See the License for the specific language governing permissions and  
15 - limitations under the License.  
16 -  
17 --->  
18 -<tb-grid grid-configuration="vm.edgeGridConfig">  
19 - <details-buttons tb-help="'edges'" help-container-id="help-container">  
20 - <div id="help-container"></div>  
21 - </details-buttons>  
22 - <md-tabs ng-class="{'tb-headless': vm.grid.detailsConfig.isDetailsEditMode}"  
23 - id="tabs" md-border-bottom flex class="tb-absolute-fill">  
24 - <md-tab label="{{ 'edge.details' | translate }}">  
25 - <tb-edge edge="vm.grid.operatingItem()"  
26 - is-edit="vm.grid.detailsConfig.isDetailsEditMode"  
27 - edge-scope="vm.edgesScope"  
28 - the-form="vm.grid.detailsForm"  
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)"  
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)"  
37 - on-delete-edge="vm.grid.deleteItem(event, vm.grid.detailsConfig.currentItem)"></tb-edge>  
38 - </md-tab>  
39 - <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode" md-on-select="vm.grid.triggerResize()" label="{{ 'attribute.attributes' | translate }}">  
40 - <tb-attribute-table flex  
41 - entity-id="vm.grid.operatingItem().id.id"  
42 - entity-type="{{vm.types.entityType.edge}}"  
43 - entity-name="vm.grid.operatingItem().name"  
44 - default-attribute-scope="{{vm.types.attributesScope.server.value}}">  
45 - </tb-attribute-table>  
46 - </md-tab>  
47 - <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode" md-on-select="vm.grid.triggerResize()" label="{{ 'attribute.latest-telemetry' | translate }}">  
48 - <tb-attribute-table flex  
49 - entity-id="vm.grid.operatingItem().id.id"  
50 - entity-type="{{vm.types.entityType.edge}}"  
51 - entity-name="vm.grid.operatingItem().name"  
52 - default-attribute-scope="{{vm.types.latestTelemetry.value}}"  
53 - disable-attribute-scope-selection="true">  
54 - </tb-attribute-table>  
55 - </md-tab>  
56 - <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode" md-on-select="vm.grid.triggerResize()" label="{{ 'alarm.alarms' | translate }}">  
57 - <tb-alarm-table flex entity-type="vm.types.entityType.edge"  
58 - entity-id="vm.grid.operatingItem().id.id">  
59 - </tb-alarm-table>  
60 - </md-tab>  
61 - <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode" md-on-select="vm.grid.triggerResize()" label="{{ 'edge.events' | translate }}">  
62 - <tb-event-table flex entity-type="vm.types.entityType.edge"  
63 - entity-id="vm.grid.operatingItem().id.id"  
64 - tenant-id="vm.grid.operatingItem().tenantId.id"  
65 - default-event-type="{{vm.types.eventType.error.value}}">  
66 - </tb-event-table>  
67 - </md-tab>  
68 - <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode" md-on-select="vm.grid.triggerResize()" label="{{ 'relation.relations' | translate }}">  
69 - <tb-relation-table flex  
70 - readonly="!('edge' | hasGenericPermission:'write')"  
71 - entity-id="vm.grid.operatingItem().id.id"  
72 - entity-type="{{vm.types.entityType.edge}}">  
73 - </tb-relation-table>  
74 - </md-tab>  
75 - <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode && vm.grid.isTenantAdmin()" md-on-select="vm.grid.triggerResize()" label="{{ 'audit-log.audit-logs' | translate }}">  
76 - <tb-audit-log-table flex entity-type="vm.types.entityType.edge"  
77 - entity-id="vm.grid.operatingItem().id.id"  
78 - audit-log-mode="{{vm.types.auditLogMode.entity}}">  
79 - </tb-audit-log-table>  
80 - </md-tab>  
81 - </md-tabs>  
82 -</tb-grid>  
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 -import uiRouter from 'angular-ui-router';  
17 -import thingsboardGrid from '../components/grid.directive';  
18 -import thingsboardApiUser from '../api/user.service';  
19 -import thingsboardApiEdge from '../api/edge.service';  
20 -import thingsboardApiCustomer from '../api/customer.service';  
21 -  
22 -import EdgeRoutes from './edge.routes';  
23 -import {EdgeController, EdgeCardController} from './edge.controller';  
24 -import AssignEdgeToCustomerController from './assign-to-customer.controller';  
25 -import AddEdgesToCustomerController from './add-edges-to-customer.controller';  
26 -import SetRootRuleChainToEdgesController from './set-root-rule-chain-to-edges.controller';  
27 -import EdgeDirective from './edge.directive';  
28 -  
29 -export default angular.module('thingsboard.edge', [  
30 - uiRouter,  
31 - thingsboardGrid,  
32 - thingsboardApiUser,  
33 - thingsboardApiEdge,  
34 - thingsboardApiCustomer  
35 -])  
36 - .config(EdgeRoutes)  
37 - .controller('EdgeController', EdgeController)  
38 - .controller('EdgeCardController', EdgeCardController)  
39 - .controller('AssignEdgeToCustomerController', AssignEdgeToCustomerController)  
40 - .controller('AddEdgesToCustomerController', AddEdgesToCustomerController)  
41 - .controller('SetRootRuleChainToEdgesController', SetRootRuleChainToEdgesController)  
42 - .directive('tbEdge', EdgeDirective)  
43 - .name;  
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 -/*@ngInject*/  
17 -export default function SetRootRuleChainToEdgesController(ruleChainService, edgeService, $mdDialog, $q, edgeIds, ruleChains) {  
18 -  
19 - var vm = this;  
20 -  
21 - vm.ruleChains = ruleChains;  
22 - vm.searchText = '';  
23 -  
24 - vm.assign = assign;  
25 - vm.cancel = cancel;  
26 - vm.isRuleChainSelected = isRuleChainSelected;  
27 - vm.hasData = hasData;  
28 - vm.noData = noData;  
29 - vm.searchRuleChainTextUpdated = searchRuleChainTextUpdated;  
30 - vm.toggleRuleChainSelection = toggleRuleChainSelection;  
31 -  
32 - vm.theRuleChains = {  
33 - getItemAtIndex: function (index) {  
34 - if (index > vm.ruleChains.data.length) {  
35 - vm.theRuleChains.fetchMoreItems_(index);  
36 - return null;  
37 - }  
38 - var item = vm.ruleChains.data[index];  
39 - if (item) {  
40 - item.indexNumber = index + 1;  
41 - }  
42 - return item;  
43 - },  
44 -  
45 - getLength: function () {  
46 - if (vm.ruleChains.hasNext) {  
47 - return vm.ruleChains.data.length + vm.ruleChains.nextPageLink.limit;  
48 - } else {  
49 - return vm.ruleChains.data.length;  
50 - }  
51 - },  
52 -  
53 - fetchMoreItems_: function () {  
54 - if (vm.ruleChains.hasNext && !vm.ruleChains.pending) {  
55 - vm.ruleChains.pending = true;  
56 - ruleChainService.getEdgesRuleChains(vm.ruleChains.nextPageLink).then(  
57 - function success(ruleChains) {  
58 - vm.ruleChains.data = vm.ruleChains.data.concat(ruleChains.data);  
59 - vm.ruleChains.nextPageLink = ruleChains.nextPageLink;  
60 - vm.ruleChains.hasNext = ruleChains.hasNext;  
61 - if (vm.ruleChains.hasNext) {  
62 - vm.ruleChains.nextPageLink.limit = vm.ruleChains.pageSize;  
63 - }  
64 - vm.ruleChains.pending = false;  
65 - },  
66 - function fail() {  
67 - vm.ruleChains.hasNext = false;  
68 - vm.ruleChains.pending = false;  
69 - });  
70 - }  
71 - }  
72 - };  
73 -  
74 - function cancel() {  
75 - $mdDialog.cancel();  
76 - }  
77 -  
78 - function assign() {  
79 - var assignTasks = [];  
80 - for (var i=0;i<edgeIds.length;i++) {  
81 - assignTasks.push(ruleChainService.assignRuleChainToEdge(edgeIds[i], vm.ruleChains.selection.id.id));  
82 - }  
83 - $q.all(assignTasks).then(function () {  
84 - var setRootTasks = [];  
85 - for (var j=0;j<edgeIds.length;j++) {  
86 - setRootTasks.push(edgeService.setRootRuleChain(edgeIds[j], vm.ruleChains.selection.id.id));  
87 - }  
88 - $q.all(setRootTasks).then(function () {  
89 - $mdDialog.hide();  
90 - });  
91 - });  
92 - }  
93 -  
94 - function noData() {  
95 - return vm.ruleChains.data.length == 0 && !vm.ruleChains.hasNext;  
96 - }  
97 -  
98 - function hasData() {  
99 - return vm.ruleChains.data.length > 0;  
100 - }  
101 -  
102 - function toggleRuleChainSelection($event, ruleChain) {  
103 - $event.stopPropagation();  
104 - if (vm.isRuleChainSelected(ruleChain)) {  
105 - vm.ruleChains.selection = null;  
106 - } else {  
107 - vm.ruleChains.selection = ruleChain;  
108 - }  
109 - }  
110 -  
111 - function isRuleChainSelected(ruleChain) {  
112 - return vm.ruleChains.selection != null && ruleChain &&  
113 - ruleChain.id.id === vm.ruleChains.selection.id.id;  
114 - }  
115 -  
116 - function searchRuleChainTextUpdated() {  
117 - vm.ruleChains = {  
118 - pageSize: vm.ruleChains.pageSize,  
119 - data: [],  
120 - nextPageLink: {  
121 - limit: vm.ruleChains.pageSize,  
122 - textSearch: vm.searchText  
123 - },  
124 - selection: null,  
125 - hasNext: true,  
126 - pending: false  
127 - };  
128 - }  
129 -}  
1 -<!--  
2 -  
3 - Copyright © 2016-2020 The Thingsboard Authors  
4 -  
5 - Licensed under the Apache License, Version 2.0 (the "License");  
6 - you may not use this file except in compliance with the License.  
7 - You may obtain a copy of the License at  
8 -  
9 - http://www.apache.org/licenses/LICENSE-2.0  
10 -  
11 - Unless required by applicable law or agreed to in writing, software  
12 - distributed under the License is distributed on an "AS IS" BASIS,  
13 - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  
14 - See the License for the specific language governing permissions and  
15 - limitations under the License.  
16 -  
17 --->  
18 -<md-dialog aria-label="{{ 'edge.set-root-rulechain-to-edges' | translate }}">  
19 - <form name="theForm" ng-submit="vm.assign()">  
20 - <md-toolbar>  
21 - <div class="md-toolbar-tools">  
22 - <h2 translate>edge.set-root-rulechain-to-edges</h2>  
23 - <span flex></span>  
24 - <md-button class="md-icon-button" ng-click="vm.cancel()">  
25 - <ng-md-icon icon="close" aria-label="{{ 'dialog.close' | translate }}"></ng-md-icon>  
26 - </md-button>  
27 - </div>  
28 - </md-toolbar>  
29 - <md-progress-linear class="md-warn" md-mode="indeterminate" ng-disabled="!$root.loading" ng-show="$root.loading"></md-progress-linear>  
30 - <span style="min-height: 5px;" flex="" ng-show="!$root.loading"></span>  
31 - <md-dialog-content>  
32 - <div class="md-dialog-content">  
33 - <fieldset>  
34 - <span translate>edge.set-root-rulechain-text</span>  
35 - <md-input-container class="md-block" style='margin-bottom: 0px;'>  
36 - <label>&nbsp;</label>  
37 - <md-icon aria-label="{{ 'action.search' | translate }}" class="material-icons">  
38 - search  
39 - </md-icon>  
40 - <input id="rule-chain-search" autofocus ng-model="vm.searchText"  
41 - ng-change="vm.searchRuleChainTextUpdated()"  
42 - placeholder="{{ 'common.enter-search' | translate }}"/>  
43 - </md-input-container>  
44 - <div style='min-height: 150px;'>  
45 - <span translate layout-align="center center"  
46 - style="text-transform: uppercase; display: flex; height: 150px;"  
47 - class="md-subhead"  
48 - ng-show="vm.noData()">rulechain.no-rulechains-text</span>  
49 - <md-virtual-repeat-container ng-show="vm.hasData()"  
50 - tb-scope-element="repeatContainer" md-top-index="vm.topIndex" flex  
51 - style='min-height: 150px; width: 100%;'>  
52 - <md-list>  
53 - <md-list-item md-virtual-repeat="ruleChain in vm.theRuleChains" md-on-demand  
54 - class="repeated-item" flex>  
55 - <md-checkbox ng-click="vm.toggleRuleChainSelection($event, ruleChain)"  
56 - aria-label="{{ 'item.selected' | translate }}"  
57 - ng-checked="vm.isRuleChainSelected(ruleChain)"></md-checkbox>  
58 - <span> {{ ruleChain.name }} </span>  
59 - </md-list-item>  
60 - </md-list>  
61 - </md-virtual-repeat-container>  
62 - </div>  
63 - </fieldset>  
64 - </div>  
65 - </md-dialog-content>  
66 - <md-dialog-actions layout="row">  
67 - <span flex></span>  
68 - <md-button ng-disabled="$root.loading || vm.ruleChains.selection==null" type="submit" class="md-raised md-primary">  
69 - {{ 'action.assign' | translate }}  
70 - </md-button>  
71 - <md-button ng-disabled="$root.loading" ng-click="vm.cancel()" style="margin-right:20px;">{{ 'action.cancel' |  
72 - translate }}  
73 - </md-button>  
74 - </md-dialog-actions>  
75 - </form>  
76 -</md-dialog>  
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 -/*@ngInject*/  
17 -export default function AddEntityViewsToEdgeController(entityViewService, $mdDialog, $q, edgeId, entityViews) {  
18 -  
19 - var vm = this;  
20 -  
21 - vm.entityViews = entityViews;  
22 - vm.searchText = '';  
23 -  
24 - vm.assign = assign;  
25 - vm.cancel = cancel;  
26 - vm.hasData = hasData;  
27 - vm.noData = noData;  
28 - vm.searchEntityViewTextUpdated = searchEntityViewTextUpdated;  
29 - vm.toggleEntityViewSelection = toggleEntityViewSelection;  
30 -  
31 - vm.theEntityViews = {  
32 - getItemAtIndex: function (index) {  
33 - if (index > vm.entityViews.data.length) {  
34 - vm.theEntityViews.fetchMoreItems_(index);  
35 - return null;  
36 - }  
37 - var item = vm.entityViews.data[index];  
38 - if (item) {  
39 - item.indexNumber = index + 1;  
40 - }  
41 - return item;  
42 - },  
43 -  
44 - getLength: function () {  
45 - if (vm.entityViews.hasNext) {  
46 - return vm.entityViews.data.length + vm.entityViews.nextPageLink.limit;  
47 - } else {  
48 - return vm.entityViews.data.length;  
49 - }  
50 - },  
51 -  
52 - fetchMoreItems_: function () {  
53 - if (vm.entityViews.hasNext && !vm.entityViews.pending) {  
54 - vm.entityViews.pending = true;  
55 - entityViewService.getTenantEntityViews(vm.entityViews.nextPageLink, false).then(  
56 - function success(entityViews) {  
57 - vm.entityViews.data = vm.entityViews.data.concat(entityViews.data);  
58 - vm.entityViews.nextPageLink = entityViews.nextPageLink;  
59 - vm.entityViews.hasNext = entityViews.hasNext;  
60 - if (vm.entityViews.hasNext) {  
61 - vm.entityViews.nextPageLink.limit = vm.entityViews.pageSize;  
62 - }  
63 - vm.entityViews.pending = false;  
64 - },  
65 - function fail() {  
66 - vm.entityViews.hasNext = false;  
67 - vm.entityViews.pending = false;  
68 - });  
69 - }  
70 - }  
71 - };  
72 -  
73 - function cancel () {  
74 - $mdDialog.cancel();  
75 - }  
76 -  
77 - function assign() {  
78 - var tasks = [];  
79 - for (var entityViewId in vm.entityViews.selections) {  
80 - tasks.push(entityViewService.assignEntityViewToEdge(edgeId, entityViewId));  
81 - }  
82 - $q.all(tasks).then(function () {  
83 - $mdDialog.hide();  
84 - });  
85 - }  
86 -  
87 - function noData() {  
88 - return vm.entityViews.data.length == 0 && !vm.entityViews.hasNext;  
89 - }  
90 -  
91 - function hasData() {  
92 - return vm.entityViews.data.length > 0;  
93 - }  
94 -  
95 - function toggleEntityViewSelection($event, entityView) {  
96 - $event.stopPropagation();  
97 - var selected = angular.isDefined(entityView.selected) && entityView.selected;  
98 - entityView.selected = !selected;  
99 - if (entityView.selected) {  
100 - vm.entityViews.selections[entityView.id.id] = true;  
101 - vm.entityViews.selectedCount++;  
102 - } else {  
103 - delete vm.entityViews.selections[entityView.id.id];  
104 - vm.entityViews.selectedCount--;  
105 - }  
106 - }  
107 -  
108 - function searchEntityViewTextUpdated() {  
109 - vm.entityViews = {  
110 - pageSize: vm.entityViews.pageSize,  
111 - data: [],  
112 - nextPageLink: {  
113 - limit: vm.entityViews.pageSize,  
114 - textSearch: vm.searchText  
115 - },  
116 - selections: {},  
117 - selectedCount: 0,  
118 - hasNext: true,  
119 - pending: false  
120 - };  
121 - }  
122 -  
123 -}  
1 -<!--  
2 -  
3 - Copyright © 2016-2020 The Thingsboard Authors  
4 -  
5 - Licensed under the Apache License, Version 2.0 (the "License");  
6 - you may not use this file except in compliance with the License.  
7 - You may obtain a copy of the License at  
8 -  
9 - http://www.apache.org/licenses/LICENSE-2.0  
10 -  
11 - Unless required by applicable law or agreed to in writing, software  
12 - distributed under the License is distributed on an "AS IS" BASIS,  
13 - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  
14 - See the License for the specific language governing permissions and  
15 - limitations under the License.  
16 -  
17 --->  
18 -<md-dialog aria-label="{{ 'edge.assign-to-edge' | translate }}">  
19 - <form name="theForm" ng-submit="vm.assign()">  
20 - <md-toolbar>  
21 - <div class="md-toolbar-tools">  
22 - <h2 translate>entity-view.assign-entity-view-to-edge</h2>  
23 - <span flex></span>  
24 - <md-button class="md-icon-button" ng-click="vm.cancel()">  
25 - <ng-md-icon icon="close" aria-label="{{ 'dialog.close' | translate }}"></ng-md-icon>  
26 - </md-button>  
27 - </div>  
28 - </md-toolbar>  
29 - <md-progress-linear class="md-warn" md-mode="indeterminate" ng-disabled="!$root.loading" ng-show="$root.loading"></md-progress-linear>  
30 - <span style="min-height: 5px;" flex="" ng-show="!$root.loading"></span>  
31 - <md-dialog-content>  
32 - <div class="md-dialog-content">  
33 - <fieldset>  
34 - <span translate>entity-view.assign-entity-view-to-edge-text</span>  
35 - <md-input-container class="md-block" style='margin-bottom: 0px;'>  
36 - <label>&nbsp;</label>  
37 - <md-icon aria-label="{{ 'action.search' | translate }}" class="material-icons">  
38 - search  
39 - </md-icon>  
40 - <input id="entity-view-search" autofocus ng-model="vm.searchText"  
41 - ng-change="vm.searchEntityViewTextUpdated()"  
42 - placeholder="{{ 'common.enter-search' | translate }}"/>  
43 - </md-input-container>  
44 - <div style='min-height: 150px;'>  
45 - <span translate layout-align="center center"  
46 - style="text-transform: uppercase; display: flex; height: 150px;"  
47 - class="md-subhead"  
48 - ng-show="vm.noData()">entity-view.no-entity-views-text</span>  
49 - <md-virtual-repeat-container ng-show="vm.hasData()"  
50 - tb-scope-element="repeatContainer" md-top-index="vm.topIndex" flex  
51 - style='min-height: 150px; width: 100%;'>  
52 - <md-list>  
53 - <md-list-item md-virtual-repeat="entityView in vm.theEntityViews" md-on-demand  
54 - class="repeated-item" flex>  
55 - <md-checkbox ng-click="vm.toggleEntityViewSelection($event, entityView)"  
56 - aria-label="{{ 'item.selected' | translate }}"  
57 - ng-checked="entityView.selected"></md-checkbox>  
58 - <span> {{ entityView.name }} </span>  
59 - </md-list-item>  
60 - </md-list>  
61 - </md-virtual-repeat-container>  
62 - </div>  
63 - </fieldset>  
64 - </div>  
65 - </md-dialog-content>  
66 - <md-dialog-actions layout="row">  
67 - <span flex></span>  
68 - <md-button ng-disabled="$root.loading || vm.entityViews.selectedCount == 0" type="submit"  
69 - class="md-raised md-primary">  
70 - {{ 'action.assign' | translate }}  
71 - </md-button>  
72 - <md-button ng-disabled="$root.loading" ng-click="vm.cancel()" style="margin-right:20px;">{{ 'action.cancel' |  
73 - translate }}  
74 - </md-button>  
75 - </md-dialog-actions>  
76 - </form>  
77 -</md-dialog>  
1 -<!--  
2 -  
3 - Copyright © 2016-2020 The Thingsboard Authors  
4 -  
5 - Licensed under the Apache License, Version 2.0 (the "License");  
6 - you may not use this file except in compliance with the License.  
7 - You may obtain a copy of the License at  
8 -  
9 - http://www.apache.org/licenses/LICENSE-2.0  
10 -  
11 - Unless required by applicable law or agreed to in writing, software  
12 - distributed under the License is distributed on an "AS IS" BASIS,  
13 - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  
14 - See the License for the specific language governing permissions and  
15 - limitations under the License.  
16 -  
17 --->  
18 -<div translate class="tb-cell" flex="20">event.event-time</div>  
19 -<div translate class="tb-cell" flex="20">event.event-type</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>  
1 -<!--  
2 -  
3 - Copyright © 2016-2020 The Thingsboard Authors  
4 -  
5 - Licensed under the Apache License, Version 2.0 (the "License");  
6 - you may not use this file except in compliance with the License.  
7 - You may obtain a copy of the License at  
8 -  
9 - http://www.apache.org/licenses/LICENSE-2.0  
10 -  
11 - Unless required by applicable law or agreed to in writing, software  
12 - distributed under the License is distributed on an "AS IS" BASIS,  
13 - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  
14 - See the License for the specific language governing permissions and  
15 - limitations under the License.  
16 -  
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.type }}</div>  
20 -<div class="tb-cell" flex="40">{{ event.action }}</div>  
21 -<div class="tb-cell" flex="20">{{ event.entityId }}</div>  
22 -<div class="tb-cell" flex="15" ng-style="{'color': statusColor}">{{ updateStatus(event.createdTime) }}</div>  
23 -<div class="tb-cell" flex="10">  
24 - <md-button ng-if="checkEdgeEventType(event.type)" class="md-icon-button md-primary"  
25 - ng-click="showEdgeEntityContent($event, 'edge.entity-info', 'JSON')"  
26 - aria-label="{{ 'action.view' | translate }}">  
27 - <md-tooltip md-direction="top">  
28 - {{ 'action.view' | translate }}  
29 - </md-tooltip>  
30 - <md-icon aria-label="{{ 'action.view' | translate }}"  
31 - class="material-icons">  
32 - more_horiz  
33 - </md-icon>  
34 - </md-button>  
35 -</div>  
36 -  
37 -  
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 -/*@ngInject*/  
17 -export default function AddRuleChainsToEdgeController(ruleChainService, $mdDialog, $q, $filter, edgeId, ruleChains) {  
18 -  
19 - var vm = this;  
20 -  
21 - vm.ruleChains = ruleChains;  
22 - vm.searchText = '';  
23 -  
24 - vm.assign = assign;  
25 - vm.cancel = cancel;  
26 - vm.hasData = hasData;  
27 - vm.noData = noData;  
28 - vm.searchRuleChainTextUpdated = searchRuleChainTextUpdated;  
29 - vm.toggleRuleChainSelection = toggleRuleChainSelection;  
30 -  
31 - vm.theRuleChains = {  
32 - getItemAtIndex: function (index) {  
33 - if (index > vm.ruleChains.data.length) {  
34 - vm.theRuleChains.fetchMoreItems_(index);  
35 - return null;  
36 - }  
37 - var item = vm.ruleChains.data[index];  
38 - if (item) {  
39 - item.indexNumber = index + 1;  
40 - }  
41 - return item;  
42 - },  
43 -  
44 - getLength: function () {  
45 - if (vm.ruleChains.hasNext) {  
46 - return vm.ruleChains.data.length + vm.ruleChains.nextPageLink.limit;  
47 - } else {  
48 - return vm.ruleChains.data.length;  
49 - }  
50 - },  
51 -  
52 - fetchMoreItems_: function () {  
53 - if (vm.ruleChains.hasNext && !vm.ruleChains.pending) {  
54 - vm.ruleChains.pending = true;  
55 - ruleChainService.getEdgesRuleChains(vm.ruleChains.nextPageLink).then(  
56 - function success(ruleChains) {  
57 - vm.ruleChains.data = vm.ruleChains.data.concat(ruleChains.data);  
58 - vm.ruleChains.nextPageLink = ruleChains.nextPageLink;  
59 - vm.ruleChains.hasNext = ruleChains.hasNext;  
60 - if (vm.ruleChains.hasNext) {  
61 - vm.ruleChains.nextPageLink.limit = vm.ruleChains.pageSize;  
62 - }  
63 - vm.ruleChains.pending = false;  
64 - },  
65 - function fail() {  
66 - vm.ruleChains.hasNext = false;  
67 - vm.ruleChains.pending = false;  
68 - });  
69 - }  
70 - }  
71 - }  
72 -  
73 - function cancel () {  
74 - $mdDialog.cancel();  
75 - }  
76 -  
77 - function assign () {  
78 - var tasks = [];  
79 - for (var ruleChainId in vm.ruleChains.selections) {  
80 - tasks.push(ruleChainService.assignRuleChainToEdge(edgeId, ruleChainId));  
81 - }  
82 - $q.all(tasks).then(function () {  
83 - $mdDialog.hide();  
84 - });  
85 - }  
86 -  
87 - function noData () {  
88 - return vm.ruleChains.data.length == 0 && !vm.ruleChains.hasNext;  
89 - }  
90 -  
91 - function hasData () {  
92 - return vm.ruleChains.data.length > 0;  
93 - }  
94 -  
95 - function toggleRuleChainSelection ($event, ruleChain) {  
96 - $event.stopPropagation();  
97 - var selected = angular.isDefined(ruleChain.selected) && ruleChain.selected;  
98 - ruleChain.selected = !selected;  
99 - if (ruleChain.selected) {  
100 - vm.ruleChains.selections[ruleChain.id.id] = true;  
101 - vm.ruleChains.selectedCount++;  
102 - } else {  
103 - delete vm.ruleChains.selections[ruleChain.id.id];  
104 - vm.ruleChains.selectedCount--;  
105 - }  
106 - }  
107 -  
108 - function searchRuleChainTextUpdated () {  
109 - vm.ruleChains = {  
110 - pageSize: vm.ruleChains.pageSize,  
111 - data: [],  
112 - nextPageLink: {  
113 - limit: vm.ruleChains.pageSize,  
114 - textSearch: vm.searchText  
115 - },  
116 - selections: {},  
117 - selectedCount: 0,  
118 - hasNext: true,  
119 - pending: false  
120 - };  
121 - }  
122 -}  
1 -<!--  
2 -  
3 - Copyright © 2016-2020 The Thingsboard Authors  
4 -  
5 - Licensed under the Apache License, Version 2.0 (the "License");  
6 - you may not use this file except in compliance with the License.  
7 - You may obtain a copy of the License at  
8 -  
9 - http://www.apache.org/licenses/LICENSE-2.0  
10 -  
11 - Unless required by applicable law or agreed to in writing, software  
12 - distributed under the License is distributed on an "AS IS" BASIS,  
13 - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  
14 - See the License for the specific language governing permissions and  
15 - limitations under the License.  
16 -  
17 --->  
18 -<md-dialog aria-label="{{ 'rulechain.assign-rulechain-to-edge-title' | translate }}">  
19 - <form name="theForm" ng-submit="vm.assign()">  
20 - <md-toolbar>  
21 - <div class="md-toolbar-tools">  
22 - <h2 translate>rulechain.assign-rulechain-to-edge-title</h2>  
23 - <span flex></span>  
24 - <md-button class="md-icon-button" ng-click="vm.cancel()">  
25 - <ng-md-icon icon="close" aria-label="{{ 'dialog.close' | translate }}"></ng-md-icon>  
26 - </md-button>  
27 - </div>  
28 - </md-toolbar>  
29 - <md-progress-linear class="md-warn" md-mode="indeterminate" ng-disabled="!$root.loading" ng-show="$root.loading"></md-progress-linear>  
30 - <span style="min-height: 5px;" flex="" ng-show="!$root.loading"></span>  
31 - <md-dialog-content>  
32 - <div class="md-dialog-content">  
33 - <fieldset>  
34 - <span translate>rulechain.assign-rulechain-to-edge-text</span>  
35 - <md-input-container class="md-block" style='margin-bottom: 0px;'>  
36 - <label>&nbsp;</label>  
37 - <md-icon aria-label="{{ 'action.search' | translate }}" class="material-icons">  
38 - search  
39 - </md-icon>  
40 - <input id="rulechain-search" autofocus ng-model="vm.searchText"  
41 - ng-change="vm.searchRuleChainTextUpdated()"  
42 - placeholder="{{ 'common.enter-search' | translate }}"/>  
43 - </md-input-container>  
44 - <div style='min-height: 150px;'>  
45 - <span translate layout-align="center center"  
46 - style="text-transform: uppercase; display: flex; height: 150px;"  
47 - class="md-subhead"  
48 - ng-show="vm.noData()">rulechain.no-rulechains-text</span>  
49 - <md-virtual-repeat-container ng-show="vm.hasData()"  
50 - tb-scope-element="repeatContainer" md-top-index="vm.topIndex" flex  
51 - style='min-height: 150px; width: 100%;'>  
52 - <md-list>  
53 - <md-list-item md-virtual-repeat="ruleChain in vm.theRuleChains" md-on-demand  
54 - class="repeated-item" flex>  
55 - <md-checkbox ng-click="vm.toggleRuleChainSelection($event, ruleChain)"  
56 - aria-label="{{ 'item.selected' | translate }}"  
57 - ng-checked="ruleChain.selected"></md-checkbox>  
58 - <span> {{ ruleChain.name }} </span>  
59 - </md-list-item>  
60 - </md-list>  
61 - </md-virtual-repeat-container>  
62 - </div>  
63 - </fieldset>  
64 - </div>  
65 - </md-dialog-content>  
66 - <md-dialog-actions layout="row">  
67 - <span flex></span>  
68 - <md-button ng-disabled="$root.loading || vm.ruleChains.selectedCount == 0" type="submit"  
69 - class="md-raised md-primary">  
70 - {{ 'action.assign' | translate }}  
71 - </md-button>  
72 - <md-button ng-disabled="$root.loading" ng-click="vm.cancel()" style="margin-right:20px;">{{ 'action.cancel' |  
73 - translate }}  
74 - </md-button>  
75 - </md-dialog-actions>  
76 - </form>  
77 -</md-dialog>