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 18 import com.datastax.oss.driver.api.core.uuid.Uuids;
19 19 import com.fasterxml.jackson.core.JsonProcessingException;
20 20 import com.fasterxml.jackson.databind.ObjectMapper;
  21 +import com.fasterxml.jackson.databind.node.ObjectNode;
21 22 import com.google.common.util.concurrent.FutureCallback;
22 23 import com.google.common.util.concurrent.Futures;
23 24 import com.google.common.util.concurrent.ListenableFuture;
... ... @@ -342,8 +343,8 @@ public final class EdgeGrpcSession implements Closeable {
342 343 case CREDENTIALS_REQUEST:
343 344 downlinkMsg = processCredentialsRequestMessage(edgeEvent);
344 345 break;
345   - case ENTITY_EXISTS_REQUEST:
346   - downlinkMsg = processEntityExistsRequestMessage(edgeEvent);
  346 + case ENTITY_MERGE_REQUEST:
  347 + downlinkMsg = processEntityMergeRequestMessage(edgeEvent);
347 348 break;
348 349 case RPC_CALL:
349 350 downlinkMsg = processRpcCallMsg(edgeEvent);
... ... @@ -359,13 +360,18 @@ public final class EdgeGrpcSession implements Closeable {
359 360 return result;
360 361 }
361 362
362   - private DownlinkMsg processEntityExistsRequestMessage(EdgeEvent edgeEvent) {
  363 + private DownlinkMsg processEntityMergeRequestMessage(EdgeEvent edgeEvent) {
363 364 DownlinkMsg downlinkMsg = null;
364 365 if (EdgeEventType.DEVICE.equals(edgeEvent.getType())) {
365 366 DeviceId deviceId = new DeviceId(edgeEvent.getEntityId());
366 367 Device device = ctx.getDeviceService().findDeviceById(edge.getTenantId(), deviceId);
367 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 375 downlinkMsg = DownlinkMsg.newBuilder()
370 376 .addAllDeviceUpdateMsg(Collections.singletonList(d))
371 377 .build();
... ... @@ -504,7 +510,7 @@ public final class EdgeGrpcSession implements Closeable {
504 510 if (device != null) {
505 511 CustomerId customerId = getCustomerIdIfEdgeAssignedToCustomer(device);
506 512 DeviceUpdateMsg deviceUpdateMsg =
507   - ctx.getDeviceMsgConstructor().constructDeviceUpdatedMsg(msgType, device, customerId);
  513 + ctx.getDeviceMsgConstructor().constructDeviceUpdatedMsg(msgType, device, customerId, null);
508 514 downlinkMsg = DownlinkMsg.newBuilder()
509 515 .addAllDeviceUpdateMsg(Collections.singletonList(deviceUpdateMsg))
510 516 .build();
... ...
... ... @@ -38,7 +38,7 @@ public class DeviceMsgConstructor {
38 38
39 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 42 DeviceUpdateMsg.Builder builder = DeviceUpdateMsg.newBuilder()
43 43 .setMsgType(msgType)
44 44 .setIdMSB(device.getId().getId().getMostSignificantBits())
... ... @@ -55,6 +55,9 @@ public class DeviceMsgConstructor {
55 55 if (device.getAdditionalInfo() != null) {
56 56 builder.setAdditionalInfo(JacksonUtil.toString(device.getAdditionalInfo()));
57 57 }
  58 + if (conflictName != null) {
  59 + builder.setConflictName(conflictName);
  60 + }
58 61 return builder.build();
59 62 }
60 63
... ...
... ... @@ -37,6 +37,7 @@ import org.thingsboard.server.dao.dashboard.DashboardService;
37 37 import org.thingsboard.server.dao.device.DeviceCredentialsService;
38 38 import org.thingsboard.server.dao.device.DeviceService;
39 39 import org.thingsboard.server.dao.edge.EdgeEventService;
  40 +import org.thingsboard.server.dao.edge.EdgeService;
40 41 import org.thingsboard.server.dao.entityview.EntityViewService;
41 42 import org.thingsboard.server.dao.relation.RelationService;
42 43 import org.thingsboard.server.dao.user.UserService;
... ... @@ -65,6 +66,9 @@ public abstract class BaseProcessor {
65 66 protected EntityViewService entityViewService;
66 67
67 68 @Autowired
  69 + protected EdgeService edgeService;
  70 +
  71 + @Autowired
68 72 protected CustomerService customerService;
69 73
70 74 @Autowired
... ...
... ... @@ -17,12 +17,14 @@ package org.thingsboard.server.service.edge.rpc.processor;
17 17
18 18 import com.fasterxml.jackson.core.JsonProcessingException;
19 19 import com.fasterxml.jackson.databind.node.ObjectNode;
  20 +import com.google.common.util.concurrent.FutureCallback;
20 21 import com.google.common.util.concurrent.Futures;
21 22 import com.google.common.util.concurrent.ListenableFuture;
22 23 import com.google.common.util.concurrent.SettableFuture;
23 24 import lombok.extern.slf4j.Slf4j;
24 25 import org.apache.commons.lang.RandomStringUtils;
25 26 import org.apache.commons.lang.StringUtils;
  27 +import org.checkerframework.checker.nullness.qual.Nullable;
26 28 import org.springframework.stereotype.Component;
27 29 import org.thingsboard.rule.engine.api.RpcError;
28 30 import org.thingsboard.server.common.data.DataConstants;
... ... @@ -52,6 +54,7 @@ import org.thingsboard.server.queue.util.TbCoreComponent;
52 54 import org.thingsboard.server.service.rpc.FromDeviceRpcResponse;
53 55 import org.thingsboard.server.service.rpc.FromDeviceRpcResponseActorMsg;
54 56
  57 +import java.util.List;
55 58 import java.util.UUID;
56 59 import java.util.concurrent.locks.ReentrantLock;
57 60
... ... @@ -64,38 +67,62 @@ public class DeviceProcessor extends BaseProcessor {
64 67
65 68 public ListenableFuture<Void> onDeviceUpdate(TenantId tenantId, Edge edge, DeviceUpdateMsg deviceUpdateMsg) {
66 69 log.trace("[{}] onDeviceUpdate [{}] from edge [{}]", tenantId, deviceUpdateMsg, edge.getName());
67   - DeviceId edgeDeviceId = new DeviceId(new UUID(deviceUpdateMsg.getIdMSB(), deviceUpdateMsg.getIdLSB()));
68 70 switch (deviceUpdateMsg.getMsgType()) {
69 71 case ENTITY_CREATED_RPC_MESSAGE:
70 72 String deviceName = deviceUpdateMsg.getName();
71 73 Device device = deviceService.findDeviceByTenantIdAndName(tenantId, deviceName);
72 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 117 break;
92 118 case ENTITY_UPDATED_RPC_MESSAGE:
93 119 updateDevice(tenantId, edge, deviceUpdateMsg);
94 120 break;
95 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 124 if (deviceToDelete != null) {
98   - deviceService.unassignDeviceFromEdge(tenantId, edgeDeviceId, edge.getId());
  125 + deviceService.unassignDeviceFromEdge(tenantId, deviceId, edge.getId());
99 126 }
100 127 break;
101 128 case UNRECOGNIZED:
... ... @@ -105,7 +132,6 @@ public class DeviceProcessor extends BaseProcessor {
105 132 return Futures.immediateFuture(null);
106 133 }
107 134
108   -
109 135 public ListenableFuture<Void> onDeviceCredentialsUpdate(TenantId tenantId, DeviceCredentialsUpdateMsg deviceCredentialsUpdateMsg) {
110 136 log.debug("Executing onDeviceCredentialsUpdate, deviceCredentialsUpdateMsg [{}]", deviceCredentialsUpdateMsg);
111 137 DeviceId deviceId = new DeviceId(new UUID(deviceCredentialsUpdateMsg.getDeviceIdMSB(), deviceCredentialsUpdateMsg.getDeviceIdLSB()));
... ... @@ -133,37 +159,34 @@ public class DeviceProcessor extends BaseProcessor {
133 159 private void updateDevice(TenantId tenantId, Edge edge, DeviceUpdateMsg deviceUpdateMsg) {
134 160 DeviceId deviceId = new DeviceId(new UUID(deviceUpdateMsg.getIdMSB(), deviceUpdateMsg.getIdLSB()));
135 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 175 Device device;
147 176 try {
148 177 deviceCreationLock.lock();
149 178 log.debug("[{}] Creating device entity [{}] from edge [{}]", tenantId, deviceUpdateMsg, edge.getName());
150   -// DeviceId deviceId = new DeviceId(new UUID(deviceUpdateMsg.getIdMSB(), deviceUpdateMsg.getIdLSB()));
151 179 device = new Device();
152   -// device.setId(deviceId);
153 180 device.setTenantId(edge.getTenantId());
154 181 device.setCustomerId(edge.getCustomerId());
155   - device.setName(deviceUpdateMsg.getName());
  182 + device.setName(deviceName);
156 183 device.setType(deviceUpdateMsg.getType());
157 184 device.setLabel(deviceUpdateMsg.getLabel());
158 185 device.setAdditionalInfo(JacksonUtil.toJsonNode(deviceUpdateMsg.getAdditionalInfo()));
159 186 device = deviceService.saveDevice(device);
160   - // TODO: voba - is this still required?
161   -// createDeviceCredentials(device);
162 187 createRelationFromEdge(tenantId, edge.getId(), device.getId());
163 188 deviceStateService.onDeviceAdded(device);
164 189 pushDeviceCreatedEventToRuleEngine(tenantId, edge, device);
165   -
166   - // saveEdgeEvent(tenantId, edge.getId(), EdgeEventType.DEVICE, EdgeEventActionType.CREDENTIALS_REQUEST, deviceId, null);
167 190 } finally {
168 191 deviceCreationLock.unlock();
169 192 }
... ... @@ -179,14 +202,6 @@ public class DeviceProcessor extends BaseProcessor {
179 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 205 private void pushDeviceCreatedEventToRuleEngine(TenantId tenantId, Edge edge, Device device) {
191 206 try {
192 207 DeviceId deviceId = device.getId();
... ...
... ... @@ -26,6 +26,7 @@ import com.google.protobuf.AbstractMessage;
26 26 import com.google.protobuf.InvalidProtocolBufferException;
27 27 import com.google.protobuf.MessageLite;
28 28 import lombok.extern.slf4j.Slf4j;
  29 +import org.apache.commons.lang.RandomStringUtils;
29 30 import org.junit.After;
30 31 import org.junit.Assert;
31 32 import org.junit.Before;
... ... @@ -962,6 +963,7 @@ abstract public class BaseEdgeTest extends AbstractControllerTest {
962 963 private void testSendMessagesToCloud() throws Exception {
963 964 log.info("Sending messages to cloud");
964 965 sendDevice();
  966 + sendDeviceWithNameThatAlreadyExistsOnCloud();
965 967 sendRelationRequest();
966 968 sendAlarm();
967 969 sendTelemetry();
... ... @@ -972,8 +974,7 @@ abstract public class BaseEdgeTest extends AbstractControllerTest {
972 974 sendDeviceCredentialsRequest();
973 975 sendDeviceRpcResponse();
974 976 sendDeviceCredentialsUpdate();
975   - // TODO: voba - fix this test
976   - // sendAttributesRequest();
  977 + sendAttributesRequest();
977 978 log.info("Messages were sent successfully");
978 979 }
979 980
... ... @@ -991,17 +992,64 @@ abstract public class BaseEdgeTest extends AbstractControllerTest {
991 992 uplinkMsgBuilder.addDeviceUpdateMsg(deviceUpdateMsgBuilder.build());
992 993
993 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 1033 testAutoGeneratedCodeByProtobuf(uplinkMsgBuilder);
996 1034
997 1035 edgeImitator.sendUplinkMsg(uplinkMsgBuilder.build());
  1036 +
998 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 1055 private void sendRelationRequest() throws Exception {
... ...
... ... @@ -34,5 +34,5 @@ public enum EdgeEventActionType {
34 34 ASSIGNED_TO_EDGE,
35 35 UNASSIGNED_FROM_EDGE,
36 36 CREDENTIALS_REQUEST,
37   - ENTITY_EXISTS_REQUEST
  37 + ENTITY_MERGE_REQUEST
38 38 }
\ No newline at end of file
... ...
... ... @@ -97,7 +97,7 @@ enum UpdateMsgType {
97 97 ENTITY_DELETED_RPC_MESSAGE = 2;
98 98 ALARM_ACK_RPC_MESSAGE = 3;
99 99 ALARM_CLEAR_RPC_MESSAGE = 4;
100   - DEVICE_CONFLICT_RPC_MESSAGE = 5;
  100 + ENTITY_MERGE_RPC_MESSAGE = 5;
101 101 }
102 102
103 103 message EntityDataProto {
... ... @@ -182,6 +182,7 @@ message DeviceUpdateMsg {
182 182 string type = 7;
183 183 string label = 8;
184 184 string additionalInfo = 9;
  185 + string conflictName = 10;
185 186 }
186 187
187 188 message DeviceCredentialsUpdateMsg {
... ...
... ... @@ -109,6 +109,7 @@ import org.thingsboard.server.common.data.rule.DefaultRuleChainCreateRequest;
109 109 import org.thingsboard.server.common.data.rule.RuleChain;
110 110 import org.thingsboard.server.common.data.rule.RuleChainData;
111 111 import org.thingsboard.server.common.data.rule.RuleChainMetaData;
  112 +import org.thingsboard.server.common.data.rule.RuleChainType;
112 113 import org.thingsboard.server.common.data.security.DeviceCredentials;
113 114 import org.thingsboard.server.common.data.security.DeviceCredentialsType;
114 115 import org.thingsboard.server.common.data.security.model.SecuritySettings;
... ... @@ -120,6 +121,7 @@ import org.thingsboard.server.common.data.widget.WidgetsBundle;
120 121 import java.io.Closeable;
121 122 import java.io.IOException;
122 123 import java.net.URI;
  124 +import java.util.Arrays;
123 125 import java.util.Collections;
124 126 import java.util.HashMap;
125 127 import java.util.List;
... ... @@ -700,22 +702,31 @@ public class RestClient implements ClientHttpRequestInterceptor, Closeable {
700 702 }
701 703
702 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 709 return restTemplate.exchange(
704   - baseURL + "/api/components?componentType={componentType}",
  710 + baseURL + "/api/components/" + componentType.name() + "/?ruleChainType={ruleChainType}",
705 711 HttpMethod.GET, HttpEntity.EMPTY,
706 712 new ParameterizedTypeReference<List<ComponentDescriptor>>() {
707 713 },
708   - componentType).getBody();
  714 + ruleChainType).getBody();
709 715 }
710 716
711 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 722 return restTemplate.exchange(
713   - baseURL + "/api/components?componentTypes={componentTypes}",
  723 + baseURL + "/api/components?componentTypes={componentTypes}&ruleChainType={ruleChainType}",
714 724 HttpMethod.GET,
715 725 HttpEntity.EMPTY,
716 726 new ParameterizedTypeReference<List<ComponentDescriptor>>() {
717 727 },
718   - listEnumToString(componentTypes))
  728 + listEnumToString(componentTypes),
  729 + ruleChainType)
719 730 .getBody();
720 731 }
721 732
... ...
... ... @@ -1117,6 +1117,7 @@
1117 1117 "edge": {
1118 1118 "edge": "Edge",
1119 1119 "edges": "Edges",
  1120 + "edge-file": "Edge file",
1120 1121 "management": "Edge management",
1121 1122 "no-edges-matching": "No edges matching '{{entity}}' were found.",
1122 1123 "add": "Add Edge",
... ... @@ -1173,17 +1174,19 @@
1173 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 1175 "import": "Import edge",
1175 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 1178 "assign-new-edge": "Assign new edge",
1178 1179 "manage-edge-dashboards": "Manage edge dashboards",
1179 1180 "unassign-from-edge": "Unassign from edge",
1180 1181 "dashboards": "Edge Dashboards",
1181 1182 "manage-edge-rulechains": "Manage edge rule chains",
  1183 + "rulechains": "Edge Rule Chains",
  1184 + "rulechain": "Edge Rule Chain",
1182 1185 "edge-key": "Edge key",
1183   - "copy-edge-key": "Copy Edge key",
  1186 + "copy-edge-key": "Copy edge key",
1184 1187 "edge-key-copied-message": "Edge key has been copied to clipboard",
1185 1188 "edge-secret": "Edge secret",
1186   - "copy-edge-secret": "Copy Edge secret",
  1189 + "copy-edge-secret": "Copy edge secret",
1187 1190 "edge-secret-copied-message": "Edge secret has been copied to clipboard",
1188 1191 "manage-edge-assets": "Manage edge assets",
1189 1192 "manage-edge-devices": "Manage edge devices",
... ... @@ -1191,22 +1194,23 @@
1191 1194 "assets": "Edge assets",
1192 1195 "devices": "Edge devices",
1193 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 1200 "status": "Received by edge",
1198 1201 "success": "Deployed",
1199 1202 "failed": "Pending",
1200 1203 "search": "Search edges",
1201 1204 "selected-edges": "{ count, plural, 1 {1 edge} other {# edges} } selected",
1202   - "enter-edge-type": "Enter entity view type",
1203 1205 "any-edge": "Any edge",
1204 1206 "no-edge-types-matching": "No edge types matching '{{entitySubtype}}' were found.",
1205 1207 "edge-type-list-empty": "No device types selected.",
1206 1208 "edge-types": "Edge types",
1207 1209 "dashboard": "Edge dashboard",
1208 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 1215 "error": {
1212 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>
\ No newline at end of file
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   -}
\ No newline at end of file
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>
\ No newline at end of file
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>
\ No newline at end of file
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>
\ No newline at end of file
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>
\ No newline at end of file
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>
\ No newline at end of file
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>
\ No newline at end of file
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   -}
\ No newline at end of file
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>