diff --git a/application/src/main/java/org/thingsboard/server/controller/AssetController.java b/application/src/main/java/org/thingsboard/server/controller/AssetController.java index cb4a989d60..c8810d3b4a 100644 --- a/application/src/main/java/org/thingsboard/server/controller/AssetController.java +++ b/application/src/main/java/org/thingsboard/server/controller/AssetController.java @@ -32,14 +32,14 @@ import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.asset.Asset; import org.thingsboard.server.common.data.asset.AssetSearchQuery; import org.thingsboard.server.common.data.audit.ActionType; -import org.thingsboard.server.common.data.exception.ThingsboardErrorCode; +import org.thingsboard.server.common.data.edge.Edge; import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.id.AssetId; import org.thingsboard.server.common.data.id.CustomerId; +import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.TextPageData; import org.thingsboard.server.common.data.page.TextPageLink; -import org.thingsboard.server.common.data.security.Authority; import org.thingsboard.server.dao.exception.IncorrectParameterException; import org.thingsboard.server.dao.model.ModelConstants; import org.thingsboard.server.service.security.model.SecurityUser; @@ -330,4 +330,92 @@ public class AssetController extends BaseController { throw handleException(e); } } + + @PreAuthorize("hasAuthority('TENANT_ADMIN')") + @RequestMapping(value = "/edge/{edgeId}/asset/{assetId}", method = RequestMethod.POST) + @ResponseBody + public Asset assignAssetToEdge(@PathVariable("edgeId") String strEdgeId, + @PathVariable(ASSET_ID) String strAssetId) throws ThingsboardException { + checkParameter("edgeId", strEdgeId); + checkParameter(ASSET_ID, strAssetId); + try { + EdgeId edgeId = new EdgeId(toUUID(strEdgeId)); + Edge edge = checkEdgeId(edgeId, Operation.READ); + + AssetId assetId = new AssetId(toUUID(strAssetId)); + checkAssetId(assetId, Operation.ASSIGN_TO_EDGE); + + Asset savedAsset = checkNotNull(assetService.assignAssetToEdge(getTenantId(), assetId, edgeId)); + + logEntityAction(assetId, savedAsset, + savedAsset.getCustomerId(), + ActionType.ASSIGNED_TO_EDGE, null, strAssetId, strEdgeId, edge.getName()); + + return savedAsset; + } catch (Exception e) { + + logEntityAction(emptyId(EntityType.ASSET), null, + null, + ActionType.ASSIGNED_TO_EDGE, e, strAssetId, strEdgeId); + + throw handleException(e); + } + } + + @PreAuthorize("hasAuthority('TENANT_ADMIN')") + @RequestMapping(value = "/edge/asset/{assetId}", method = RequestMethod.DELETE) + @ResponseBody + public Asset unassignAssetFromEdge(@PathVariable(ASSET_ID) String strAssetId) throws ThingsboardException { + checkParameter(ASSET_ID, strAssetId); + try { + AssetId assetId = new AssetId(toUUID(strAssetId)); + Asset asset = checkAssetId(assetId, Operation.UNASSIGN_FROM_EDGE); + if (asset.getEdgeId() == null || asset.getEdgeId().getId().equals(ModelConstants.NULL_UUID)) { + throw new IncorrectParameterException("Asset isn't assigned to any edge!"); + } + + Edge edge = checkEdgeId(asset.getEdgeId(), Operation.READ); + + Asset savedAsset = checkNotNull(assetService.unassignAssetFromEdge(getTenantId(), assetId)); + + logEntityAction(assetId, asset, + asset.getCustomerId(), + ActionType.UNASSIGNED_FROM_EDGE, null, strAssetId, edge.getId().toString(), edge.getName()); + + return savedAsset; + } catch (Exception e) { + + logEntityAction(emptyId(EntityType.ASSET), null, + null, + ActionType.UNASSIGNED_FROM_EDGE, e, strAssetId); + + throw handleException(e); + } + } + + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") + @RequestMapping(value = "/edge/{edgeId}/assets", params = {"limit"}, method = RequestMethod.GET) + @ResponseBody + public TextPageData getEdgeAssets( + @PathVariable("edgeId") String strEdgeId, + @RequestParam int limit, + @RequestParam(required = false) String type, + @RequestParam(required = false) String textSearch, + @RequestParam(required = false) String idOffset, + @RequestParam(required = false) String textOffset) throws ThingsboardException { + checkParameter("edgeId", strEdgeId); + try { + TenantId tenantId = getCurrentUser().getTenantId(); + EdgeId edgeId = new EdgeId(toUUID(strEdgeId)); + checkEdgeId(edgeId, Operation.READ); + TextPageLink pageLink = createPageLink(limit, textSearch, idOffset, textOffset); + if (type != null && type.trim().length()>0) { + return checkNotNull(assetService.findAssetsByTenantIdAndEdgeIdAndType(tenantId, edgeId, type, pageLink)); + } else { + return checkNotNull(assetService.findAssetsByTenantIdAndEdgeId(tenantId, edgeId, pageLink)); + } + } catch (Exception e) { + throw handleException(e); + } + } } diff --git a/application/src/main/java/org/thingsboard/server/controller/DeviceController.java b/application/src/main/java/org/thingsboard/server/controller/DeviceController.java index f497c4fefa..a65255ff07 100644 --- a/application/src/main/java/org/thingsboard/server/controller/DeviceController.java +++ b/application/src/main/java/org/thingsboard/server/controller/DeviceController.java @@ -37,9 +37,11 @@ import org.thingsboard.server.common.data.EntitySubtype; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.audit.ActionType; import org.thingsboard.server.common.data.device.DeviceSearchQuery; +import org.thingsboard.server.common.data.edge.Edge; import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.DeviceId; +import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.TextPageData; import org.thingsboard.server.common.data.page.TextPageLink; @@ -59,6 +61,8 @@ import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; +import static org.thingsboard.server.controller.EdgeController.EDGE_ID; + @RestController @RequestMapping("/api") public class DeviceController extends BaseController { @@ -479,4 +483,87 @@ public class DeviceController extends BaseController { } return DataConstants.DEFAULT_SECRET_KEY; } + + @PreAuthorize("hasAuthority('TENANT_ADMIN')") + @RequestMapping(value = "/edge/{edgeId}/device/{deviceId}", method = RequestMethod.POST) + @ResponseBody + public Device assignDeviceToEdge(@PathVariable(EDGE_ID) String strEdgeId, + @PathVariable(DEVICE_ID) String strDeviceId) throws ThingsboardException { + checkParameter(EDGE_ID, strEdgeId); + checkParameter(DEVICE_ID, strDeviceId); + try { + EdgeId edgeId = new EdgeId(toUUID(strEdgeId)); + Edge edge = checkEdgeId(edgeId, Operation.READ); + + DeviceId deviceId = new DeviceId(toUUID(strDeviceId)); + checkDeviceId(deviceId, Operation.ASSIGN_TO_EDGE); + + Device savedDevice = checkNotNull(deviceService.assignDeviceToEdge(getCurrentUser().getTenantId(), deviceId, edgeId)); + + logEntityAction(deviceId, savedDevice, + savedDevice.getCustomerId(), + ActionType.ASSIGNED_TO_EDGE, null, strDeviceId, strEdgeId, edge.getName()); + + return savedDevice; + } catch (Exception e) { + logEntityAction(emptyId(EntityType.DEVICE), null, + null, + ActionType.ASSIGNED_TO_EDGE, e, strDeviceId, strEdgeId); + throw handleException(e); + } + } + + @PreAuthorize("hasAuthority('TENANT_ADMIN')") + @RequestMapping(value = "/edge/device/{deviceId}", method = RequestMethod.DELETE) + @ResponseBody + public Device unassignDeviceFromEdge(@PathVariable(DEVICE_ID) String strDeviceId) throws ThingsboardException { + checkParameter(DEVICE_ID, strDeviceId); + try { + DeviceId deviceId = new DeviceId(toUUID(strDeviceId)); + Device device = checkDeviceId(deviceId, Operation.UNASSIGN_FROM_EDGE); + if (device.getEdgeId() == null || device.getEdgeId().getId().equals(ModelConstants.NULL_UUID)) { + throw new IncorrectParameterException("Device isn't assigned to any edge!"); + } + Edge edge = checkEdgeId(device.getEdgeId(), Operation.READ); + + Device savedDevice = checkNotNull(deviceService.unassignDeviceFromEdge(getCurrentUser().getTenantId(), deviceId)); + + logEntityAction(deviceId, device, + device.getCustomerId(), + ActionType.UNASSIGNED_FROM_EDGE, null, strDeviceId, edge.getId().toString(), edge.getName()); + + return savedDevice; + } catch (Exception e) { + logEntityAction(emptyId(EntityType.DEVICE), null, + null, + ActionType.UNASSIGNED_FROM_EDGE, e, strDeviceId); + throw handleException(e); + } + } + + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") + @RequestMapping(value = "/edge/{edgeId}/devices", params = {"limit"}, method = RequestMethod.GET) + @ResponseBody + public TextPageData getEdgeDevices( + @PathVariable("edgeId") String strEdgeId, + @RequestParam int limit, + @RequestParam(required = false) String type, + @RequestParam(required = false) String textSearch, + @RequestParam(required = false) String idOffset, + @RequestParam(required = false) String textOffset) throws ThingsboardException { + checkParameter("edgeId", strEdgeId); + try { + TenantId tenantId = getCurrentUser().getTenantId(); + EdgeId edgeId = new EdgeId(toUUID(strEdgeId)); + checkEdgeId(edgeId, Operation.READ); + TextPageLink pageLink = createPageLink(limit, textSearch, idOffset, textOffset); + if (type != null && type.trim().length()>0) { + return checkNotNull(deviceService.findDevicesByTenantIdAndEdgeIdAndType(tenantId, edgeId, type, pageLink)); + } else { + return checkNotNull(deviceService.findDevicesByTenantIdAndEdgeId(tenantId, edgeId, pageLink)); + } + } catch (Exception e) { + throw handleException(e); + } + } } diff --git a/application/src/main/java/org/thingsboard/server/controller/EdgeController.java b/application/src/main/java/org/thingsboard/server/controller/EdgeController.java index 1a16fbd4ed..32018f63d1 100644 --- a/application/src/main/java/org/thingsboard/server/controller/EdgeController.java +++ b/application/src/main/java/org/thingsboard/server/controller/EdgeController.java @@ -54,7 +54,7 @@ import java.util.stream.Collectors; @RequestMapping("/api") public class EdgeController extends BaseController { - private static final String EDGE_ID = "edgeId"; + public static final String EDGE_ID = "edgeId"; @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/edge/{edgeId}", method = RequestMethod.GET) @@ -118,6 +118,22 @@ public class EdgeController extends BaseController { } } + @PreAuthorize("hasAuthority('TENANT_ADMIN')") + @RequestMapping(value = "/edges", params = {"limit"}, method = RequestMethod.GET) + @ResponseBody + public TextPageData getEdges(@RequestParam int limit, + @RequestParam(required = false) String textSearch, + @RequestParam(required = false) String idOffset, + @RequestParam(required = false) String textOffset) throws ThingsboardException { + try { + TextPageLink pageLink = createPageLink(limit, textSearch, idOffset, textOffset); + TenantId tenantId = getCurrentUser().getTenantId(); + return checkNotNull(edgeService.findEdgesByTenantId(tenantId, pageLink)); + } catch (Exception e) { + throw handleException(e); + } + } + @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/customer/{customerId}/edge/{edgeId}", method = RequestMethod.POST) @ResponseBody diff --git a/application/src/main/java/org/thingsboard/server/controller/EntityViewController.java b/application/src/main/java/org/thingsboard/server/controller/EntityViewController.java index b0d9896e4b..373bdbbf97 100644 --- a/application/src/main/java/org/thingsboard/server/controller/EntityViewController.java +++ b/application/src/main/java/org/thingsboard/server/controller/EntityViewController.java @@ -35,9 +35,11 @@ import org.thingsboard.server.common.data.EntitySubtype; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.EntityView; import org.thingsboard.server.common.data.audit.ActionType; +import org.thingsboard.server.common.data.edge.Edge; import org.thingsboard.server.common.data.entityview.EntityViewSearchQuery; import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.id.CustomerId; +import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.EntityViewId; import org.thingsboard.server.common.data.id.TenantId; @@ -59,6 +61,7 @@ import java.util.concurrent.ExecutionException; import java.util.stream.Collectors; import static org.thingsboard.server.controller.CustomerController.CUSTOMER_ID; +import static org.thingsboard.server.controller.EdgeController.EDGE_ID; /** * Created by Victor Basanets on 8/28/2017. @@ -365,4 +368,83 @@ public class EntityViewController extends BaseController { throw handleException(e); } } + + @PreAuthorize("hasAuthority('TENANT_ADMIN')") + @RequestMapping(value = "/edge/{edgeId}/entityView/{entityViewId}", method = RequestMethod.POST) + @ResponseBody + public EntityView assignEntityViewToEdge(@PathVariable(EDGE_ID) String strEdgeId, + @PathVariable(ENTITY_VIEW_ID) String strEntityViewId) throws ThingsboardException { + checkParameter(EDGE_ID, strEdgeId); + checkParameter(ENTITY_VIEW_ID, strEntityViewId); + try { + EdgeId edgeId = new EdgeId(toUUID(strEdgeId)); + Edge edge = checkEdgeId(edgeId, Operation.READ); + + EntityViewId entityViewId = new EntityViewId(toUUID(strEntityViewId)); + checkEntityViewId(entityViewId, Operation.ASSIGN_TO_EDGE); + + EntityView savedEntityView = checkNotNull(entityViewService.assignEntityViewToEdge(getTenantId(), entityViewId, edgeId)); + logEntityAction(entityViewId, savedEntityView, + savedEntityView.getCustomerId(), + ActionType.ASSIGNED_TO_EDGE, null, strEntityViewId, strEdgeId, edge.getName()); + return savedEntityView; + } catch (Exception e) { + logEntityAction(emptyId(EntityType.ENTITY_VIEW), null, + null, + ActionType.ASSIGNED_TO_EDGE, e, strEntityViewId, strEdgeId); + throw handleException(e); + } + } + + @PreAuthorize("hasAuthority('TENANT_ADMIN')") + @RequestMapping(value = "/edge/entityView/{entityViewId}", method = RequestMethod.DELETE) + @ResponseBody + public EntityView unassignEntityViewFromEdge(@PathVariable(ENTITY_VIEW_ID) String strEntityViewId) throws ThingsboardException { + checkParameter(ENTITY_VIEW_ID, strEntityViewId); + try { + EntityViewId entityViewId = new EntityViewId(toUUID(strEntityViewId)); + EntityView entityView = checkEntityViewId(entityViewId, Operation.UNASSIGN_FROM_EDGE); + if (entityView.getEdgeId() == null || entityView.getEdgeId().getId().equals(ModelConstants.NULL_UUID)) { + throw new IncorrectParameterException("Entity View isn't assigned to any edge!"); + } + Edge edge = checkEdgeId(entityView.getEdgeId(), Operation.READ); + EntityView savedEntityView = checkNotNull(entityViewService.unassignEntityViewFromEdge(getTenantId(), entityViewId)); + logEntityAction(entityViewId, entityView, + entityView.getCustomerId(), + ActionType.UNASSIGNED_FROM_EDGE, null, strEntityViewId, edge.getId().toString(), edge.getName()); + + return savedEntityView; + } catch (Exception e) { + logEntityAction(emptyId(EntityType.ENTITY_VIEW), null, + null, + ActionType.UNASSIGNED_FROM_EDGE, e, strEntityViewId); + throw handleException(e); + } + } + + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") + @RequestMapping(value = "/edge/{edgeId}/entityViews", params = {"limit"}, method = RequestMethod.GET) + @ResponseBody + public TextPageData getEdgeEntityViews( + @PathVariable("edgeId") String strEdgeId, + @RequestParam int limit, + @RequestParam(required = false) String type, + @RequestParam(required = false) String textSearch, + @RequestParam(required = false) String idOffset, + @RequestParam(required = false) String textOffset) throws ThingsboardException { + checkParameter("edgeId", strEdgeId); + try { + TenantId tenantId = getCurrentUser().getTenantId(); + EdgeId edgeId = new EdgeId(toUUID(strEdgeId)); + checkEdgeId(edgeId, Operation.READ); + TextPageLink pageLink = createPageLink(limit, textSearch, idOffset, textOffset); + if (type != null && type.trim().length()>0) { + return checkNotNull(entityViewService.findEntityViewsByTenantIdAndEdgeIdAndType(tenantId, edgeId, type, pageLink)); + } else { + return checkNotNull(entityViewService.findEntityViewsByTenantIdAndEdgeId(tenantId, edgeId, pageLink)); + } + } catch (Exception e) { + throw handleException(e); + } + } } diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/asset/AssetService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/asset/AssetService.java index 97933f7ab7..be17ae18e7 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/asset/AssetService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/asset/AssetService.java @@ -21,6 +21,7 @@ import org.thingsboard.server.common.data.asset.Asset; import org.thingsboard.server.common.data.asset.AssetSearchQuery; import org.thingsboard.server.common.data.id.AssetId; import org.thingsboard.server.common.data.id.CustomerId; +import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.TextPageData; import org.thingsboard.server.common.data.page.TextPageLink; @@ -63,4 +64,12 @@ public interface AssetService { ListenableFuture> findAssetsByQuery(TenantId tenantId, AssetSearchQuery query); ListenableFuture> findAssetTypesByTenantId(TenantId tenantId); + + Asset assignAssetToEdge(TenantId tenantId, AssetId assetId, EdgeId edgeId); + + Asset unassignAssetFromEdge(TenantId tenantId, AssetId assetId); + + TextPageData findAssetsByTenantIdAndEdgeId(TenantId tenantId, EdgeId edgeId, TextPageLink pageLink); + + TextPageData findAssetsByTenantIdAndEdgeIdAndType(TenantId tenantId, EdgeId edgeId, String type, TextPageLink pageLink); } diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceService.java index 793bb9829b..62ae55be3a 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceService.java @@ -21,6 +21,7 @@ import org.thingsboard.server.common.data.EntitySubtype; import org.thingsboard.server.common.data.device.DeviceSearchQuery; import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.DeviceId; +import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.TextPageData; import org.thingsboard.server.common.data.page.TextPageLink; @@ -63,4 +64,12 @@ public interface DeviceService { ListenableFuture> findDeviceTypesByTenantId(TenantId tenantId); + Device assignDeviceToEdge(TenantId tenantId, DeviceId deviceId, EdgeId edgeId); + + Device unassignDeviceFromEdge(TenantId tenantId, DeviceId deviceId); + + TextPageData findDevicesByTenantIdAndEdgeId(TenantId tenantId, EdgeId edgeId, TextPageLink pageLink); + + TextPageData findDevicesByTenantIdAndEdgeIdAndType(TenantId tenantId, EdgeId edgeId, String type, TextPageLink pageLink); + } diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/entityview/EntityViewService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/entityview/EntityViewService.java index 454a36446b..86475a3b5d 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/entityview/EntityViewService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/entityview/EntityViewService.java @@ -18,9 +18,9 @@ package org.thingsboard.server.dao.entityview; import com.google.common.util.concurrent.ListenableFuture; import org.thingsboard.server.common.data.EntitySubtype; import org.thingsboard.server.common.data.EntityView; -import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.entityview.EntityViewSearchQuery; import org.thingsboard.server.common.data.id.CustomerId; +import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.EntityViewId; import org.thingsboard.server.common.data.id.TenantId; @@ -65,4 +65,14 @@ public interface EntityViewService { void deleteEntityViewsByTenantId(TenantId tenantId); ListenableFuture> findEntityViewTypesByTenantId(TenantId tenantId); + + EntityView assignEntityViewToEdge(TenantId tenantId, EntityViewId entityViewId, EdgeId edgeId); + + EntityView unassignEntityViewFromEdge(TenantId tenantId, EntityViewId entityViewId); + + TextPageData findEntityViewsByTenantIdAndEdgeId(TenantId tenantId, EdgeId edgeId, TextPageLink pageLink); + + TextPageData findEntityViewsByTenantIdAndEdgeIdAndType(TenantId tenantId, EdgeId edgeId, String type, TextPageLink pageLink); + + } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/Device.java b/common/data/src/main/java/org/thingsboard/server/common/data/Device.java index 971a5568d4..7866e35a57 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/Device.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/Device.java @@ -18,6 +18,7 @@ package org.thingsboard.server.common.data; import lombok.EqualsAndHashCode; import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.DeviceId; +import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.TenantId; @EqualsAndHashCode(callSuper = true) @@ -27,6 +28,7 @@ public class Device extends SearchTextBasedWithAdditionalInfo implemen private TenantId tenantId; private CustomerId customerId; + private EdgeId edgeId; private String name; private String type; private String label; @@ -46,6 +48,7 @@ public class Device extends SearchTextBasedWithAdditionalInfo implemen this.name = device.getName(); this.type = device.getType(); this.label = device.getLabel(); + this.edgeId = device.getEdgeId(); } public TenantId getTenantId() { @@ -64,6 +67,14 @@ public class Device extends SearchTextBasedWithAdditionalInfo implemen this.customerId = customerId; } + public EdgeId getEdgeId() { + return edgeId; + } + + public void setEdgeId(EdgeId edgeId) { + this.edgeId = edgeId; + } + @Override public String getName() { return name; @@ -101,6 +112,8 @@ public class Device extends SearchTextBasedWithAdditionalInfo implemen builder.append(tenantId); builder.append(", customerId="); builder.append(customerId); + builder.append(", edgeId="); + builder.append(edgeId); builder.append(", name="); builder.append(name); builder.append(", type="); diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/EntityView.java b/common/data/src/main/java/org/thingsboard/server/common/data/EntityView.java index 4075fca000..993efc2604 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/EntityView.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/EntityView.java @@ -19,6 +19,7 @@ import lombok.AllArgsConstructor; import lombok.Data; import lombok.EqualsAndHashCode; import org.thingsboard.server.common.data.id.CustomerId; +import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.EntityViewId; import org.thingsboard.server.common.data.id.TenantId; @@ -39,6 +40,7 @@ public class EntityView extends SearchTextBasedWithAdditionalInfo private EntityId entityId; private TenantId tenantId; private CustomerId customerId; + private EdgeId edgeId; private String name; private String type; private TelemetryEntityView keys; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/asset/Asset.java b/common/data/src/main/java/org/thingsboard/server/common/data/asset/Asset.java index 174044de28..8d926de853 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/asset/Asset.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/asset/Asset.java @@ -20,6 +20,7 @@ import lombok.EqualsAndHashCode; import org.thingsboard.server.common.data.*; import org.thingsboard.server.common.data.id.AssetId; import org.thingsboard.server.common.data.id.CustomerId; +import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.TenantId; @EqualsAndHashCode(callSuper = true) @@ -31,6 +32,7 @@ public class Asset extends SearchTextBasedWithAdditionalInfo implements private CustomerId customerId; private String name; private String type; + private EdgeId edgeId; public Asset() { super(); @@ -46,6 +48,7 @@ public class Asset extends SearchTextBasedWithAdditionalInfo implements this.customerId = asset.getCustomerId(); this.name = asset.getName(); this.type = asset.getType(); + this.edgeId = asset.getEdgeId(); } public TenantId getTenantId() { @@ -64,6 +67,14 @@ public class Asset extends SearchTextBasedWithAdditionalInfo implements this.customerId = customerId; } + public EdgeId getEdgeId() { + return edgeId; + } + + public void setEdgeId(EdgeId edgeId) { + this.edgeId = edgeId; + } + @Override public String getName() { return name; @@ -93,6 +104,8 @@ public class Asset extends SearchTextBasedWithAdditionalInfo implements builder.append(tenantId); builder.append(", customerId="); builder.append(customerId); + builder.append(", edgeId="); + builder.append(edgeId); builder.append(", name="); builder.append(name); builder.append(", type="); diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/edge/EdgeQueueEntry.java b/common/data/src/main/java/org/thingsboard/server/common/data/edge/EdgeQueueEntry.java index 4cfc210267..6dad707c90 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/edge/EdgeQueueEntry.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/edge/EdgeQueueEntry.java @@ -1,3 +1,18 @@ +/** + * Copyright © 2016-2019 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.thingsboard.server.common.data.edge; import lombok.Data; diff --git a/dao/src/main/java/org/thingsboard/server/dao/asset/AssetDao.java b/dao/src/main/java/org/thingsboard/server/dao/asset/AssetDao.java index 1c67fd40eb..c7b8b23610 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/asset/AssetDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/asset/AssetDao.java @@ -115,4 +115,24 @@ public interface AssetDao extends Dao { */ ListenableFuture> findTenantAssetTypesAsync(UUID tenantId); + /** + * Find assets by tenantId, customerId and page link. + * + * @param tenantId the tenantId + * @param edgeId the edgeId + * @param pageLink the page link + * @return the list of asset objects + */ + List findAssetsByTenantIdAndEdgeId(UUID tenantId, UUID edgeId, TextPageLink pageLink); + + /** + * Find assets by tenantId, customerId, type and page link. + * + * @param tenantId the tenantId + * @param edgeId the edgeId + * @param type the type + * @param pageLink the page link + * @return the list of asset objects + */ + List findAssetsByTenantIdAndEdgeIdAndType(UUID tenantId, UUID edgeId, String type, TextPageLink pageLink); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/asset/BaseAssetService.java b/dao/src/main/java/org/thingsboard/server/dao/asset/BaseAssetService.java index cf679a103f..c77935d124 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/asset/BaseAssetService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/asset/BaseAssetService.java @@ -36,6 +36,7 @@ import org.thingsboard.server.common.data.asset.Asset; import org.thingsboard.server.common.data.asset.AssetSearchQuery; import org.thingsboard.server.common.data.id.AssetId; import org.thingsboard.server.common.data.id.CustomerId; +import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.TextPageData; @@ -70,6 +71,8 @@ public class BaseAssetService extends AbstractEntityService implements AssetServ public static final String INCORRECT_PAGE_LINK = "Incorrect page link "; public static final String INCORRECT_CUSTOMER_ID = "Incorrect customerId "; public static final String INCORRECT_ASSET_ID = "Incorrect assetId "; + public static final String INCORRECT_EDGE_ID = "Incorrect edgeId "; + @Autowired private AssetDao assetDao; @@ -260,6 +263,41 @@ public class BaseAssetService extends AbstractEntityService implements AssetServ }); } + @Override + public Asset assignAssetToEdge(TenantId tenantId, AssetId assetId, EdgeId edgeId) { + Asset asset = findAssetById(tenantId, assetId); + asset.setEdgeId(edgeId); + return saveAsset(asset); + } + + @Override + public Asset unassignAssetFromEdge(TenantId tenantId, AssetId assetId) { + Asset asset = findAssetById(tenantId, assetId); + asset.setEdgeId(null); + return saveAsset(asset); + } + + @Override + public TextPageData findAssetsByTenantIdAndEdgeId(TenantId tenantId, EdgeId edgeId, TextPageLink pageLink) { + log.trace("Executing findAssetsByTenantIdAndEdgeId, tenantId [{}], edgeId [{}], pageLink [{}]", tenantId, edgeId, pageLink); + validateId(tenantId, INCORRECT_TENANT_ID + tenantId); + validateId(edgeId, INCORRECT_EDGE_ID + edgeId); + validatePageLink(pageLink, INCORRECT_PAGE_LINK + pageLink); + List assets = assetDao.findAssetsByTenantIdAndEdgeId(tenantId.getId(), edgeId.getId(), pageLink); + return new TextPageData<>(assets, pageLink); + } + + @Override + public TextPageData findAssetsByTenantIdAndEdgeIdAndType(TenantId tenantId, EdgeId edgeId, String type, TextPageLink pageLink) { + log.trace("Executing findAssetsByTenantIdAndEdgeIdAndType, tenantId [{}], edgeId [{}], type [{}], pageLink [{}]", tenantId, edgeId, type, pageLink); + validateId(tenantId, INCORRECT_TENANT_ID + tenantId); + validateId(edgeId, INCORRECT_EDGE_ID + edgeId); + validateString(type, "Incorrect type " + type); + validatePageLink(pageLink, INCORRECT_PAGE_LINK + pageLink); + List assets = assetDao.findAssetsByTenantIdAndEdgeIdAndType(tenantId.getId(), edgeId.getId(), type, pageLink); + return new TextPageData<>(assets, pageLink); + } + private DataValidator assetValidator = new DataValidator() { diff --git a/dao/src/main/java/org/thingsboard/server/dao/asset/CassandraAssetDao.java b/dao/src/main/java/org/thingsboard/server/dao/asset/CassandraAssetDao.java index deba1cc639..89acd961fc 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/asset/CassandraAssetDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/asset/CassandraAssetDao.java @@ -188,4 +188,31 @@ public class CassandraAssetDao extends CassandraAbstractSearchTextDao findAssetsByTenantIdAndEdgeId(UUID tenantId, UUID edgeId, TextPageLink pageLink) { +// log.debug("Try to find assets by tenantId [{}], customerId[{}] and pageLink [{}]", tenantId, customerId, pageLink); +// List assetEntities = findPageWithTextSearch(new TenantId(tenantId), ASSET_BY_CUSTOMER_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME, +// Arrays.asList(eq(ASSET_CUSTOMER_ID_PROPERTY, customerId), +// eq(ASSET_TENANT_ID_PROPERTY, tenantId)), +// pageLink); +// +// log.trace("Found assets [{}] by tenantId [{}], customerId [{}] and pageLink [{}]", assetEntities, tenantId, customerId, pageLink); +// return DaoUtil.convertDataList(assetEntities); + throw new UnsupportedOperationException("Cassandra is not supported yet"); + } + + @Override + public List findAssetsByTenantIdAndEdgeIdAndType(UUID tenantId, UUID edgeId, String type, TextPageLink pageLink) { +// log.debug("Try to find assets by tenantId [{}], customerId [{}], type [{}] and pageLink [{}]", tenantId, customerId, type, pageLink); +// List assetEntities = findPageWithTextSearch(new TenantId(tenantId), ASSET_BY_CUSTOMER_BY_TYPE_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME, +// Arrays.asList(eq(ASSET_TYPE_PROPERTY, type), +// eq(ASSET_CUSTOMER_ID_PROPERTY, customerId), +// eq(ASSET_TENANT_ID_PROPERTY, tenantId)), +// pageLink); +// +// log.trace("Found assets [{}] by tenantId [{}], customerId [{}], type [{}] and pageLink [{}]", assetEntities, tenantId, customerId, type, pageLink); +// return DaoUtil.convertDataList(assetEntities); + throw new UnsupportedOperationException("Cassandra is not supported yet"); + } + } diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/CassandraDeviceDao.java b/dao/src/main/java/org/thingsboard/server/dao/device/CassandraDeviceDao.java index fe94db9225..9abda5e031 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/CassandraDeviceDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/CassandraDeviceDao.java @@ -188,4 +188,31 @@ public class CassandraDeviceDao extends CassandraAbstractSearchTextDao findDevicesByTenantIdAndEdgeId(UUID tenantId, UUID edgeId, TextPageLink pageLink) { +// log.debug("Try to find devices by tenantId [{}], customerId[{}] and pageLink [{}]", tenantId, customerId, pageLink); +// List deviceEntities = findPageWithTextSearch(new TenantId(tenantId), DEVICE_BY_CUSTOMER_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME, +// Arrays.asList(eq(DEVICE_CUSTOMER_ID_PROPERTY, customerId), +// eq(DEVICE_TENANT_ID_PROPERTY, tenantId)), +// pageLink); +// +// log.trace("Found devices [{}] by tenantId [{}], customerId [{}] and pageLink [{}]", deviceEntities, tenantId, customerId, pageLink); +// return DaoUtil.convertDataList(deviceEntities); + throw new UnsupportedOperationException("Cassandra is not supported yet"); + } + + @Override + public List findDevicesByTenantIdAndEdgeIdAndType(UUID tenantId, UUID edgeId, String type, TextPageLink pageLink) { +// log.debug("Try to find devices by tenantId [{}], customerId [{}], type [{}] and pageLink [{}]", tenantId, customerId, type, pageLink); +// List deviceEntities = findPageWithTextSearch(new TenantId(tenantId), DEVICE_BY_CUSTOMER_BY_TYPE_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME, +// Arrays.asList(eq(DEVICE_TYPE_PROPERTY, type), +// eq(DEVICE_CUSTOMER_ID_PROPERTY, customerId), +// eq(DEVICE_TENANT_ID_PROPERTY, tenantId)), +// pageLink); +// +// log.trace("Found devices [{}] by tenantId [{}], customerId [{}], type [{}] and pageLink [{}]", deviceEntities, tenantId, customerId, type, pageLink); +// return DaoUtil.convertDataList(deviceEntities); + throw new UnsupportedOperationException("Cassandra is not supported yet"); + } + } diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceDao.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceDao.java index 83533f1e36..df8e5534c4 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceDao.java @@ -115,4 +115,25 @@ public interface DeviceDao extends Dao { * @return the list of tenant device type objects */ ListenableFuture> findTenantDeviceTypesAsync(UUID tenantId); + + /** + * Find devices by tenantId, edgeId and page link. + * + * @param tenantId the tenantId + * @param edgeId the edgeId + * @param pageLink the page link + * @return the list of device objects + */ + List findDevicesByTenantIdAndEdgeId(UUID tenantId, UUID edgeId, TextPageLink pageLink); + + /** + * Find devices by tenantId, edgeId, type and page link. + * + * @param tenantId the tenantId + * @param edgeId the edgeId + * @param type the type + * @param pageLink the page link + * @return the list of device objects + */ + List findDevicesByTenantIdAndEdgeIdAndType(UUID tenantId, UUID edgeId, String type, TextPageLink pageLink); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java index 872e03a387..32615e92ba 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java @@ -34,8 +34,10 @@ import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.EntityView; import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.device.DeviceSearchQuery; +import org.thingsboard.server.common.data.edge.Edge; import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.DeviceId; +import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.TextPageData; @@ -77,6 +79,8 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe public static final String INCORRECT_PAGE_LINK = "Incorrect page link "; public static final String INCORRECT_CUSTOMER_ID = "Incorrect customerId "; public static final String INCORRECT_DEVICE_ID = "Incorrect deviceId "; + public static final String INCORRECT_EDGE_ID = "Incorrect edgeId "; + @Autowired private DeviceDao deviceDao; @@ -291,6 +295,41 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe }); } + @Override + public Device assignDeviceToEdge(TenantId tenantId, DeviceId deviceId, EdgeId edgeId) { + Device device = findDeviceById(tenantId, deviceId); + device.setEdgeId(edgeId); + return saveDevice(device); + } + + @Override + public Device unassignDeviceFromEdge(TenantId tenantId, DeviceId deviceId) { + Device device = findDeviceById(tenantId, deviceId); + device.setEdgeId(null); + return saveDevice(device); + } + + @Override + public TextPageData findDevicesByTenantIdAndEdgeId(TenantId tenantId, EdgeId edgeId, TextPageLink pageLink) { + log.trace("Executing findDevicesByTenantIdAndEdgeId, tenantId [{}], edgeId [{}], pageLink [{}]", tenantId, edgeId, pageLink); + validateId(tenantId, INCORRECT_TENANT_ID + tenantId); + validateId(edgeId, INCORRECT_EDGE_ID + edgeId); + validatePageLink(pageLink, INCORRECT_PAGE_LINK + pageLink); + List devices = deviceDao.findDevicesByTenantIdAndEdgeId(tenantId.getId(), edgeId.getId(), pageLink); + return new TextPageData<>(devices, pageLink); + } + + @Override + public TextPageData findDevicesByTenantIdAndEdgeIdAndType(TenantId tenantId, EdgeId edgeId, String type, TextPageLink pageLink) { + log.trace("Executing findDevicesByTenantIdAndEdgeIdAndType, tenantId [{}], edgeId [{}], type [{}], pageLink [{}]", tenantId, edgeId, type, pageLink); + validateId(tenantId, INCORRECT_TENANT_ID + tenantId); + validateId(edgeId, INCORRECT_EDGE_ID + edgeId); + validateString(type, "Incorrect type " + type); + validatePageLink(pageLink, INCORRECT_PAGE_LINK + pageLink); + List devices = deviceDao.findDevicesByTenantIdAndEdgeIdAndType(tenantId.getId(), edgeId.getId(), type, pageLink); + return new TextPageData<>(devices, pageLink); + } + private DataValidator deviceValidator = new DataValidator() { diff --git a/dao/src/main/java/org/thingsboard/server/dao/edge/BaseEdgeService.java b/dao/src/main/java/org/thingsboard/server/dao/edge/BaseEdgeService.java index 95b61d4053..748d494020 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/edge/BaseEdgeService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/edge/BaseEdgeService.java @@ -5,7 +5,7 @@ * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, diff --git a/dao/src/main/java/org/thingsboard/server/dao/entityview/CassandraEntityViewDao.java b/dao/src/main/java/org/thingsboard/server/dao/entityview/CassandraEntityViewDao.java index 9935178e3f..3c7371539c 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/entityview/CassandraEntityViewDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/entityview/CassandraEntityViewDao.java @@ -183,4 +183,32 @@ public class CassandraEntityViewDao extends CassandraAbstractSearchTextDao findEntityViewsByTenantIdAndEdgeId(UUID tenantId, UUID edgeId, TextPageLink pageLink) { +// log.debug("Try to find entity views by tenantId [{}], customerId[{}] and pageLink [{}]", +// tenantId, customerId, pageLink); +// List entityViewEntities = findPageWithTextSearch(new TenantId(tenantId), +// ENTITY_VIEW_BY_TENANT_AND_CUSTOMER_CF, +// Arrays.asList(eq(CUSTOMER_ID_PROPERTY, customerId), eq(TENANT_ID_PROPERTY, tenantId)), +// pageLink); +// log.trace("Found find entity views [{}] by tenantId [{}], customerId [{}] and pageLink [{}]", +// entityViewEntities, tenantId, customerId, pageLink); +// return DaoUtil.convertDataList(entityViewEntities); + throw new UnsupportedOperationException("Cassandra is not supported yet"); + } + + @Override + public List findEntityViewsByTenantIdAndEdgeIdAndType(UUID tenantId, UUID edgeId, String type, TextPageLink pageLink) { +// log.debug("Try to find entity views by tenantId [{}], customerId[{}], type [{}] and pageLink [{}]", +// tenantId, customerId, type, pageLink); +// List entityViewEntities = findPageWithTextSearch(new TenantId(tenantId), +// ENTITY_VIEW_BY_TENANT_AND_CUSTOMER_AND_TYPE_CF, +// Arrays.asList(eq(DEVICE_TYPE_PROPERTY, type), eq(CUSTOMER_ID_PROPERTY, customerId), eq(TENANT_ID_PROPERTY, tenantId)), +// pageLink); +// log.trace("Found find entity views [{}] by tenantId [{}], customerId [{}], type [{}] and pageLink [{}]", +// entityViewEntities, tenantId, customerId, type, pageLink); +// return DaoUtil.convertDataList(entityViewEntities); + throw new UnsupportedOperationException("Cassandra is not supported yet"); + } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewDao.java b/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewDao.java index b839cac825..c9b10ef4d9 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewDao.java @@ -16,7 +16,6 @@ package org.thingsboard.server.dao.entityview; import com.google.common.util.concurrent.ListenableFuture; -import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.EntitySubtype; import org.thingsboard.server.common.data.EntityView; import org.thingsboard.server.common.data.id.TenantId; @@ -103,4 +102,30 @@ public interface EntityViewDao extends Dao { */ ListenableFuture> findTenantEntityViewTypesAsync(UUID tenantId); + /** + * Find entity views by tenantId, edgeId and page link. + * + * @param tenantId the tenantId + * @param edgeId the edgeId + * @param pageLink the page link + * @return the list of entity view objects + */ + List findEntityViewsByTenantIdAndEdgeId(UUID tenantId, + UUID edgeId, + TextPageLink pageLink); + + /** + * Find entity views by tenantId, edgeId, type and page link. + * + * @param tenantId the tenantId + * @param edgeId the edgeId + * @param type the type + * @param pageLink the page link + * @return the list of entity view objects + */ + List findEntityViewsByTenantIdAndEdgeIdAndType(UUID tenantId, + UUID edgeId, + String type, + TextPageLink pageLink); + } diff --git a/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewServiceImpl.java index e3142e216e..cc6d0ba184 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewServiceImpl.java @@ -35,6 +35,7 @@ import org.thingsboard.server.common.data.EntityView; import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.entityview.EntityViewSearchQuery; import org.thingsboard.server.common.data.id.CustomerId; +import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.EntityViewId; import org.thingsboard.server.common.data.id.TenantId; @@ -75,6 +76,7 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti public static final String INCORRECT_PAGE_LINK = "Incorrect page link "; public static final String INCORRECT_CUSTOMER_ID = "Incorrect customerId "; public static final String INCORRECT_ENTITY_VIEW_ID = "Incorrect entityViewId "; + public static final String INCORRECT_EDGE_ID = "Incorrect edgeId "; @Autowired private EntityViewDao entityViewDao; @@ -282,6 +284,49 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti }); } + + @CacheEvict(cacheNames = ENTITY_VIEW_CACHE, key = "{#entityViewId}") + @Override + public EntityView assignEntityViewToEdge(TenantId tenantId, EntityViewId entityViewId, EdgeId edgeId) { + EntityView entityView = findEntityViewById(tenantId, entityViewId); + entityView.setEdgeId(edgeId); + return saveEntityView(entityView); + } + + @CacheEvict(cacheNames = ENTITY_VIEW_CACHE, key = "{#entityViewId}") + @Override + public EntityView unassignEntityViewFromEdge(TenantId tenantId, EntityViewId entityViewId) { + EntityView entityView = findEntityViewById(tenantId, entityViewId); + entityView.setEdgeId(null); + return saveEntityView(entityView); + } + + @Override + public TextPageData findEntityViewsByTenantIdAndEdgeId(TenantId tenantId, EdgeId edgeId, + TextPageLink pageLink) { + log.trace("Executing findEntityViewsByTenantIdAndEdgeId, tenantId [{}], edgeId [{}]," + + " pageLink [{}]", tenantId, edgeId, pageLink); + validateId(tenantId, INCORRECT_TENANT_ID + tenantId); + validateId(edgeId, INCORRECT_EDGE_ID + edgeId); + validatePageLink(pageLink, INCORRECT_PAGE_LINK + pageLink); + List entityViews = entityViewDao.findEntityViewsByTenantIdAndEdgeId(tenantId.getId(), + edgeId.getId(), pageLink); + return new TextPageData<>(entityViews, pageLink); + } + + @Override + public TextPageData findEntityViewsByTenantIdAndEdgeIdAndType(TenantId tenantId, EdgeId edgeId, String type, TextPageLink pageLink) { + log.trace("Executing findEntityViewsByTenantIdAndEdgeIdAndType, tenantId [{}], edgeId [{}]," + + " pageLink [{}], type [{}]", tenantId, edgeId, pageLink, type); + validateId(tenantId, INCORRECT_TENANT_ID + tenantId); + validateId(edgeId, INCORRECT_EDGE_ID + edgeId); + validatePageLink(pageLink, INCORRECT_PAGE_LINK + pageLink); + validateString(type, "Incorrect type " + type); + List entityViews = entityViewDao.findEntityViewsByTenantIdAndEdgeIdAndType(tenantId.getId(), + edgeId.getId(), type, pageLink); + return new TextPageData<>(entityViews, pageLink); + } + private DataValidator entityViewValidator = new DataValidator() { diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java b/dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java index 516ad3f690..7d78876d5e 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java @@ -137,6 +137,7 @@ public class ModelConstants { public static final String DEVICE_TYPE_PROPERTY = "type"; public static final String DEVICE_LABEL_PROPERTY = "label"; public static final String DEVICE_ADDITIONAL_INFO_PROPERTY = ADDITIONAL_INFO_PROPERTY; + public static final String DEVICE_EDGE_ID_PROPERTY = "edge_id"; public static final String DEVICE_BY_TENANT_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME = "device_by_tenant_and_search_text"; public static final String DEVICE_BY_TENANT_BY_TYPE_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME = "device_by_tenant_by_type_and_search_text"; public static final String DEVICE_BY_CUSTOMER_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME = "device_by_customer_and_search_text"; @@ -152,6 +153,7 @@ public class ModelConstants { public static final String ENTITY_VIEW_TENANT_ID_PROPERTY = TENANT_ID_PROPERTY; public static final String ENTITY_VIEW_CUSTOMER_ID_PROPERTY = CUSTOMER_ID_PROPERTY; public static final String ENTITY_VIEW_NAME_PROPERTY = DEVICE_NAME_PROPERTY; + public static final String ENTITY_VIEW_EDGE_ID_PROPERTY = "edge_id"; public static final String ENTITY_VIEW_BY_TENANT_AND_CUSTOMER_CF = "entity_view_by_tenant_and_customer"; public static final String ENTITY_VIEW_BY_TENANT_AND_CUSTOMER_AND_TYPE_CF = "entity_view_by_tenant_and_customer_and_type"; public static final String ENTITY_VIEW_BY_TENANT_AND_ENTITY_ID_CF = "entity_view_by_tenant_and_entity_id"; @@ -198,6 +200,7 @@ public class ModelConstants { public static final String ASSET_NAME_PROPERTY = "name"; public static final String ASSET_TYPE_PROPERTY = "type"; public static final String ASSET_ADDITIONAL_INFO_PROPERTY = ADDITIONAL_INFO_PROPERTY; + public static final String ASSET_EDGE_ID_PROPERTY = "edge_id"; public static final String ASSET_BY_TENANT_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME = "asset_by_tenant_and_search_text"; public static final String ASSET_BY_TENANT_BY_TYPE_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME = "asset_by_tenant_by_type_and_search_text"; diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/nosql/AssetEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/nosql/AssetEntity.java index a951b970f3..277eb4ea72 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/nosql/AssetEntity.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/nosql/AssetEntity.java @@ -25,6 +25,7 @@ import lombok.ToString; import org.thingsboard.server.common.data.asset.Asset; import org.thingsboard.server.common.data.id.AssetId; import org.thingsboard.server.common.data.id.CustomerId; +import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.dao.model.SearchTextEntity; import org.thingsboard.server.dao.model.type.JsonCodec; @@ -34,6 +35,7 @@ import java.util.UUID; import static org.thingsboard.server.dao.model.ModelConstants.ASSET_ADDITIONAL_INFO_PROPERTY; import static org.thingsboard.server.dao.model.ModelConstants.ASSET_COLUMN_FAMILY_NAME; import static org.thingsboard.server.dao.model.ModelConstants.ASSET_CUSTOMER_ID_PROPERTY; +import static org.thingsboard.server.dao.model.ModelConstants.ASSET_EDGE_ID_PROPERTY; import static org.thingsboard.server.dao.model.ModelConstants.ASSET_NAME_PROPERTY; import static org.thingsboard.server.dao.model.ModelConstants.ASSET_TENANT_ID_PROPERTY; import static org.thingsboard.server.dao.model.ModelConstants.ASSET_TYPE_PROPERTY; @@ -61,6 +63,10 @@ public final class AssetEntity implements SearchTextEntity { @Column(name = ASSET_TYPE_PROPERTY) private String type; + @PartitionKey(value = 4) + @Column(name = ASSET_EDGE_ID_PROPERTY) + private UUID edgeId; + @Column(name = ASSET_NAME_PROPERTY) private String name; @@ -84,6 +90,9 @@ public final class AssetEntity implements SearchTextEntity { if (asset.getCustomerId() != null) { this.customerId = asset.getCustomerId().getId(); } + if (asset.getEdgeId() != null) { + this.edgeId = asset.getEdgeId().getId(); + } this.name = asset.getName(); this.type = asset.getType(); this.additionalInfo = asset.getAdditionalInfo(); @@ -113,6 +122,14 @@ public final class AssetEntity implements SearchTextEntity { this.customerId = customerId; } + public UUID getEdgeId() { + return edgeId; + } + + public void setEdgeId(UUID edgeId) { + this.edgeId = edgeId; + } + public String getName() { return name; } @@ -161,6 +178,9 @@ public final class AssetEntity implements SearchTextEntity { if (customerId != null) { asset.setCustomerId(new CustomerId(customerId)); } + if (edgeId != null) { + asset.setEdgeId(new EdgeId(edgeId)); + } asset.setName(name); asset.setType(type); asset.setAdditionalInfo(additionalInfo); diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/nosql/DeviceEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/nosql/DeviceEntity.java index 2c44cf3d87..f3fdc1d6d7 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/nosql/DeviceEntity.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/nosql/DeviceEntity.java @@ -25,6 +25,7 @@ import lombok.ToString; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.DeviceId; +import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.dao.model.SearchTextEntity; import org.thingsboard.server.dao.model.type.JsonCodec; @@ -54,6 +55,10 @@ public final class DeviceEntity implements SearchTextEntity { @Column(name = DEVICE_TYPE_PROPERTY) private String type; + @PartitionKey(value = 4) + @Column(name = DEVICE_EDGE_ID_PROPERTY) + private UUID edgeId; + @Column(name = DEVICE_NAME_PROPERTY) private String name; @@ -80,6 +85,9 @@ public final class DeviceEntity implements SearchTextEntity { if (device.getCustomerId() != null) { this.customerId = device.getCustomerId().getId(); } + if (device.getEdgeId() != null) { + this.edgeId = device.getEdgeId().getId(); + } this.name = device.getName(); this.type = device.getType(); this.label = device.getLabel(); @@ -109,7 +117,15 @@ public final class DeviceEntity implements SearchTextEntity { public void setCustomerId(UUID customerId) { this.customerId = customerId; } - + + public UUID getEdgeId() { + return edgeId; + } + + public void setEdgeId(UUID edgeId) { + this.edgeId = edgeId; + } + public String getName() { return name; } @@ -158,6 +174,9 @@ public final class DeviceEntity implements SearchTextEntity { if (customerId != null) { device.setCustomerId(new CustomerId(customerId)); } + if (edgeId != null) { + device.setEdgeId(new EdgeId(edgeId)); + } device.setName(name); device.setType(type); device.setLabel(label); diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/nosql/EntityViewEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/nosql/EntityViewEntity.java index f5cebe906a..cfa549b03d 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/nosql/EntityViewEntity.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/nosql/EntityViewEntity.java @@ -29,6 +29,7 @@ import org.hibernate.annotations.Type; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.EntityView; import org.thingsboard.server.common.data.id.CustomerId; +import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.EntityIdFactory; import org.thingsboard.server.common.data.id.EntityViewId; import org.thingsboard.server.common.data.id.TenantId; @@ -41,14 +42,12 @@ import javax.persistence.Enumerated; import java.io.IOException; import java.util.UUID; +import static org.thingsboard.server.dao.model.ModelConstants.DEVICE_EDGE_ID_PROPERTY; import static org.thingsboard.server.dao.model.ModelConstants.DEVICE_TYPE_PROPERTY; import static org.thingsboard.server.dao.model.ModelConstants.ENTITY_TYPE_PROPERTY; import static org.thingsboard.server.dao.model.ModelConstants.ENTITY_VIEW_TABLE_FAMILY_NAME; import static org.thingsboard.server.dao.model.ModelConstants.ID_PROPERTY; -/** - * Created by Victor Basanets on 8/31/2017. - */ @Data @Table(name = ENTITY_VIEW_TABLE_FAMILY_NAME) @EqualsAndHashCode @@ -72,6 +71,10 @@ public class EntityViewEntity implements SearchTextEntity { @Column(name = DEVICE_TYPE_PROPERTY) private String type; + @PartitionKey(value = 4) + @Column(name = DEVICE_EDGE_ID_PROPERTY) + private UUID edgeId; + @Enumerated(EnumType.STRING) @Column(name = ENTITY_TYPE_PROPERTY) private EntityType entityType; @@ -118,6 +121,9 @@ public class EntityViewEntity implements SearchTextEntity { if (entityView.getCustomerId() != null) { this.customerId = entityView.getCustomerId().getId(); } + if (entityView.getEdgeId() != null) { + this.edgeId = entityView.getEdgeId().getId(); + } this.type = entityView.getType(); this.name = entityView.getName(); try { @@ -149,6 +155,9 @@ public class EntityViewEntity implements SearchTextEntity { if (customerId != null) { entityView.setCustomerId(new CustomerId(customerId)); } + if (edgeId != null) { + entityView.setEdgeId(new EdgeId(edgeId)); + } entityView.setType(type); entityView.setName(name); try { diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/sql/AssetEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/sql/AssetEntity.java index 043a02b813..d87dfa560b 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/sql/AssetEntity.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/sql/AssetEntity.java @@ -25,6 +25,7 @@ import org.thingsboard.server.common.data.UUIDConverter; import org.thingsboard.server.common.data.asset.Asset; import org.thingsboard.server.common.data.id.AssetId; import org.thingsboard.server.common.data.id.CustomerId; +import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.dao.model.BaseSqlEntity; import org.thingsboard.server.dao.model.ModelConstants; @@ -37,6 +38,7 @@ import javax.persistence.Table; import static org.thingsboard.server.dao.model.ModelConstants.ASSET_COLUMN_FAMILY_NAME; import static org.thingsboard.server.dao.model.ModelConstants.ASSET_CUSTOMER_ID_PROPERTY; +import static org.thingsboard.server.dao.model.ModelConstants.ASSET_EDGE_ID_PROPERTY; import static org.thingsboard.server.dao.model.ModelConstants.ASSET_NAME_PROPERTY; import static org.thingsboard.server.dao.model.ModelConstants.ASSET_TENANT_ID_PROPERTY; import static org.thingsboard.server.dao.model.ModelConstants.ASSET_TYPE_PROPERTY; @@ -55,6 +57,9 @@ public final class AssetEntity extends BaseSqlEntity implements SearchTex @Column(name = ASSET_CUSTOMER_ID_PROPERTY) private String customerId; + @Column(name = ASSET_EDGE_ID_PROPERTY) + private String edgeId; + @Column(name = ASSET_NAME_PROPERTY) private String name; @@ -82,6 +87,9 @@ public final class AssetEntity extends BaseSqlEntity implements SearchTex if (asset.getCustomerId() != null) { this.customerId = UUIDConverter.fromTimeUUID(asset.getCustomerId().getId()); } + if (asset.getEdgeId() != null) { + this.edgeId = UUIDConverter.fromTimeUUID(asset.getEdgeId().getId()); + } this.name = asset.getName(); this.type = asset.getType(); this.additionalInfo = asset.getAdditionalInfo(); @@ -111,6 +119,9 @@ public final class AssetEntity extends BaseSqlEntity implements SearchTex if (customerId != null) { asset.setCustomerId(new CustomerId(UUIDConverter.fromString(customerId))); } + if (edgeId != null) { + asset.setEdgeId(new EdgeId(UUIDConverter.fromString(edgeId))); + } asset.setName(name); asset.setType(type); asset.setAdditionalInfo(additionalInfo); diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/sql/DeviceEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/sql/DeviceEntity.java index 66feed0077..df5efb6d81 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/sql/DeviceEntity.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/sql/DeviceEntity.java @@ -24,6 +24,7 @@ import org.hibernate.annotations.TypeDef; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.DeviceId; +import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.dao.model.BaseSqlEntity; import org.thingsboard.server.dao.model.ModelConstants; @@ -47,6 +48,9 @@ public final class DeviceEntity extends BaseSqlEntity implements SearchT @Column(name = ModelConstants.DEVICE_CUSTOMER_ID_PROPERTY) private String customerId; + @Column(name = ModelConstants.DEVICE_EDGE_ID_PROPERTY) + private String edgeId; + @Column(name = ModelConstants.DEVICE_TYPE_PROPERTY) private String type; @@ -77,6 +81,9 @@ public final class DeviceEntity extends BaseSqlEntity implements SearchT if (device.getCustomerId() != null) { this.customerId = toString(device.getCustomerId().getId()); } + if (device.getEdgeId() != null) { + this.edgeId = toString(device.getEdgeId().getId()); + } this.name = device.getName(); this.type = device.getType(); this.label = device.getLabel(); @@ -103,6 +110,9 @@ public final class DeviceEntity extends BaseSqlEntity implements SearchT if (customerId != null) { device.setCustomerId(new CustomerId(toUUID(customerId))); } + if (edgeId != null) { + device.setEdgeId(new EdgeId(toUUID(edgeId))); + } device.setName(name); device.setType(type); device.setLabel(label); diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/sql/EntityViewEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/sql/EntityViewEntity.java index 4eddeba6a9..7425be99e5 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/sql/EntityViewEntity.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/sql/EntityViewEntity.java @@ -26,6 +26,7 @@ import org.hibernate.annotations.TypeDef; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.EntityView; import org.thingsboard.server.common.data.id.CustomerId; +import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.EntityIdFactory; import org.thingsboard.server.common.data.id.EntityViewId; import org.thingsboard.server.common.data.id.TenantId; @@ -44,10 +45,6 @@ import java.io.IOException; import static org.thingsboard.server.dao.model.ModelConstants.ENTITY_TYPE_PROPERTY; -/** - * Created by Victor Basanets on 8/30/2017. - */ - @Data @EqualsAndHashCode(callSuper = true) @Entity @@ -69,6 +66,9 @@ public class EntityViewEntity extends BaseSqlEntity implements Searc @Column(name = ModelConstants.ENTITY_VIEW_CUSTOMER_ID_PROPERTY) private String customerId; + @Column(name = ModelConstants.ENTITY_VIEW_EDGE_ID_PROPERTY) + private String edgeId; + @Column(name = ModelConstants.DEVICE_TYPE_PROPERTY) private String type; @@ -111,6 +111,9 @@ public class EntityViewEntity extends BaseSqlEntity implements Searc if (entityView.getCustomerId() != null) { this.customerId = toString(entityView.getCustomerId().getId()); } + if (entityView.getEdgeId() != null) { + this.edgeId = toString(entityView.getEdgeId().getId()); + } this.type = entityView.getType(); this.name = entityView.getName(); try { @@ -148,6 +151,9 @@ public class EntityViewEntity extends BaseSqlEntity implements Searc if (customerId != null) { entityView.setCustomerId(new CustomerId(toUUID(customerId))); } + if (edgeId != null) { + entityView.setEdgeId(new EdgeId(toUUID(edgeId))); + } entityView.setType(type); entityView.setName(name); try { diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/asset/AssetRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/asset/AssetRepository.java index f5e98253b7..124f68057d 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/asset/AssetRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/asset/AssetRepository.java @@ -78,4 +78,25 @@ public interface AssetRepository extends CrudRepository { @Query("SELECT DISTINCT a.type FROM AssetEntity a WHERE a.tenantId = :tenantId") List findTenantAssetTypes(@Param("tenantId") String tenantId); + @Query("SELECT a FROM AssetEntity a WHERE a.tenantId = :tenantId " + + "AND a.edgeId = :edgeId " + + "AND LOWER(a.searchText) LIKE LOWER(CONCAT(:textSearch, '%')) " + + "AND a.id > :idOffset ORDER BY a.id") + List findByTenantIdAndEdgeId(@Param("tenantId") String tenantId, + @Param("edgeId") String edgeId, + @Param("textSearch") String textSearch, + @Param("idOffset") String idOffset, + Pageable pageable); + + @Query("SELECT a FROM AssetEntity a WHERE a.tenantId = :tenantId " + + "AND a.edgeId = :edgeId AND a.type = :type " + + "AND LOWER(a.searchText) LIKE LOWER(CONCAT(:textSearch, '%')) " + + "AND a.id > :idOffset ORDER BY a.id") + List findByTenantIdAndEdgeIdAndType(@Param("tenantId") String tenantId, + @Param("edgeId") String edgeId, + @Param("type") String type, + @Param("textSearch") String textSearch, + @Param("idOffset") String idOffset, + Pageable pageable); + } diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/asset/JpaAssetDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/asset/JpaAssetDao.java index c600efcdf3..96a24ae5b5 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/asset/JpaAssetDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/asset/JpaAssetDao.java @@ -139,4 +139,29 @@ public class JpaAssetDao extends JpaAbstractSearchTextDao im } return list; } + + @Override + public List findAssetsByTenantIdAndEdgeId(UUID tenantId, UUID edgeId, TextPageLink pageLink) { + return DaoUtil.convertDataList(assetRepository + .findByTenantIdAndEdgeId( + fromTimeUUID(tenantId), + fromTimeUUID(edgeId), + Objects.toString(pageLink.getTextSearch(), ""), + pageLink.getIdOffset() == null ? NULL_UUID_STR : fromTimeUUID(pageLink.getIdOffset()), + new PageRequest(0, pageLink.getLimit()))); + } + + + @Override + public List findAssetsByTenantIdAndEdgeIdAndType(UUID tenantId, UUID edgeId, String type, TextPageLink pageLink) { + return DaoUtil.convertDataList(assetRepository + .findByTenantIdAndEdgeIdAndType( + fromTimeUUID(tenantId), + fromTimeUUID(edgeId), + type, + Objects.toString(pageLink.getTextSearch(), ""), + pageLink.getIdOffset() == null ? NULL_UUID_STR : fromTimeUUID(pageLink.getIdOffset()), + new PageRequest(0, pageLink.getLimit()))); + } + } diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/device/DeviceRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/device/DeviceRepository.java index 1c61b33f82..561a5e76c6 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/device/DeviceRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/device/DeviceRepository.java @@ -79,4 +79,26 @@ public interface DeviceRepository extends CrudRepository { List findDevicesByTenantIdAndCustomerIdAndIdIn(String tenantId, String customerId, List deviceIds); List findDevicesByTenantIdAndIdIn(String tenantId, List deviceIds); + + @Query("SELECT d FROM DeviceEntity d WHERE d.tenantId = :tenantId " + + "AND d.edgeId = :edgeId " + + "AND LOWER(d.searchText) LIKE LOWER(CONCAT(:searchText, '%')) " + + "AND d.id > :idOffset ORDER BY d.id") + List findByTenantIdAndEdgeId(@Param("tenantId") String tenantId, + @Param("edgeId") String edgeId, + @Param("searchText") String searchText, + @Param("idOffset") String idOffset, + Pageable pageable); + + @Query("SELECT d FROM DeviceEntity d WHERE d.tenantId = :tenantId " + + "AND d.edgeId = :edgeId " + + "AND d.type = :type " + + "AND LOWER(d.searchText) LIKE LOWER(CONCAT(:textSearch, '%')) " + + "AND d.id > :idOffset ORDER BY d.id") + List findByTenantIdAndEdgeIdAndType(@Param("tenantId") String tenantId, + @Param("edgeId") String edgeId, + @Param("type") String type, + @Param("textSearch") String textSearch, + @Param("idOffset") String idOffset, + Pageable pageable); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/device/JpaDeviceDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/device/JpaDeviceDao.java index be0b4b89df..df3c1cbd5a 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/device/JpaDeviceDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/device/JpaDeviceDao.java @@ -139,4 +139,29 @@ public class JpaDeviceDao extends JpaAbstractSearchTextDao } return list; } + + + @Override + public List findDevicesByTenantIdAndEdgeId(UUID tenantId, UUID edgeId, TextPageLink pageLink) { + return DaoUtil.convertDataList( + deviceRepository.findByTenantIdAndEdgeId( + fromTimeUUID(tenantId), + fromTimeUUID(edgeId), + Objects.toString(pageLink.getTextSearch(), ""), + pageLink.getIdOffset() == null ? NULL_UUID_STR : fromTimeUUID(pageLink.getIdOffset()), + new PageRequest(0, pageLink.getLimit()))); + } + + @Override + public List findDevicesByTenantIdAndEdgeIdAndType(UUID tenantId, UUID edgeId, String type, TextPageLink pageLink) { + return DaoUtil.convertDataList( + deviceRepository.findByTenantIdAndEdgeIdAndType( + fromTimeUUID(tenantId), + fromTimeUUID(edgeId), + type, + Objects.toString(pageLink.getTextSearch(), ""), + pageLink.getIdOffset() == null ? NULL_UUID_STR : fromTimeUUID(pageLink.getIdOffset()), + new PageRequest(0, pageLink.getLimit()))); + } + } diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/entityview/EntityViewRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/entityview/EntityViewRepository.java index f152e1f665..38bd549391 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/entityview/EntityViewRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/entityview/EntityViewRepository.java @@ -76,4 +76,26 @@ public interface EntityViewRepository extends CrudRepository findTenantEntityViewTypes(@Param("tenantId") String tenantId); + + @Query("SELECT e FROM EntityViewEntity e WHERE e.tenantId = :tenantId " + + "AND e.edgeId = :edgeId " + + "AND LOWER(e.searchText) LIKE LOWER(CONCAT(:searchText, '%')) " + + "AND e.id > :idOffset ORDER BY e.id") + List findByTenantIdAndEdgeId(@Param("tenantId") String tenantId, + @Param("edgeId") String edgeId, + @Param("searchText") String searchText, + @Param("idOffset") String idOffset, + Pageable pageable); + + @Query("SELECT e FROM EntityViewEntity e WHERE e.tenantId = :tenantId " + + "AND e.edgeId = :edgeId " + + "AND e.type = :type " + + "AND LOWER(e.searchText) LIKE LOWER(CONCAT(:searchText, '%')) " + + "AND e.id > :idOffset ORDER BY e.id") + List findByTenantIdAndEdgeIdAndType(@Param("tenantId") String tenantId, + @Param("edgeId") String edgeId, + @Param("type") String type, + @Param("searchText") String searchText, + @Param("idOffset") String idOffset, + Pageable pageable); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/entityview/JpaEntityViewDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/entityview/JpaEntityViewDao.java index 981b239e62..df15f75f95 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/entityview/JpaEntityViewDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/entityview/JpaEntityViewDao.java @@ -138,4 +138,32 @@ public class JpaEntityViewDao extends JpaAbstractSearchTextDao findEntityViewsByTenantIdAndEdgeId(UUID tenantId, + UUID edgeId, + TextPageLink pageLink) { + return DaoUtil.convertDataList( + entityViewRepository.findByTenantIdAndEdgeId( + fromTimeUUID(tenantId), + fromTimeUUID(edgeId), + Objects.toString(pageLink.getTextSearch(), ""), + pageLink.getIdOffset() == null ? NULL_UUID_STR : fromTimeUUID(pageLink.getIdOffset()), + new PageRequest(0, pageLink.getLimit()) + )); + } + + @Override + public List findEntityViewsByTenantIdAndEdgeIdAndType(UUID tenantId, UUID edgeId, String type, TextPageLink pageLink) { + return DaoUtil.convertDataList( + entityViewRepository.findByTenantIdAndEdgeIdAndType( + fromTimeUUID(tenantId), + fromTimeUUID(edgeId), + type, + Objects.toString(pageLink.getTextSearch(), ""), + pageLink.getIdOffset() == null ? NULL_UUID_STR : fromTimeUUID(pageLink.getIdOffset()), + new PageRequest(0, pageLink.getLimit()) + )); + } + } diff --git a/msa/js-executor/package-lock.json b/msa/js-executor/package-lock.json index c61ef011a2..706607b99b 100644 --- a/msa/js-executor/package-lock.json +++ b/msa/js-executor/package-lock.json @@ -1261,7 +1261,7 @@ }, "fecha": { "version": "2.3.3", - "resolved": "http://registry.npmjs.org/fecha/-/fecha-2.3.3.tgz", + "resolved": "https://registry.npmjs.org/fecha/-/fecha-2.3.3.tgz", "integrity": "sha512-lUGBnIamTAwk4znq5BcqsDaxSmZ9nDVJaij6NvRt/Tg4R69gERA+otPKbS86ROw9nxVMw2/mp1fnaiWqbs6Sdg==" }, "file-stream-rotator": { @@ -2426,7 +2426,7 @@ }, "json5": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "resolved": "http://registry.npmjs.org/json5/-/json5-1.0.1.tgz", "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", "requires": { "minimist": "^1.2.0" @@ -2947,7 +2947,7 @@ }, "os-homedir": { "version": "1.0.2", - "resolved": "http://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", "optional": true }, @@ -2995,7 +2995,7 @@ }, "path-is-absolute": { "version": "1.0.1", - "resolved": "http://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", "dev": true }, diff --git a/msa/web-ui/package-lock.json b/msa/web-ui/package-lock.json index 9298d31f27..8530f75419 100644 --- a/msa/web-ui/package-lock.json +++ b/msa/web-ui/package-lock.json @@ -1149,7 +1149,7 @@ }, "fecha": { "version": "2.3.3", - "resolved": "http://registry.npmjs.org/fecha/-/fecha-2.3.3.tgz", + "resolved": "https://registry.npmjs.org/fecha/-/fecha-2.3.3.tgz", "integrity": "sha512-lUGBnIamTAwk4znq5BcqsDaxSmZ9nDVJaij6NvRt/Tg4R69gERA+otPKbS86ROw9nxVMw2/mp1fnaiWqbs6Sdg==" }, "file-stream-rotator": { @@ -2354,7 +2354,7 @@ }, "json5": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "resolved": "http://registry.npmjs.org/json5/-/json5-1.0.1.tgz", "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", "requires": { "minimist": "^1.2.0" @@ -2581,7 +2581,7 @@ }, "mkdirp": { "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "resolved": "http://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", "dev": true, "requires": { @@ -2590,7 +2590,7 @@ "dependencies": { "minimist": { "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "resolved": "http://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", "dev": true } @@ -2859,7 +2859,7 @@ }, "path-is-absolute": { "version": "1.0.1", - "resolved": "http://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", "dev": true }, diff --git a/ui/src/app/api/asset.service.js b/ui/src/app/api/asset.service.js index de01620bd3..82111e7f2f 100644 --- a/ui/src/app/api/asset.service.js +++ b/ui/src/app/api/asset.service.js @@ -33,7 +33,10 @@ function AssetService($http, $q, customerService, userService) { findByQuery: findByQuery, fetchAssetsByNameFilter: fetchAssetsByNameFilter, getAssetTypes: getAssetTypes, - findByName: findByName + findByName: findByName, + assignAssetToEdge: assignAssetToEdge, + unassignAssetFromEdge: unassignAssetFromEdge, + getEdgeAssets: getEdgeAssets } return service; @@ -289,4 +292,57 @@ function AssetService($http, $q, customerService, userService) { return deferred.promise; } + function assignAssetToEdge(edgeId, assetId, ignoreErrors, config) { + var deferred = $q.defer(); + var url = '/api/edge/' + edgeId + '/asset/' + assetId; + if (!config) { + config = {}; + } + config = Object.assign(config, { ignoreErrors: ignoreErrors }); + $http.post(url, null, config).then(function success(response) { + deferred.resolve(response.data); + }, function fail() { + deferred.reject(); + }); + return deferred.promise; + } + + function unassignAssetFromEdge(assetId, ignoreErrors, config) { + var deferred = $q.defer(); + var url = '/api/edge/asset/' + assetId; + if (!config) { + config = {}; + } + config = Object.assign(config, { ignoreErrors: ignoreErrors }); + $http.delete(url, config).then(function success(response) { + deferred.resolve(response.data); + }, function fail() { + deferred.reject(); + }); + return deferred.promise; + } + + function getEdgeAssets(edgeId, pageLink, config, type) { + var deferred = $q.defer(); + var url = '/api/edge/' + edgeId + '/assets?limit=' + pageLink.limit; + if (angular.isDefined(pageLink.textSearch)) { + url += '&textSearch=' + pageLink.textSearch; + } + if (angular.isDefined(pageLink.idOffset)) { + url += '&idOffset=' + pageLink.idOffset; + } + if (angular.isDefined(pageLink.textOffset)) { + url += '&textOffset=' + pageLink.textOffset; + } + if (angular.isDefined(type) && type.length) { + url += '&type=' + type; + } + $http.get(url, config).then(function success(response) { + deferred.resolve(response.data); + }, function fail() { + deferred.reject(); + }); + + return deferred.promise; + } } diff --git a/ui/src/app/api/device.service.js b/ui/src/app/api/device.service.js index 429d3b0cdb..d414d72e8f 100644 --- a/ui/src/app/api/device.service.js +++ b/ui/src/app/api/device.service.js @@ -43,7 +43,10 @@ function DeviceService($http, $q, $window, userService, attributeService, custom sendTwoWayRpcCommand: sendTwoWayRpcCommand, findByQuery: findByQuery, getDeviceTypes: getDeviceTypes, - findByName: findByName + findByName: findByName, + assignDeviceToEdge: assignDeviceToEdge, + unassignDeviceFromEdge: unassignDeviceFromEdge, + getEdgeDevices: getEdgeDevices }; return service; @@ -332,4 +335,51 @@ function DeviceService($http, $q, $window, userService, attributeService, custom }); return deferred.promise; } + + function assignDeviceToEdge(edgeId, deviceId) { + var deferred = $q.defer(); + var url = '/api/edge/' + edgeId + '/device/' + deviceId; + $http.post(url, null).then(function success(response) { + deferred.resolve(response.data); + }, function fail() { + deferred.reject(); + }); + return deferred.promise; + } + + function unassignDeviceFromEdge(deviceId) { + var deferred = $q.defer(); + var url = '/api/edge/device/' + deviceId; + $http.delete(url).then(function success(response) { + deferred.resolve(response.data); + }, function fail() { + deferred.reject(); + }); + return deferred.promise; + } + + function getEdgeDevices(edgeId, pageLink, config, type) { + var deferred = $q.defer(); + var url = '/api/edge/' + edgeId + '/devices?limit=' + pageLink.limit; + if (angular.isDefined(pageLink.textSearch)) { + url += '&textSearch=' + pageLink.textSearch; + } + if (angular.isDefined(pageLink.idOffset)) { + url += '&idOffset=' + pageLink.idOffset; + } + if (angular.isDefined(pageLink.textOffset)) { + url += '&textOffset=' + pageLink.textOffset; + } + if (angular.isDefined(type) && type.length) { + url += '&type=' + type; + } + $http.get(url, config).then(function success(response) { + deferred.resolve(response.data); + }, function fail() { + deferred.reject(); + }); + + return deferred.promise; + } + } diff --git a/ui/src/app/api/entity-view.service.js b/ui/src/app/api/entity-view.service.js index 257e3dd498..726e09a06e 100644 --- a/ui/src/app/api/entity-view.service.js +++ b/ui/src/app/api/entity-view.service.js @@ -35,7 +35,10 @@ function EntityViewService($http, $q, $window, userService, attributeService, cu unsubscribeForEntityViewAttributes: unsubscribeForEntityViewAttributes, findByQuery: findByQuery, getEntityViewTypes: getEntityViewTypes, - makeEntityViewPublic: makeEntityViewPublic + makeEntityViewPublic: makeEntityViewPublic, + assignEntityViewToEdge: assignEntityViewToEdge, + unassignEntityViewFromEdge: unassignEntityViewFromEdge, + getEdgeEntityViews: getEdgeEntityViews } return service; @@ -220,5 +223,49 @@ function EntityViewService($http, $q, $window, userService, attributeService, cu return deferred.promise; } + function assignEntityViewToEdge(edgeId, entityViewId) { + var deferred = $q.defer(); + var url = '/api/edge/' + edgeId + '/entityView/' + entityViewId; + $http.post(url, null).then(function success(response) { + deferred.resolve(response.data); + }, function fail() { + deferred.reject(); + }); + return deferred.promise; + } + + function unassignEntityViewFromEdge(entityViewId) { + var deferred = $q.defer(); + var url = '/api/edge/entityView/' + entityViewId; + $http.delete(url).then(function success(response) { + deferred.resolve(response.data); + }, function fail() { + deferred.reject(); + }); + return deferred.promise; + } + + function getEdgeEntityViews(edgeId, pageLink, config, type) { + var deferred = $q.defer(); + var url = '/api/edge/' + edgeId + '/entityViews?limit=' + pageLink.limit; + if (angular.isDefined(pageLink.textSearch)) { + url += '&textSearch=' + pageLink.textSearch; + } + if (angular.isDefined(pageLink.idOffset)) { + url += '&idOffset=' + pageLink.idOffset; + } + if (angular.isDefined(pageLink.textOffset)) { + url += '&textOffset=' + pageLink.textOffset; + } + if (angular.isDefined(type) && type.length) { + url += '&type=' + type; + } + $http.get(url, config).then(function success(response) { + deferred.resolve(response.data); + }, function fail() { + deferred.reject(); + }); + return deferred.promise; + } } diff --git a/ui/src/app/asset/add-assets-to-edge.controller.js b/ui/src/app/asset/add-assets-to-edge.controller.js new file mode 100644 index 0000000000..0234a2c94c --- /dev/null +++ b/ui/src/app/asset/add-assets-to-edge.controller.js @@ -0,0 +1,123 @@ +/* + * Copyright © 2016-2019 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*@ngInject*/ +export default function AddAssetsToEdgeController(assetService, $mdDialog, $q, edgeId, assets) { + + var vm = this; + + vm.assets = assets; + vm.searchText = ''; + + vm.assign = assign; + vm.cancel = cancel; + vm.hasData = hasData; + vm.noData = noData; + vm.searchAssetTextUpdated = searchAssetTextUpdated; + vm.toggleAssetSelection = toggleAssetSelection; + + vm.theAssets = { + getItemAtIndex: function (index) { + if (index > vm.assets.data.length) { + vm.theAssets.fetchMoreItems_(index); + return null; + } + var item = vm.assets.data[index]; + if (item) { + item.indexNumber = index + 1; + } + return item; + }, + + getLength: function () { + if (vm.assets.hasNext) { + return vm.assets.data.length + vm.assets.nextPageLink.limit; + } else { + return vm.assets.data.length; + } + }, + + fetchMoreItems_: function () { + if (vm.assets.hasNext && !vm.assets.pending) { + vm.assets.pending = true; + assetService.getTenantAssets(vm.assets.nextPageLink, false).then( + function success(assets) { + vm.assets.data = vm.assets.data.concat(assets.data); + vm.assets.nextPageLink = assets.nextPageLink; + vm.assets.hasNext = assets.hasNext; + if (vm.assets.hasNext) { + vm.assets.nextPageLink.limit = vm.assets.pageSize; + } + vm.assets.pending = false; + }, + function fail() { + vm.assets.hasNext = false; + vm.assets.pending = false; + }); + } + } + }; + + function cancel () { + $mdDialog.cancel(); + } + + function assign() { + var tasks = []; + for (var assetId in vm.assets.selections) { + tasks.push(assetService.assignAssetToEdge(edgeId, assetId)); + } + $q.all(tasks).then(function () { + $mdDialog.hide(); + }); + } + + function noData() { + return vm.assets.data.length == 0 && !vm.assets.hasNext; + } + + function hasData() { + return vm.assets.data.length > 0; + } + + function toggleAssetSelection($event, asset) { + $event.stopPropagation(); + var selected = angular.isDefined(asset.selected) && asset.selected; + asset.selected = !selected; + if (asset.selected) { + vm.assets.selections[asset.id.id] = true; + vm.assets.selectedCount++; + } else { + delete vm.assets.selections[asset.id.id]; + vm.assets.selectedCount--; + } + } + + function searchAssetTextUpdated() { + vm.assets = { + pageSize: vm.assets.pageSize, + data: [], + nextPageLink: { + limit: vm.assets.pageSize, + textSearch: vm.searchText + }, + selections: {}, + selectedCount: 0, + hasNext: true, + pending: false + }; + } + +} diff --git a/ui/src/app/asset/add-assets-to-edge.tpl.html b/ui/src/app/asset/add-assets-to-edge.tpl.html new file mode 100644 index 0000000000..eb564de75e --- /dev/null +++ b/ui/src/app/asset/add-assets-to-edge.tpl.html @@ -0,0 +1,77 @@ + + +
+ +
+

asset.assign-asset-to-edge

+ + + + +
+
+ + + +
+
+ asset.assign-asset-to-edge-text + + + + search + + + +
+ asset.no-assets-text + + + + + {{ asset.name }} + + + +
+
+
+
+ + + + {{ 'action.assign' | translate }} + + {{ 'action.cancel' | + translate }} + + +
+
\ No newline at end of file diff --git a/ui/src/app/asset/asset.controller.js b/ui/src/app/asset/asset.controller.js index 27d68f0878..fbec7f2586 100644 --- a/ui/src/app/asset/asset.controller.js +++ b/ui/src/app/asset/asset.controller.js @@ -19,6 +19,8 @@ import addAssetTemplate from './add-asset.tpl.html'; import assetCard from './asset-card.tpl.html'; import assignToCustomerTemplate from './assign-to-customer.tpl.html'; import addAssetsToCustomerTemplate from './add-assets-to-customer.tpl.html'; +import assignToEdgeTemplate from './assign-to-edge.tpl.html'; +import addAssetsToEdgeTemplate from './add-assets-to-edge.tpl.html'; /* eslint-enable import/no-unresolved, import/default */ @@ -47,10 +49,11 @@ export function AssetCardController(types) { /*@ngInject*/ -export function AssetController($rootScope, userService, assetService, customerService, $state, $stateParams, +export function AssetController($rootScope, userService, assetService, customerService, edgeService, $state, $stateParams, $document, $mdDialog, $q, $translate, types, importExport) { var customerId = $stateParams.customerId; + var edgeId = $stateParams.edgeId; var assetActionsList = []; @@ -216,6 +219,32 @@ export function AssetController($rootScope, userService, assetService, customerS } }); + assetActionsList.push({ + onAction: function ($event, item) { + assignToEdge($event, [ item.id.id ]); + }, + name: function() { return $translate.instant('action.assign') }, + details: function() { return $translate.instant('asset.assign-to-edge') }, + icon: "wifi_tethering", + isEnabled: function(asset) { + return asset && (!asset.edgeId || asset.edgeId.id === types.id.nullUid); + } + } + ); + + assetActionsList.push({ + onAction: function ($event, item) { + unassignFromEdge($event, item, false); + }, + name: function() { return $translate.instant('action.unassign') }, + details: function() { return $translate.instant('asset.unassign-from-edge') }, + icon: "portable_wifi_off", + isEnabled: function(asset) { + return asset && asset.edgeId && asset.edgeId.id !== types.id.nullUid; + } + } + ); + assetActionsList.push( { onAction: function ($event, item) { @@ -240,6 +269,19 @@ export function AssetController($rootScope, userService, assetService, customerS } ); + assetGroupActionsList.push( + { + onAction: function ($event, items) { + assignAssetsToEdge($event, items); + }, + name: function() { return $translate.instant('asset.assign-assets') }, + details: function(selectedCount) { + return $translate.instant('asset.assign-assets-text', {count: selectedCount}, "messageformat"); + }, + icon: "wifi_tethering" + } + ); + assetGroupActionsList.push( { onAction: function ($event) { @@ -320,6 +362,51 @@ export function AssetController($rootScope, userService, assetService, customerS } vm.assetGridConfig.addItemActions = []; + } else if (vm.assetsScope === 'edge') { + fetchAssetsFunction = function (pageLink, assetType) { + return assetService.getEdgeAssets(edgeId, pageLink, null, assetType); + }; + deleteAssetFunction = function (assetId) { + return assetService.unassignAssetFromEdge(assetId); + }; + refreshAssetsParamsFunction = function () { + return {"edgeId": edgeId, "topIndex": vm.topIndex}; + }; + + assetActionsList.push( + { + onAction: function ($event, item) { + unassignFromEdge($event, item, false); + }, + name: function() { return $translate.instant('action.unassign') }, + details: function() { return $translate.instant('asset.unassign-from-edge') }, + icon: "assignment_return" + } + ); + + assetGroupActionsList.push( + { + onAction: function ($event, items) { + unassignAssetsFromEdge($event, items); + }, + name: function() { return $translate.instant('asset.unassign-assets') }, + details: function(selectedCount) { + return $translate.instant('asset.unassign-assets-action-title', {count: selectedCount}, "messageformat"); + }, + icon: "assignment_return" + } + ); + + vm.assetGridConfig.addItemAction = { + onAction: function ($event) { + addAssetsToEdge($event); + }, + name: function() { return $translate.instant('asset.assign-assets') }, + details: function() { return $translate.instant('asset.assign-new-asset') }, + icon: "add" + }; + vm.assetGridConfig.addItemActions = []; + } vm.assetGridConfig.refreshParamsFunc = refreshAssetsParamsFunction; @@ -531,4 +618,124 @@ export function AssetController($rootScope, userService, assetService, customerS }); }); } + + function assignToEdge($event, assetIds) { + if ($event) { + $event.stopPropagation(); + } + var pageSize = 10; + edgeService.getEdges({limit: pageSize, textSearch: ''}).then( + function success(_edges) { + var edges = { + pageSize: pageSize, + data: _edges.data, + nextPageLink: _edges.nextPageLink, + selection: null, + hasNext: _edges.hasNext, + pending: false + }; + if (edges.hasNext) { + edges.nextPageLink.limit = pageSize; + } + $mdDialog.show({ + controller: 'AssignAssetToEdgeController', + controllerAs: 'vm', + templateUrl: assignToEdgeTemplate, + locals: {assetIds: assetIds, edges: edges}, + parent: angular.element($document[0].body), + fullscreen: true, + targetEvent: $event + }).then(function () { + vm.grid.refreshList(); + }, function () { + }); + }, + function fail() { + }); + } + + function addAssetsToEdge($event) { + if ($event) { + $event.stopPropagation(); + } + var pageSize = 10; + assetService.getTenantAssets({limit: pageSize, textSearch: ''}, false).then( + function success(_assets) { + var assets = { + pageSize: pageSize, + data: _assets.data, + nextPageLink: _assets.nextPageLink, + selections: {}, + selectedCount: 0, + hasNext: _assets.hasNext, + pending: false + }; + if (assets.hasNext) { + assets.nextPageLink.limit = pageSize; + } + $mdDialog.show({ + controller: 'AddAssetsToEdgeController', + controllerAs: 'vm', + templateUrl: addAssetsToEdgeTemplate, + locals: {edgeId: edgeId, assets: assets}, + parent: angular.element($document[0].body), + fullscreen: true, + targetEvent: $event + }).then(function () { + vm.grid.refreshList(); + }, function () { + }); + }, + function fail() { + }); + } + + function assignAssetsToEdge($event, items) { + var assetIds = []; + for (var id in items.selections) { + assetIds.push(id); + } + assignToEdge($event, assetIds); + } + + function unassignFromEdge($event, asset) { + if ($event) { + $event.stopPropagation(); + } + var title = $translate.instant('asset.unassign-asset-from-edge-title', {assetName: asset.name}); + var content = $translate.instant('asset.unassign-asset-from-edge-text'); + var label = $translate.instant('asset.unassign-asset'); + var confirm = $mdDialog.confirm() + .targetEvent($event) + .title(title) + .htmlContent(content) + .ariaLabel(label) + .cancel($translate.instant('action.no')) + .ok($translate.instant('action.yes')); + $mdDialog.show(confirm).then(function () { + assetService.unassignAssetFromEdge(asset.id.id).then(function success() { + vm.grid.refreshList(); + }); + }); + } + + function unassignAssetsFromEdge($event, items) { + var confirm = $mdDialog.confirm() + .targetEvent($event) + .title($translate.instant('asset.unassign-assets-title', {count: items.selectedCount}, 'messageformat')) + .htmlContent($translate.instant('asset.unassign-assets-text')) + .ariaLabel($translate.instant('asset.unassign-asset')) + .cancel($translate.instant('action.no')) + .ok($translate.instant('action.yes')); + $mdDialog.show(confirm).then(function () { + var tasks = []; + for (var id in items.selections) { + tasks.push(assetService.unassignAssetFromEdge(id)); + } + $q.all(tasks).then(function () { + vm.grid.refreshList(); + }); + }); + } + } diff --git a/ui/src/app/asset/asset.routes.js b/ui/src/app/asset/asset.routes.js index 7dfe4c496a..2659b9fa99 100644 --- a/ui/src/app/asset/asset.routes.js +++ b/ui/src/app/asset/asset.routes.js @@ -67,6 +67,29 @@ export default function AssetRoutes($stateProvider, types) { ncyBreadcrumb: { label: '{"icon": "domain", "label": "{{ vm.customerAssetsTitle }}", "translate": "false"}' } + }) + .state('home.edges.assets', { + url: '/:edgeId/assets', + params: {'topIndex': 0}, + module: 'private', + auth: ['TENANT_ADMIN'], + views: { + "content@home": { + templateUrl: assetsTemplate, + controllerAs: 'vm', + controller: 'AssetController' + } + }, + data: { + assetsType: 'edge', + searchEnabled: true, + searchByEntitySubtype: true, + searchEntityType: types.entityType.asset, + pageTitle: 'edge.assets' + }, + ncyBreadcrumb: { + label: '{"icon": "domain", "label": "edge.assets"}' + } }); } diff --git a/ui/src/app/asset/assign-to-edge.controller.js b/ui/src/app/asset/assign-to-edge.controller.js new file mode 100644 index 0000000000..798a615eae --- /dev/null +++ b/ui/src/app/asset/assign-to-edge.controller.js @@ -0,0 +1,123 @@ +/* + * Copyright © 2016-2019 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*@ngInject*/ +export default function AssignAssetToEdgeController(edgeService, assetService, $mdDialog, $q, assetIds, edges) { + + var vm = this; + + vm.edges = edges; + vm.searchText = ''; + + vm.assign = assign; + vm.cancel = cancel; + vm.isEdgeSelected = isEdgeSelected; + vm.hasData = hasData; + vm.noData = noData; + vm.searchEdgeTextUpdated = searchEdgeTextUpdated; + vm.toggleEdgeSelection = toggleEdgeSelection; + + vm.theEdges = { + getItemAtIndex: function (index) { + if (index > vm.edges.data.length) { + vm.theEdges.fetchMoreItems_(index); + return null; + } + var item = vm.edges.data[index]; + if (item) { + item.indexNumber = index + 1; + } + return item; + }, + + getLength: function () { + if (vm.edges.hasNext) { + return vm.edges.data.length + vm.edges.nextPageLink.limit; + } else { + return vm.edges.data.length; + } + }, + + fetchMoreItems_: function () { + if (vm.edges.hasNext && !vm.edges.pending) { + vm.edges.pending = true; + edgeService.getEdges(vm.edges.nextPageLink).then( + function success(edges) { + vm.edges.data = vm.edges.data.concat(edges.data); + vm.edges.nextPageLink = edges.nextPageLink; + vm.edges.hasNext = edges.hasNext; + if (vm.edges.hasNext) { + vm.edges.nextPageLink.limit = vm.edges.pageSize; + } + vm.edges.pending = false; + }, + function fail() { + vm.edges.hasNext = false; + vm.edges.pending = false; + }); + } + } + }; + + function cancel() { + $mdDialog.cancel(); + } + + function assign() { + var tasks = []; + for (var i=0;i 0; + } + + function toggleEdgeSelection($event, edge) { + $event.stopPropagation(); + if (vm.isEdgeSelected(edge)) { + vm.edges.selection = null; + } else { + vm.edges.selection = edge; + } + } + + function isEdgeSelected(edge) { + return vm.edges.selection != null && edge && + edge.id.id === vm.edges.selection.id.id; + } + + function searchEdgeTextUpdated() { + vm.edges = { + pageSize: vm.edges.pageSize, + data: [], + nextPageLink: { + limit: vm.edges.pageSize, + textSearch: vm.searchText + }, + selection: null, + hasNext: true, + pending: false + }; + } +} diff --git a/ui/src/app/asset/assign-to-edge.tpl.html b/ui/src/app/asset/assign-to-edge.tpl.html new file mode 100644 index 0000000000..51fb07a225 --- /dev/null +++ b/ui/src/app/asset/assign-to-edge.tpl.html @@ -0,0 +1,76 @@ + + +
+ +
+

asset.assign-asset-to-edge

+ + + + +
+
+ + + +
+
+ asset.assign-to-edge-text + + + + search + + + +
+ edge.no-edges-text + + + + + {{ edge.name }} + + + +
+
+
+
+ + + + {{ 'action.assign' | translate }} + + {{ 'action.cancel' | + translate }} + + +
+
\ No newline at end of file diff --git a/ui/src/app/asset/index.js b/ui/src/app/asset/index.js index 716722fa4f..b0bb84ad25 100644 --- a/ui/src/app/asset/index.js +++ b/ui/src/app/asset/index.js @@ -24,6 +24,8 @@ import {AssetController, AssetCardController} from './asset.controller'; import AssignAssetToCustomerController from './assign-to-customer.controller'; import AddAssetsToCustomerController from './add-assets-to-customer.controller'; import AssetDirective from './asset.directive'; +import AssignAssetToEdgeController from './assign-to-edge.controller'; +import AddAssetsToEdgeController from './add-assets-to-edge.controller'; export default angular.module('thingsboard.asset', [ uiRouter, @@ -37,5 +39,7 @@ export default angular.module('thingsboard.asset', [ .controller('AssetCardController', AssetCardController) .controller('AssignAssetToCustomerController', AssignAssetToCustomerController) .controller('AddAssetsToCustomerController', AddAssetsToCustomerController) + .controller('AssignAssetToEdgeController', AssignAssetToEdgeController) + .controller('AddAssetsToEdgeController', AddAssetsToEdgeController) .directive('tbAsset', AssetDirective) .name; diff --git a/ui/src/app/device/add-devices-to-edge.controller.js b/ui/src/app/device/add-devices-to-edge.controller.js new file mode 100644 index 0000000000..34483d6182 --- /dev/null +++ b/ui/src/app/device/add-devices-to-edge.controller.js @@ -0,0 +1,123 @@ +/* + * Copyright © 2016-2019 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*@ngInject*/ +export default function AddDevicesToEdgeController(deviceService, $mdDialog, $q, edgeId, devices) { + + var vm = this; + + vm.devices = devices; + vm.searchText = ''; + + vm.assign = assign; + vm.cancel = cancel; + vm.hasData = hasData; + vm.noData = noData; + vm.searchDeviceTextUpdated = searchDeviceTextUpdated; + vm.toggleDeviceSelection = toggleDeviceSelection; + + vm.theDevices = { + getItemAtIndex: function (index) { + if (index > vm.devices.data.length) { + vm.theDevices.fetchMoreItems_(index); + return null; + } + var item = vm.devices.data[index]; + if (item) { + item.indexNumber = index + 1; + } + return item; + }, + + getLength: function () { + if (vm.devices.hasNext) { + return vm.devices.data.length + vm.devices.nextPageLink.limit; + } else { + return vm.devices.data.length; + } + }, + + fetchMoreItems_: function () { + if (vm.devices.hasNext && !vm.devices.pending) { + vm.devices.pending = true; + deviceService.getTenantDevices(vm.devices.nextPageLink, false).then( + function success(devices) { + vm.devices.data = vm.devices.data.concat(devices.data); + vm.devices.nextPageLink = devices.nextPageLink; + vm.devices.hasNext = devices.hasNext; + if (vm.devices.hasNext) { + vm.devices.nextPageLink.limit = vm.devices.pageSize; + } + vm.devices.pending = false; + }, + function fail() { + vm.devices.hasNext = false; + vm.devices.pending = false; + }); + } + } + }; + + function cancel () { + $mdDialog.cancel(); + } + + function assign() { + var tasks = []; + for (var deviceId in vm.devices.selections) { + tasks.push(deviceService.assignDeviceToEdge(edgeId, deviceId)); + } + $q.all(tasks).then(function () { + $mdDialog.hide(); + }); + } + + function noData() { + return vm.devices.data.length == 0 && !vm.devices.hasNext; + } + + function hasData() { + return vm.devices.data.length > 0; + } + + function toggleDeviceSelection($event, device) { + $event.stopPropagation(); + var selected = angular.isDefined(device.selected) && device.selected; + device.selected = !selected; + if (device.selected) { + vm.devices.selections[device.id.id] = true; + vm.devices.selectedCount++; + } else { + delete vm.devices.selections[device.id.id]; + vm.devices.selectedCount--; + } + } + + function searchDeviceTextUpdated() { + vm.devices = { + pageSize: vm.devices.pageSize, + data: [], + nextPageLink: { + limit: vm.devices.pageSize, + textSearch: vm.searchText + }, + selections: {}, + selectedCount: 0, + hasNext: true, + pending: false + }; + } + +} diff --git a/ui/src/app/device/add-devices-to-edge.tpl.html b/ui/src/app/device/add-devices-to-edge.tpl.html new file mode 100644 index 0000000000..2c4dec06c9 --- /dev/null +++ b/ui/src/app/device/add-devices-to-edge.tpl.html @@ -0,0 +1,77 @@ + + +
+ +
+

device.assign-device-to-edge

+ + + + +
+
+ + + +
+
+ device.assign-device-to-edge-text + + + + search + + + +
+ device.no-devices-text + + + + + {{ device.name }} + + + +
+
+
+
+ + + + {{ 'action.assign' | translate }} + + {{ 'action.cancel' | + translate }} + + +
+
\ No newline at end of file diff --git a/ui/src/app/device/assign-to-edge.controller.js b/ui/src/app/device/assign-to-edge.controller.js new file mode 100644 index 0000000000..4c4242c795 --- /dev/null +++ b/ui/src/app/device/assign-to-edge.controller.js @@ -0,0 +1,123 @@ +/* + * Copyright © 2016-2019 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*@ngInject*/ +export default function AssignDeviceToEdgeController(edgeService, deviceService, $mdDialog, $q, deviceIds, edges) { + + var vm = this; + + vm.edges = edges; + vm.searchText = ''; + + vm.assign = assign; + vm.cancel = cancel; + vm.isEdgeSelected = isEdgeSelected; + vm.hasData = hasData; + vm.noData = noData; + vm.searchEdgeTextUpdated = searchEdgeTextUpdated; + vm.toggleEdgeSelection = toggleEdgeSelection; + + vm.theEdges = { + getItemAtIndex: function (index) { + if (index > vm.edges.data.length) { + vm.theEdges.fetchMoreItems_(index); + return null; + } + var item = vm.edges.data[index]; + if (item) { + item.indexNumber = index + 1; + } + return item; + }, + + getLength: function () { + if (vm.edges.hasNext) { + return vm.edges.data.length + vm.edges.nextPageLink.limit; + } else { + return vm.edges.data.length; + } + }, + + fetchMoreItems_: function () { + if (vm.edges.hasNext && !vm.edges.pending) { + vm.edges.pending = true; + edgeService.getEdges(vm.edges.nextPageLink).then( + function success(edges) { + vm.edges.data = vm.edges.data.concat(edges.data); + vm.edges.nextPageLink = edges.nextPageLink; + vm.edges.hasNext = edges.hasNext; + if (vm.edges.hasNext) { + vm.edges.nextPageLink.limit = vm.edges.pageSize; + } + vm.edges.pending = false; + }, + function fail() { + vm.edges.hasNext = false; + vm.edges.pending = false; + }); + } + } + }; + + function cancel() { + $mdDialog.cancel(); + } + + function assign() { + var tasks = []; + for (var i=0;i 0; + } + + function toggleEdgeSelection($event, edge) { + $event.stopPropagation(); + if (vm.isEdgeSelected(edge)) { + vm.edges.selection = null; + } else { + vm.edges.selection = edge; + } + } + + function isEdgeSelected(edge) { + return vm.edges.selection != null && edge && + edge.id.id === vm.edges.selection.id.id; + } + + function searchEdgeTextUpdated() { + vm.edges = { + pageSize: vm.edges.pageSize, + data: [], + nextPageLink: { + limit: vm.edges.pageSize, + textSearch: vm.searchText + }, + selection: null, + hasNext: true, + pending: false + }; + } +} diff --git a/ui/src/app/device/assign-to-edge.tpl.html b/ui/src/app/device/assign-to-edge.tpl.html new file mode 100644 index 0000000000..e7700ff683 --- /dev/null +++ b/ui/src/app/device/assign-to-edge.tpl.html @@ -0,0 +1,76 @@ + + +
+ +
+

device.assign-device-to-edge

+ + + + +
+
+ + + +
+
+ device.assign-to-edge-text + + + + search + + + +
+ edge.no-edges-text + + + + + {{ edge.name }} + + + +
+
+
+
+ + + + {{ 'action.assign' | translate }} + + {{ 'action.cancel' | + translate }} + + +
+
\ No newline at end of file diff --git a/ui/src/app/device/device.controller.js b/ui/src/app/device/device.controller.js index e015ef098d..a4f1a46fb0 100644 --- a/ui/src/app/device/device.controller.js +++ b/ui/src/app/device/device.controller.js @@ -20,6 +20,8 @@ import deviceCard from './device-card.tpl.html'; import assignToCustomerTemplate from './assign-to-customer.tpl.html'; import addDevicesToCustomerTemplate from './add-devices-to-customer.tpl.html'; import deviceCredentialsTemplate from './device-credentials.tpl.html'; +import assignToEdgeTemplate from './assign-to-edge.tpl.html'; +import addDevicesToEdgeTemplate from './add-devices-to-edge.tpl.html'; /* eslint-enable import/no-unresolved, import/default */ @@ -48,10 +50,11 @@ export function DeviceCardController(types) { /*@ngInject*/ -export function DeviceController($rootScope, userService, deviceService, customerService, $state, $stateParams, +export function DeviceController($rootScope, userService, deviceService, customerService, edgeService, $state, $stateParams, $document, $mdDialog, $q, $translate, types, importExport) { var customerId = $stateParams.customerId; + var edgeId = $stateParams.edgeId; var deviceActionsList = []; @@ -217,6 +220,35 @@ export function DeviceController($rootScope, userService, deviceService, custome } }); + + deviceActionsList.push( + { + onAction: function ($event, item) { + assignToEdge($event, [ item.id.id ]); + }, + name: function() { return $translate.instant('action.assign') }, + details: function() { return $translate.instant('device.assign-to-edge') }, + icon: "wifi_tethering", + isEnabled: function(device) { + return device && (!device.edgeId || device.edgeId.id === types.id.nullUid); + } + } + ); + + deviceActionsList.push( + { + onAction: function ($event, item) { + unassignFromEdge($event, item, false); + }, + name: function() { return $translate.instant('action.unassign') }, + details: function() { return $translate.instant('device.unassign-from-edge') }, + icon: "portable_wifi_off", + isEnabled: function(device) { + return device && device.edgeId && device.edgeId.id !== types.id.nullUid; + } + } + ); + deviceActionsList.push( { onAction: function ($event, item) { @@ -252,6 +284,20 @@ export function DeviceController($rootScope, userService, deviceService, custome } ); + deviceGroupActionsList.push( + { + onAction: function ($event, items) { + assignDevicesToEdge($event, items); + }, + name: function() { return $translate.instant('device.assign-devices') }, + details: function(selectedCount) { + return $translate.instant('device.assign-devices-text', {count: selectedCount}, "messageformat"); + }, + icon: "wifi_tethering" + } + ); + + deviceGroupActionsList.push( { onAction: function ($event) { @@ -353,6 +399,50 @@ export function DeviceController($rootScope, userService, deviceService, custome } vm.deviceGridConfig.addItemActions = []; + } else if (vm.devicesScope === 'edge') { + fetchDevicesFunction = function (pageLink, deviceType) { + return deviceService.getEdgeDevices(edgeId, pageLink, null, deviceType); + }; + deleteDeviceFunction = function (deviceId) { + return deviceService.unassignDeviceFromEdge(deviceId); + }; + refreshDevicesParamsFunction = function () { + return {"edgeId": edgeId, "topIndex": vm.topIndex}; + }; + + deviceActionsList.push( + { + onAction: function ($event, item) { + unassignFromEdge($event, item, false); + }, + name: function() { return $translate.instant('action.unassign') }, + details: function() { return $translate.instant('device.unassign-from-edge') }, + icon: "assignment_return" + } + ); + + deviceGroupActionsList.push( + { + onAction: function ($event, items) { + unassignDevicesFromEdge($event, items); + }, + name: function() { return $translate.instant('device.unassign-devices') }, + details: function(selectedCount) { + return $translate.instant('device.unassign-devices-action-title', {count: selectedCount}, "messageformat"); + }, + icon: "assignment_return" + } + ); + + vm.deviceGridConfig.addItemAction = { + onAction: function ($event) { + addDevicesToEdge($event); + }, + name: function() { return $translate.instant('device.assign-devices') }, + details: function() { return $translate.instant('device.assign-new-device') }, + icon: "add" + }; + vm.deviceGridConfig.addItemActions = []; } vm.deviceGridConfig.refreshParamsFunc = refreshDevicesParamsFunction; @@ -581,4 +671,123 @@ export function DeviceController($rootScope, userService, deviceService, custome }, function () { }); } + + function assignToEdge($event, deviceIds) { + if ($event) { + $event.stopPropagation(); + } + var pageSize = 10; + edgeService.getEdges({limit: pageSize, textSearch: ''}).then( + function success(_edges) { + var edges = { + pageSize: pageSize, + data: _edges.data, + nextPageLink: _edges.nextPageLink, + selection: null, + hasNext: _edges.hasNext, + pending: false + }; + if (edges.hasNext) { + edges.nextPageLink.limit = pageSize; + } + $mdDialog.show({ + controller: 'AssignDeviceToEdgeController', + controllerAs: 'vm', + templateUrl: assignToEdgeTemplate, + locals: {deviceIds: deviceIds, edges: edges}, + parent: angular.element($document[0].body), + fullscreen: true, + targetEvent: $event + }).then(function () { + vm.grid.refreshList(); + }, function () { + }); + }, + function fail() { + }); + } + + function addDevicesToEdge($event) { + if ($event) { + $event.stopPropagation(); + } + var pageSize = 10; + deviceService.getTenantDevices({limit: pageSize, textSearch: ''}, false).then( + function success(_devices) { + var devices = { + pageSize: pageSize, + data: _devices.data, + nextPageLink: _devices.nextPageLink, + selections: {}, + selectedCount: 0, + hasNext: _devices.hasNext, + pending: false + }; + if (devices.hasNext) { + devices.nextPageLink.limit = pageSize; + } + $mdDialog.show({ + controller: 'AddDevicesToEdgeController', + controllerAs: 'vm', + templateUrl: addDevicesToEdgeTemplate, + locals: {edgeId: edgeId, devices: devices}, + parent: angular.element($document[0].body), + fullscreen: true, + targetEvent: $event + }).then(function () { + vm.grid.refreshList(); + }, function () { + }); + }, + function fail() { + }); + } + + function assignDevicesToEdge($event, items) { + var deviceIds = []; + for (var id in items.selections) { + deviceIds.push(id); + } + assignToEdge($event, deviceIds); + } + + function unassignFromEdge($event, device) { + if ($event) { + $event.stopPropagation(); + } + var title = $translate.instant('device.unassign-device-from-edge-title', {deviceName: device.name}); + var content = $translate.instant('device.unassign-device-from-edge-text'); + var label = $translate.instant('device.unassign-device'); + var confirm = $mdDialog.confirm() + .targetEvent($event) + .title(title) + .htmlContent(content) + .ariaLabel(label) + .cancel($translate.instant('action.no')) + .ok($translate.instant('action.yes')); + $mdDialog.show(confirm).then(function () { + deviceService.unassignDeviceFromEdge(device.id.id).then(function success() { + vm.grid.refreshList(); + }); + }); + } + + function unassignDevicesFromEdge($event, items) { + var confirm = $mdDialog.confirm() + .targetEvent($event) + .title($translate.instant('device.unassign-devices-title', {count: items.selectedCount}, 'messageformat')) + .htmlContent($translate.instant('device.unassign-devices-text')) + .ariaLabel($translate.instant('device.unassign-device')) + .cancel($translate.instant('action.no')) + .ok($translate.instant('action.yes')); + $mdDialog.show(confirm).then(function () { + var tasks = []; + for (var id in items.selections) { + tasks.push(deviceService.unassignDeviceFromEdge(id)); + } + $q.all(tasks).then(function () { + vm.grid.refreshList(); + }); + }); + } } diff --git a/ui/src/app/device/device.routes.js b/ui/src/app/device/device.routes.js index 6100263b5e..9249283f59 100644 --- a/ui/src/app/device/device.routes.js +++ b/ui/src/app/device/device.routes.js @@ -67,6 +67,29 @@ export default function DeviceRoutes($stateProvider, types) { ncyBreadcrumb: { label: '{"icon": "devices_other", "label": "{{ vm.customerDevicesTitle }}", "translate": "false"}' } + }) + .state('home.edges.devices', { + url: '/:edgeId/devices', + params: {'topIndex': 0}, + module: 'private', + auth: ['TENANT_ADMIN'], + views: { + "content@home": { + templateUrl: devicesTemplate, + controllerAs: 'vm', + controller: 'DeviceController' + } + }, + data: { + devicesType: 'edge', + searchEnabled: true, + searchByEntitySubtype: true, + searchEntityType: types.entityType.device, + pageTitle: 'edge.devices' + }, + ncyBreadcrumb: { + label: '{"icon": "devices_other", "label": "edge.devices"}' + } }); } diff --git a/ui/src/app/device/index.js b/ui/src/app/device/index.js index 952db4efdf..95980d70ca 100644 --- a/ui/src/app/device/index.js +++ b/ui/src/app/device/index.js @@ -25,6 +25,8 @@ import AssignDeviceToCustomerController from './assign-to-customer.controller'; import AddDevicesToCustomerController from './add-devices-to-customer.controller'; import ManageDeviceCredentialsController from './device-credentials.controller'; import DeviceDirective from './device.directive'; +import AssignDeviceToEdgeController from './assign-to-edge.controller'; +import AddDevicesToEdgeController from './add-devices-to-edge.controller'; export default angular.module('thingsboard.device', [ uiRouter, @@ -39,5 +41,7 @@ export default angular.module('thingsboard.device', [ .controller('AssignDeviceToCustomerController', AssignDeviceToCustomerController) .controller('AddDevicesToCustomerController', AddDevicesToCustomerController) .controller('ManageDeviceCredentialsController', ManageDeviceCredentialsController) + .controller('AssignDeviceToEdgeController', AssignDeviceToEdgeController) + .controller('AddDevicesToEdgeController', AddDevicesToEdgeController) .directive('tbDevice', DeviceDirective) .name; diff --git a/ui/src/app/edge/edge.controller.js b/ui/src/app/edge/edge.controller.js index 6c200aebb6..d215144af3 100644 --- a/ui/src/app/edge/edge.controller.js +++ b/ui/src/app/edge/edge.controller.js @@ -216,6 +216,45 @@ export function EdgeController($rootScope, userService, edgeService, customerSer } }); + edgeActionsList.push( + { + onAction: function ($event, item) { + openEdgeAssets($event, item); + }, + name: function() { return $translate.instant('asset.assets') }, + details: function() { + return $translate.instant('edge.manage-edge-assets'); + }, + icon: "domain" + } + ); + + edgeActionsList.push( + { + onAction: function ($event, item) { + openEdgeDevices($event, item); + }, + name: function() { return $translate.instant('device.devices') }, + details: function() { + return $translate.instant('edge.manage-edge-devices'); + }, + icon: "devices_other" + } + ); + + edgeActionsList.push( + { + onAction: function ($event, item) { + openEdgeEntityViews($event, item); + }, + name: function() { return $translate.instant('entity-view.entity-views') }, + details: function() { + return $translate.instant('edge.manage-edge-entity-views'); + }, + icon: "view_quilt" + } + ); + edgeActionsList.push( { onAction: function ($event, item) { @@ -573,4 +612,27 @@ export function EdgeController($rootScope, userService, edgeService, customerSer } $state.go('home.edges.ruleChains', {edgeId: edge.id.id}); } + + + function openEdgeAssets($event, edge) { + if ($event) { + $event.stopPropagation(); + } + $state.go('home.edges.assets', {edgeId: edge.id.id}); + } + + function openEdgeDevices($event, edge) { + if ($event) { + $event.stopPropagation(); + } + $state.go('home.edges.devices', {edgeId: edge.id.id}); + } + + function openEdgeEntityViews($event, edge) { + if ($event) { + $event.stopPropagation(); + } + $state.go('home.edges.entityViews', {edgeId: edge.id.id}); + } + } diff --git a/ui/src/app/entity-view/add-entity-views-to-edge.controller.js b/ui/src/app/entity-view/add-entity-views-to-edge.controller.js new file mode 100644 index 0000000000..b8ae15ac7e --- /dev/null +++ b/ui/src/app/entity-view/add-entity-views-to-edge.controller.js @@ -0,0 +1,123 @@ +/* + * Copyright © 2016-2019 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*@ngInject*/ +export default function AddEntityViewsToEdgeController(entityViewService, $mdDialog, $q, edgeId, entityViews) { + + var vm = this; + + vm.entityViews = entityViews; + vm.searchText = ''; + + vm.assign = assign; + vm.cancel = cancel; + vm.hasData = hasData; + vm.noData = noData; + vm.searchEntityViewTextUpdated = searchEntityViewTextUpdated; + vm.toggleEntityViewSelection = toggleEntityViewSelection; + + vm.theEntityViews = { + getItemAtIndex: function (index) { + if (index > vm.entityViews.data.length) { + vm.theEntityViews.fetchMoreItems_(index); + return null; + } + var item = vm.entityViews.data[index]; + if (item) { + item.indexNumber = index + 1; + } + return item; + }, + + getLength: function () { + if (vm.entityViews.hasNext) { + return vm.entityViews.data.length + vm.entityViews.nextPageLink.limit; + } else { + return vm.entityViews.data.length; + } + }, + + fetchMoreItems_: function () { + if (vm.entityViews.hasNext && !vm.entityViews.pending) { + vm.entityViews.pending = true; + entityViewService.getTenantEntityViews(vm.entityViews.nextPageLink, false).then( + function success(entityViews) { + vm.entityViews.data = vm.entityViews.data.concat(entityViews.data); + vm.entityViews.nextPageLink = entityViews.nextPageLink; + vm.entityViews.hasNext = entityViews.hasNext; + if (vm.entityViews.hasNext) { + vm.entityViews.nextPageLink.limit = vm.entityViews.pageSize; + } + vm.entityViews.pending = false; + }, + function fail() { + vm.entityViews.hasNext = false; + vm.entityViews.pending = false; + }); + } + } + }; + + function cancel () { + $mdDialog.cancel(); + } + + function assign() { + var tasks = []; + for (var entityViewId in vm.entityViews.selections) { + tasks.push(entityViewService.assignEntityViewToEdge(edgeId, entityViewId)); + } + $q.all(tasks).then(function () { + $mdDialog.hide(); + }); + } + + function noData() { + return vm.entityViews.data.length == 0 && !vm.entityViews.hasNext; + } + + function hasData() { + return vm.entityViews.data.length > 0; + } + + function toggleEntityViewSelection($event, entityView) { + $event.stopPropagation(); + var selected = angular.isDefined(entityView.selected) && entityView.selected; + entityView.selected = !selected; + if (entityView.selected) { + vm.entityViews.selections[entityView.id.id] = true; + vm.entityViews.selectedCount++; + } else { + delete vm.entityViews.selections[entityView.id.id]; + vm.entityViews.selectedCount--; + } + } + + function searchEntityViewTextUpdated() { + vm.entityViews = { + pageSize: vm.entityViews.pageSize, + data: [], + nextPageLink: { + limit: vm.entityViews.pageSize, + textSearch: vm.searchText + }, + selections: {}, + selectedCount: 0, + hasNext: true, + pending: false + }; + } + +} diff --git a/ui/src/app/entity-view/add-entity-views-to-edge.tpl.html b/ui/src/app/entity-view/add-entity-views-to-edge.tpl.html new file mode 100644 index 0000000000..0eb063b84d --- /dev/null +++ b/ui/src/app/entity-view/add-entity-views-to-edge.tpl.html @@ -0,0 +1,77 @@ + + +
+ +
+

entity-view.assign-entity-view-to-edge

+ + + + +
+
+ + + +
+
+ entity-view.assign-entity-view-to-edge-text + + + + search + + + +
+ entity-view.no-entity-views-text + + + + + {{ entityView.name }} + + + +
+
+
+
+ + + + {{ 'action.assign' | translate }} + + {{ 'action.cancel' | + translate }} + + +
+
\ No newline at end of file diff --git a/ui/src/app/entity-view/assign-to-edge.controller.js b/ui/src/app/entity-view/assign-to-edge.controller.js new file mode 100644 index 0000000000..b2ea5bcdb2 --- /dev/null +++ b/ui/src/app/entity-view/assign-to-edge.controller.js @@ -0,0 +1,123 @@ +/* + * Copyright © 2016-2019 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*@ngInject*/ +export default function AssignEntityViewToEdgeController(edgeService, entityViewService, $mdDialog, $q, entityViewIds, edges) { + + var vm = this; + + vm.edges = edges; + vm.searchText = ''; + + vm.assign = assign; + vm.cancel = cancel; + vm.isEdgeSelected = isEdgeSelected; + vm.hasData = hasData; + vm.noData = noData; + vm.searchEdgeTextUpdated = searchEdgeTextUpdated; + vm.toggleEdgeSelection = toggleEdgeSelection; + + vm.theEdges = { + getItemAtIndex: function (index) { + if (index > vm.edges.data.length) { + vm.theEdges.fetchMoreItems_(index); + return null; + } + var item = vm.edges.data[index]; + if (item) { + item.indexNumber = index + 1; + } + return item; + }, + + getLength: function () { + if (vm.edges.hasNext) { + return vm.edges.data.length + vm.edges.nextPageLink.limit; + } else { + return vm.edges.data.length; + } + }, + + fetchMoreItems_: function () { + if (vm.edges.hasNext && !vm.edges.pending) { + vm.edges.pending = true; + edgeService.getEdges(vm.edges.nextPageLink).then( + function success(edges) { + vm.edges.data = vm.edges.data.concat(edges.data); + vm.edges.nextPageLink = edges.nextPageLink; + vm.edges.hasNext = edges.hasNext; + if (vm.edges.hasNext) { + vm.edges.nextPageLink.limit = vm.edges.pageSize; + } + vm.edges.pending = false; + }, + function fail() { + vm.edges.hasNext = false; + vm.edges.pending = false; + }); + } + } + }; + + function cancel() { + $mdDialog.cancel(); + } + + function assign() { + var tasks = []; + for (var i=0; i < entityViewIds.length;i++) { + tasks.push(entityViewService.assignEntityViewToEdge(vm.edges.selection.id.id, entityViewIds[i])); + } + $q.all(tasks).then(function () { + $mdDialog.hide(); + }); + } + + function noData() { + return vm.edges.data.length == 0 && !vm.edges.hasNext; + } + + function hasData() { + return vm.edges.data.length > 0; + } + + function toggleEdgeSelection($event, edge) { + $event.stopPropagation(); + if (vm.isEdgeSelected(edge)) { + vm.edges.selection = null; + } else { + vm.edges.selection = edge; + } + } + + function isEdgeSelected(edge) { + return vm.edges.selection != null && edge && + edge.id.id === vm.edges.selection.id.id; + } + + function searchEdgeTextUpdated() { + vm.edges = { + pageSize: vm.edges.pageSize, + data: [], + nextPageLink: { + limit: vm.edges.pageSize, + textSearch: vm.searchText + }, + selection: null, + hasNext: true, + pending: false + }; + } +} diff --git a/ui/src/app/entity-view/assign-to-edge.tpl.html b/ui/src/app/entity-view/assign-to-edge.tpl.html new file mode 100644 index 0000000000..c3c0fcf8a9 --- /dev/null +++ b/ui/src/app/entity-view/assign-to-edge.tpl.html @@ -0,0 +1,76 @@ + + +
+ +
+

entity-view.assign-entity-view-to-edge

+ + + + +
+
+ + + +
+
+ entity-view.assign-to-edge-text + + + + search + + + +
+ edge.no-edges-text + + + + + {{ edge.name }} + + + +
+
+
+
+ + + + {{ 'action.assign' | translate }} + + {{ 'action.cancel' | + translate }} + + +
+
\ No newline at end of file diff --git a/ui/src/app/entity-view/entity-view.controller.js b/ui/src/app/entity-view/entity-view.controller.js index 1cdc35cf3d..c02b3605b1 100644 --- a/ui/src/app/entity-view/entity-view.controller.js +++ b/ui/src/app/entity-view/entity-view.controller.js @@ -19,6 +19,8 @@ import addEntityViewTemplate from './add-entity-view.tpl.html'; import entityViewCard from './entity-view-card.tpl.html'; import assignToCustomerTemplate from './assign-to-customer.tpl.html'; import addEntityViewsToCustomerTemplate from './add-entity-views-to-customer.tpl.html'; +import assignToEdgeTemplate from './assign-to-edge.tpl.html'; +import addEntityViewsToEdgeTemplate from './add-entity-views-to-edge.tpl.html'; /* eslint-enable import/no-unresolved, import/default */ @@ -47,10 +49,11 @@ export function EntityViewCardController(types) { /*@ngInject*/ -export function EntityViewController($rootScope, userService, entityViewService, customerService, $state, $stateParams, +export function EntityViewController($rootScope, userService, entityViewService, customerService, edgeService, $state, $stateParams, $document, $mdDialog, $q, $translate, types) { var customerId = $stateParams.customerId; + var edgeId = $stateParams.edgeId; var entityViewActionsList = []; @@ -192,6 +195,32 @@ export function EntityViewController($rootScope, userService, entityViewService, } }); + entityViewActionsList.push({ + onAction: function ($event, item) { + assignToEdge($event, [ item.id.id ]); + }, + name: function() { return $translate.instant('action.assign') }, + details: function() { return $translate.instant('entity-view.assign-to-edge') }, + icon: "wifi_tethering", + isEnabled: function(entityView) { + return entityView && (!entityView.edgeId || entityView.edgeId.id === types.id.nullUid); + } + } + ); + + entityViewActionsList.push({ + onAction: function ($event, item) { + unassignFromEdge($event, item, false); + }, + name: function() { return $translate.instant('action.unassign') }, + details: function() { return $translate.instant('entity-view.unassign-from-edge') }, + icon: "portable_wifi_off", + isEnabled: function(entityView) { + return entityView && entityView.edgeId && entityView.edgeId.id !== types.id.nullUid; + } + } + ); + entityViewActionsList.push( { onAction: function ($event, item) { @@ -216,6 +245,19 @@ export function EntityViewController($rootScope, userService, entityViewService, } ); + entityViewGroupActionsList.push( + { + onAction: function ($event, items) { + assignEntityViewsToEdge($event, items); + }, + name: function() { return $translate.instant('entity-view.assign-assets') }, + details: function(selectedCount) { + return $translate.instant('entity-view.assign-entity-views-text', {count: selectedCount}, "messageformat"); + }, + icon: "wifi_tethering" + } + ); + entityViewGroupActionsList.push( { onAction: function ($event) { @@ -281,6 +323,51 @@ export function EntityViewController($rootScope, userService, entityViewService, } else if (vm.entityViewsScope === 'customer_user') { vm.entityViewGridConfig.addItemAction = {}; } + } else if (vm.entityViewsScope === 'edge') { + fetchEntityViewsFunction = function (pageLink, entityViewType) { + return entityViewService.getEdgeEntityViews(edgeId, pageLink, null, entityViewType); + }; + deleteEntityViewFunction = function (entityViewId) { + return entityViewService.unassignEntityViewFromEdge(entityViewId); + }; + refreshEntityViewsParamsFunction = function () { + return {"edgeId": edgeId, "topIndex": vm.topIndex}; + }; + + entityViewActionsList.push( + { + onAction: function ($event, item) { + unassignFromEdge($event, item, false); + }, + name: function() { return $translate.instant('action.unassign') }, + details: function() { return $translate.instant('entity-view.unassign-from-edge') }, + icon: "assignment_return" + } + ); + + entityViewGroupActionsList.push( + { + onAction: function ($event, items) { + unassignEntityViewsFromEdge($event, items); + }, + name: function() { return $translate.instant('entity-view.unassign-entity-views') }, + details: function(selectedCount) { + return $translate.instant('entity-view.unassign-entity-views-action-title', {count: selectedCount}, "messageformat"); + }, + icon: "assignment_return" + } + ); + + vm.entityViewGridConfig.addItemAction = { + onAction: function ($event) { + addEntityViewsToEdge($event); + }, + name: function() { return $translate.instant('entity-view.assign-entity-views') }, + details: function() { return $translate.instant('entity-view.assign-new-entity-view') }, + icon: "add" + }; + vm.entityViewGridConfig.addItemActions = []; + } vm.entityViewGridConfig.refreshParamsFunc = refreshEntityViewsParamsFunction; @@ -492,4 +579,123 @@ export function EntityViewController($rootScope, userService, entityViewService, }); }); } + + function assignToEdge($event, entityViewIds) { + if ($event) { + $event.stopPropagation(); + } + var pageSize = 10; + edgeService.getEdges({limit: pageSize, textSearch: ''}).then( + function success(_edges) { + var edges = { + pageSize: pageSize, + data: _edges.data, + nextPageLink: _edges.nextPageLink, + selection: null, + hasNext: _edges.hasNext, + pending: false + }; + if (edges.hasNext) { + edges.nextPageLink.limit = pageSize; + } + $mdDialog.show({ + controller: 'AssignEntityViewToEdgeController', + controllerAs: 'vm', + templateUrl: assignToEdgeTemplate, + locals: {entityViewIds: entityViewIds, edges: edges}, + parent: angular.element($document[0].body), + fullscreen: true, + targetEvent: $event + }).then(function () { + vm.grid.refreshList(); + }, function () { + }); + }, + function fail() { + }); + } + + function addEntityViewsToEdge($event) { + if ($event) { + $event.stopPropagation(); + } + var pageSize = 10; + entityViewService.getTenantEntityViews({limit: pageSize, textSearch: ''}, false).then( + function success(_entityViews) { + var entityViews = { + pageSize: pageSize, + data: _entityViews.data, + nextPageLink: _entityViews.nextPageLink, + selections: {}, + selectedCount: 0, + hasNext: _entityViews.hasNext, + pending: false + }; + if (entityViews.hasNext) { + entityViews.nextPageLink.limit = pageSize; + } + $mdDialog.show({ + controller: 'AddEntityViewsToEdgeController', + controllerAs: 'vm', + templateUrl: addEntityViewsToEdgeTemplate, + locals: {edgeId: edgeId, entityViews: entityViews}, + parent: angular.element($document[0].body), + fullscreen: true, + targetEvent: $event + }).then(function () { + vm.grid.refreshList(); + }, function () { + }); + }, + function fail() { + }); + } + + function assignEntityViewsToEdge($event, items) { + var entityViewIds = []; + for (var id in items.selections) { + entityViewIds.push(id); + } + assignToEdge($event, entityViewIds); + } + + function unassignFromEdge($event, entityView) { + if ($event) { + $event.stopPropagation(); + } + var title = $translate.instant('entity-view.unassign-entity-view-from-edge-title', {entityViewName: entityView.name}); + var content = $translate.instant('entity-view.unassign-entity-view-from-edge-text'); + var label = $translate.instant('entity-view.unassign-entity-view'); + var confirm = $mdDialog.confirm() + .targetEvent($event) + .title(title) + .htmlContent(content) + .ariaLabel(label) + .cancel($translate.instant('action.no')) + .ok($translate.instant('action.yes')); + $mdDialog.show(confirm).then(function () { + entityViewService.unassignEntityViewFromEdge(entityView.id.id).then(function success() { + vm.grid.refreshList(); + }); + }); + } + + function unassignEntityViewsFromEdge($event, items) { + var confirm = $mdDialog.confirm() + .targetEvent($event) + .title($translate.instant('entity-view.unassign-entity-views-title', {count: items.selectedCount}, 'messageformat')) + .htmlContent($translate.instant('entity-view.unassign-entity-views-text')) + .ariaLabel($translate.instant('entity-view.unassign-entity-view')) + .cancel($translate.instant('action.no')) + .ok($translate.instant('action.yes')); + $mdDialog.show(confirm).then(function () { + var tasks = []; + for (var id in items.selections) { + tasks.push(entityViewService.unassignEntityViewFromEdge(id)); + } + $q.all(tasks).then(function () { + vm.grid.refreshList(); + }); + }); + } } diff --git a/ui/src/app/entity-view/entity-view.routes.js b/ui/src/app/entity-view/entity-view.routes.js index 6828cfd19b..3e9d562486 100644 --- a/ui/src/app/entity-view/entity-view.routes.js +++ b/ui/src/app/entity-view/entity-view.routes.js @@ -67,6 +67,29 @@ export default function EntityViewRoutes($stateProvider, types) { ncyBreadcrumb: { label: '{"icon": "view_quilt", "label": "{{ vm.customerEntityViewsTitle }}", "translate": "false"}' } + }) + .state('home.edges.entityViews', { + url: '/:edgeId/entityViews', + params: {'topIndex': 0}, + module: 'private', + auth: ['TENANT_ADMIN'], + views: { + "content@home": { + templateUrl: entityViewsTemplate, + controllerAs: 'vm', + controller: 'EntityViewController' + } + }, + data: { + entityViewsType: 'edge', + searchEnabled: true, + searchByEntitySubtype: true, + searchEntityType: types.entityType.entityView, + pageTitle: 'edge.entity-views' + }, + ncyBreadcrumb: { + label: '{"icon": "view_quilt", "label": "edge.entity-views"}' + } }); } diff --git a/ui/src/app/entity-view/index.js b/ui/src/app/entity-view/index.js index 79faf0a98d..6bdd334191 100644 --- a/ui/src/app/entity-view/index.js +++ b/ui/src/app/entity-view/index.js @@ -24,6 +24,8 @@ import {EntityViewController, EntityViewCardController} from './entity-view.cont import AssignEntityViewToCustomerController from './assign-to-customer.controller'; import AddEntityViewsToCustomerController from './add-entity-views-to-customer.controller'; import EntityViewDirective from './entity-view.directive'; +import AssignEntityViewToEdgeController from './assign-to-edge.controller'; +import AddEntityViewsToEdgeController from './add-entity-views-to-edge.controller'; export default angular.module('thingsboard.entityView', [ uiRouter, @@ -37,5 +39,7 @@ export default angular.module('thingsboard.entityView', [ .controller('EntityViewCardController', EntityViewCardController) .controller('AssignEntityViewToCustomerController', AssignEntityViewToCustomerController) .controller('AddEntityViewsToCustomerController', AddEntityViewsToCustomerController) + .controller('AssignEntityViewToEdgeController', AssignEntityViewToEdgeController) + .controller('AddEntityViewsToEdgeController', AddEntityViewsToEdgeController) .directive('tbEntityView', EntityViewDirective) .name; diff --git a/ui/src/app/locale/locale.constant-en_US.json b/ui/src/app/locale/locale.constant-en_US.json index f20a324129..0c4f13f239 100644 --- a/ui/src/app/locale/locale.constant-en_US.json +++ b/ui/src/app/locale/locale.constant-en_US.json @@ -271,7 +271,14 @@ "asset-required": "Asset is required", "name-starts-with": "Asset name starts with", "import": "Import assets", - "asset-file": "Asset file" + "asset-file": "Asset file", + "assign-asset-to-edge": "Assign Asset(s) To Edge", + "assign-asset-to-edge-text":"Please select the assets to assign to the edge", + "unassign-from-edge": "Unassign from edge", + "assign-to-edge": "Assign to edge", + "assign-to-edge-text": "Please select the edge to assign the asset(s)", + "unassign-asset-from-edge-title": "Are you sure you want to unassign the asset '{{assetName}}'?", + "unassign-asset-from-edge-text": "After the confirmation the asset will be unassigned and won't be accessible by the edge." }, "attribute": { "attributes": "Attributes", @@ -716,7 +723,14 @@ "device-public": "Device is public", "select-device": "Select device", "import": "Import device", - "device-file": "Device file" + "device-file": "Device file", + "assign-device-to-edge": "Assign Device(s) To Edge", + "assign-device-to-edge-text":"Please select the devices to assign to the edge", + "unassign-from-edge": "Unassign from edge", + "assign-to-edge": "Assign to edge", + "assign-to-edge-text": "Please select the edge to assign the device(s)", + "unassign-device-from-edge-title": "Are you sure you want to unassign the device '{{deviceName}}'?", + "unassign-device-from-edge-text": "After the confirmation the device will be unassigned and won't be accessible by the edge." }, "dialog": { "close": "Close dialog" @@ -783,7 +797,13 @@ "edge-key-copied-message": "Edge key has been copied to clipboard", "edge-secret": "Edge secret", "copy-edge-secret": "Copy edge secret", - "edge-secret-copied-message": "Edge secret has been copied to clipboard" + "edge-secret-copied-message": "Edge secret has been copied to clipboard", + "manage-edge-assets": "Manage edge assets", + "manage-edge-devices": "Manage edge devices", + "manage-edge-entity-views": "Manage edge entity views", + "assets": "Edge assets", + "devices": "Edge devices", + "entity-views": "Edge entity views" }, "error": { "unable-to-connect": "Unable to connect to the server! Please check your internet connection.", @@ -986,7 +1006,14 @@ "make-public-entity-view-title": "Are you sure you want to make the entity view '{{entityViewName}}' public?", "make-public-entity-view-text": "After the confirmation the entity view and all its data will be made public and accessible by others.", "make-private-entity-view-title": "Are you sure you want to make the entity view '{{entityViewName}}' private?", - "make-private-entity-view-text": "After the confirmation the entity view and all its data will be made private and won't be accessible by others." + "make-private-entity-view-text": "After the confirmation the entity view and all its data will be made private and won't be accessible by others.", + "assign-entity-view-to-edge": "Assign Entity View(s) To Edge", + "assign-entity-view-to-edge-text":"Please select the entity views to assign to the edge", + "unassign-from-edge": "Unassign from edge", + "assign-to-edge": "Assign to edge", + "assign-to-edge-text": "Please select the edge to assign the entity view(s)", + "unassign-entity-view-from-edge-title": "Are you sure you want to unassign the entity view '{{entityViewName}}'?", + "unassign-entity-view-from-edge-text": "After the confirmation the entity view will be unassigned and won't be accessible by the edge." }, "event": { "event-type": "Event type",