thingsboard-memoizeit

Details

diff --git a/application/src/main/java/org/thingsboard/server/controller/EntityRelationController.java b/application/src/main/java/org/thingsboard/server/controller/EntityRelationController.java
index 1a08d56..3ddc597 100644
--- a/application/src/main/java/org/thingsboard/server/controller/EntityRelationController.java
+++ b/application/src/main/java/org/thingsboard/server/controller/EntityRelationController.java
@@ -34,7 +34,7 @@ import java.util.List;
 @RequestMapping("/api")
 public class EntityRelationController extends BaseController {
 
-    @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
+    @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
     @RequestMapping(value = "/relation", method = RequestMethod.POST)
     @ResponseStatus(value = HttpStatus.OK)
     public void saveRelation(@RequestBody EntityRelation relation) throws ThingsboardException {
@@ -42,31 +42,33 @@ public class EntityRelationController extends BaseController {
             checkNotNull(relation);
             checkEntityId(relation.getFrom());
             checkEntityId(relation.getTo());
+            if (relation.getTypeGroup() == null) {
+                relation.setTypeGroup(RelationTypeGroup.COMMON);
+            }
             relationService.saveRelation(relation).get();
         } catch (Exception e) {
             throw handleException(e);
         }
     }
 
-    @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
+    @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
     @RequestMapping(value = "/relation", method = RequestMethod.DELETE, params = {"fromId", "fromType", "relationType", "toId", "toType"})
     @ResponseStatus(value = HttpStatus.OK)
     public void deleteRelation(@RequestParam("fromId") String strFromId,
                                @RequestParam("fromType") String strFromType,
                                @RequestParam("relationType") String strRelationType,
-                               @RequestParam("relationTypeGroup") String strRelationTypeGroup,
+                               @RequestParam(value = "relationTypeGroup", required = false) String strRelationTypeGroup,
                                @RequestParam("toId") String strToId, @RequestParam("toType") String strToType) throws ThingsboardException {
         checkParameter("fromId", strFromId);
         checkParameter("fromType", strFromType);
         checkParameter("relationType", strRelationType);
-        checkParameter("relationTypeGroup", strRelationTypeGroup);
         checkParameter("toId", strToId);
         checkParameter("toType", strToType);
         EntityId fromId = EntityIdFactory.getByTypeAndId(strFromType, strFromId);
         EntityId toId = EntityIdFactory.getByTypeAndId(strToType, strToId);
         checkEntityId(fromId);
         checkEntityId(toId);
-        RelationTypeGroup relationTypeGroup = RelationTypeGroup.valueOf(strRelationTypeGroup);
+        RelationTypeGroup relationTypeGroup = parseRelationTypeGroup(strRelationTypeGroup, RelationTypeGroup.COMMON);
         try {
             Boolean found = relationService.deleteRelation(fromId, toId, strRelationType, relationTypeGroup).get();
             if (!found) {
@@ -77,7 +79,7 @@ public class EntityRelationController extends BaseController {
         }
     }
 
-    @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
+    @PreAuthorize("hasAnyAuthority('SYS_ADMIN','TENANT_ADMIN', 'CUSTOMER_USER')")
     @RequestMapping(value = "/relations", method = RequestMethod.DELETE, params = {"id", "type"})
     @ResponseStatus(value = HttpStatus.OK)
     public void deleteRelations(@RequestParam("entityId") String strId,
@@ -93,7 +95,7 @@ public class EntityRelationController extends BaseController {
         }
     }
 
-    @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
+    @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
     @RequestMapping(value = "/relation", method = RequestMethod.GET, params = {"fromId", "fromType", "relationType", "toId", "toType"})
     @ResponseStatus(value = HttpStatus.OK)
     public void checkRelation(@RequestParam("fromId") String strFromId,
@@ -121,7 +123,7 @@ public class EntityRelationController extends BaseController {
         }
     }
 
-    @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
+    @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
     @RequestMapping(value = "/relations", method = RequestMethod.GET, params = {"fromId", "fromType"})
     @ResponseBody
     public List<EntityRelation> findByFrom(@RequestParam("fromId") String strFromId,
@@ -139,7 +141,7 @@ public class EntityRelationController extends BaseController {
         }
     }
 
-    @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
+    @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
     @RequestMapping(value = "/relations/info", method = RequestMethod.GET, params = {"fromId", "fromType"})
     @ResponseBody
     public List<EntityRelationInfo> findInfoByFrom(@RequestParam("fromId") String strFromId,
@@ -157,7 +159,7 @@ public class EntityRelationController extends BaseController {
         }
     }
 
-    @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
+    @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
     @RequestMapping(value = "/relations", method = RequestMethod.GET, params = {"fromId", "fromType", "relationType"})
     @ResponseBody
     public List<EntityRelation> findByFrom(@RequestParam("fromId") String strFromId,
@@ -177,7 +179,7 @@ public class EntityRelationController extends BaseController {
         }
     }
 
-    @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
+    @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
     @RequestMapping(value = "/relations", method = RequestMethod.GET, params = {"toId", "toType"})
     @ResponseBody
     public List<EntityRelation> findByTo(@RequestParam("toId") String strToId,
@@ -195,7 +197,25 @@ public class EntityRelationController extends BaseController {
         }
     }
 
-    @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
+    @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
+    @RequestMapping(value = "/relations/info", method = RequestMethod.GET, params = {"toId", "toType"})
+    @ResponseBody
+    public List<EntityRelationInfo> findInfoByTo(@RequestParam("toId") String strToId,
+                                                   @RequestParam("toType") String strToType,
+                                                   @RequestParam(value = "relationTypeGroup", required = false) String strRelationTypeGroup) throws ThingsboardException {
+        checkParameter("toId", strToId);
+        checkParameter("toType", strToType);
+        EntityId entityId = EntityIdFactory.getByTypeAndId(strToType, strToId);
+        checkEntityId(entityId);
+        RelationTypeGroup typeGroup = parseRelationTypeGroup(strRelationTypeGroup, RelationTypeGroup.COMMON);
+        try {
+            return checkNotNull(relationService.findInfoByTo(entityId, typeGroup).get());
+        } catch (Exception e) {
+            throw handleException(e);
+        }
+    }
+
+    @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
     @RequestMapping(value = "/relations", method = RequestMethod.GET, params = {"toId", "toType", "relationType"})
     @ResponseBody
     public List<EntityRelation> findByTo(@RequestParam("toId") String strToId,
@@ -215,7 +235,7 @@ public class EntityRelationController extends BaseController {
         }
     }
 
-    @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
+    @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
     @RequestMapping(value = "/relations", method = RequestMethod.POST)
     @ResponseBody
     public List<EntityRelation> findByQuery(@RequestBody EntityRelationsQuery query) throws ThingsboardException {
diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/relation/EntityRelationInfo.java b/common/data/src/main/java/org/thingsboard/server/common/data/relation/EntityRelationInfo.java
index 709ad79..5012691 100644
--- a/common/data/src/main/java/org/thingsboard/server/common/data/relation/EntityRelationInfo.java
+++ b/common/data/src/main/java/org/thingsboard/server/common/data/relation/EntityRelationInfo.java
@@ -20,6 +20,7 @@ public class EntityRelationInfo extends EntityRelation {
 
     private static final long serialVersionUID = 2807343097519543363L;
 
+    private String fromName;
     private String toName;
 
     public EntityRelationInfo() {
@@ -30,6 +31,14 @@ public class EntityRelationInfo extends EntityRelation {
         super(entityRelation);
     }
 
+    public String getFromName() {
+        return fromName;
+    }
+
+    public void setFromName(String fromName) {
+        this.fromName = fromName;
+    }
+
     public String getToName() {
         return toName;
     }
diff --git a/dao/src/main/java/org/thingsboard/server/dao/relation/BaseRelationService.java b/dao/src/main/java/org/thingsboard/server/dao/relation/BaseRelationService.java
index 9559cd3..36ec567 100644
--- a/dao/src/main/java/org/thingsboard/server/dao/relation/BaseRelationService.java
+++ b/dao/src/main/java/org/thingsboard/server/dao/relation/BaseRelationService.java
@@ -23,29 +23,17 @@ import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.util.StringUtils;
-import org.thingsboard.server.common.data.BaseData;
-import org.thingsboard.server.common.data.Device;
-import org.thingsboard.server.common.data.EntityType;
-import org.thingsboard.server.common.data.asset.Asset;
-import org.thingsboard.server.common.data.id.AssetId;
-import org.thingsboard.server.common.data.id.DeviceId;
 import org.thingsboard.server.common.data.id.EntityId;
-import org.thingsboard.server.common.data.id.UUIDBased;
 import org.thingsboard.server.common.data.relation.EntityRelation;
 import org.thingsboard.server.common.data.relation.EntityRelationInfo;
 import org.thingsboard.server.common.data.relation.RelationTypeGroup;
-import org.thingsboard.server.dao.asset.AssetService;
-import org.thingsboard.server.dao.customer.CustomerService;
-import org.thingsboard.server.dao.device.DeviceService;
 import org.thingsboard.server.dao.entity.EntityService;
 import org.thingsboard.server.dao.exception.DataValidationException;
-import org.thingsboard.server.dao.plugin.PluginService;
-import org.thingsboard.server.dao.rule.RuleService;
-import org.thingsboard.server.dao.tenant.TenantService;
 
 import javax.annotation.Nullable;
 import java.util.*;
 import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.BiConsumer;
 
 /**
  * Created by ashvayka on 28.04.17.
@@ -133,23 +121,16 @@ public class BaseRelationService implements RelationService {
         ListenableFuture<List<EntityRelationInfo>> relationsInfo = Futures.transform(relations,
                 (AsyncFunction<List<EntityRelation>, List<EntityRelationInfo>>) relations1 -> {
             List<ListenableFuture<EntityRelationInfo>> futures = new ArrayList<>();
-                    relations1.stream().forEach(relation -> futures.add(fetchRelationInfoAsync(relation)));
-            return Futures.successfulAsList(futures);
+                    relations1.stream().forEach(relation ->
+                            futures.add(fetchRelationInfoAsync(relation,
+                                    relation2 -> relation2.getTo(),
+                                    (EntityRelationInfo relationInfo, String entityName) -> relationInfo.setToName(entityName)))
+                    );
+                    return Futures.successfulAsList(futures);
         });
         return relationsInfo;
     }
 
-    private ListenableFuture<EntityRelationInfo> fetchRelationInfoAsync(EntityRelation relation) {
-        ListenableFuture<String> entityName = entityService.fetchEntityNameAsync(relation.getTo());
-        ListenableFuture<EntityRelationInfo> entityRelationInfo =
-                Futures.transform(entityName, (Function<String, EntityRelationInfo>) entityName1 -> {
-                            EntityRelationInfo entityRelationInfo1 = new EntityRelationInfo(relation);
-                            entityRelationInfo1.setToName(entityName1);
-                            return entityRelationInfo1;
-                        });
-        return entityRelationInfo;
-    }
-
     @Override
     public ListenableFuture<List<EntityRelation>> findByFromAndType(EntityId from, String relationType, RelationTypeGroup typeGroup) {
         log.trace("Executing findByFromAndType [{}][{}][{}]", from, relationType, typeGroup);
@@ -168,6 +149,38 @@ public class BaseRelationService implements RelationService {
     }
 
     @Override
+    public ListenableFuture<List<EntityRelationInfo>> findInfoByTo(EntityId to, RelationTypeGroup typeGroup) {
+        log.trace("Executing findInfoByTo [{}][{}]", to, typeGroup);
+        validate(to);
+        validateTypeGroup(typeGroup);
+        ListenableFuture<List<EntityRelation>> relations = relationDao.findAllByTo(to, typeGroup);
+        ListenableFuture<List<EntityRelationInfo>> relationsInfo = Futures.transform(relations,
+                (AsyncFunction<List<EntityRelation>, List<EntityRelationInfo>>) relations1 -> {
+                    List<ListenableFuture<EntityRelationInfo>> futures = new ArrayList<>();
+                    relations1.stream().forEach(relation ->
+                        futures.add(fetchRelationInfoAsync(relation,
+                                relation2 -> relation2.getFrom(),
+                                (EntityRelationInfo relationInfo, String entityName) -> relationInfo.setFromName(entityName)))
+                    );
+                    return Futures.successfulAsList(futures);
+                });
+        return relationsInfo;
+    }
+
+    private ListenableFuture<EntityRelationInfo> fetchRelationInfoAsync(EntityRelation relation,
+                                                                        Function<EntityRelation, EntityId> entityIdGetter,
+                                                                        BiConsumer<EntityRelationInfo, String> entityNameSetter) {
+        ListenableFuture<String> entityName = entityService.fetchEntityNameAsync(entityIdGetter.apply(relation));
+        ListenableFuture<EntityRelationInfo> entityRelationInfo =
+                Futures.transform(entityName, (Function<String, EntityRelationInfo>) entityName1 -> {
+                    EntityRelationInfo entityRelationInfo1 = new EntityRelationInfo(relation);
+                    entityNameSetter.accept(entityRelationInfo1, entityName1);
+                    return entityRelationInfo1;
+                });
+        return entityRelationInfo;
+    }
+
+    @Override
     public ListenableFuture<List<EntityRelation>> findByToAndType(EntityId to, String relationType, RelationTypeGroup typeGroup) {
         log.trace("Executing findByToAndType [{}][{}][{}]", to, relationType, typeGroup);
         validate(to);
diff --git a/dao/src/main/java/org/thingsboard/server/dao/relation/RelationService.java b/dao/src/main/java/org/thingsboard/server/dao/relation/RelationService.java
index 868769f..a810454 100644
--- a/dao/src/main/java/org/thingsboard/server/dao/relation/RelationService.java
+++ b/dao/src/main/java/org/thingsboard/server/dao/relation/RelationService.java
@@ -46,6 +46,8 @@ public interface RelationService {
 
     ListenableFuture<List<EntityRelation>> findByTo(EntityId to, RelationTypeGroup typeGroup);
 
+    ListenableFuture<List<EntityRelationInfo>> findInfoByTo(EntityId to, RelationTypeGroup typeGroup);
+
     ListenableFuture<List<EntityRelation>> findByToAndType(EntityId to, String relationType, RelationTypeGroup typeGroup);
 
     ListenableFuture<List<EntityRelation>> findByQuery(EntityRelationsQuery query);
diff --git a/ui/src/app/api/entity-relation.service.js b/ui/src/app/api/entity-relation.service.js
index 7039645..875b2fa 100644
--- a/ui/src/app/api/entity-relation.service.js
+++ b/ui/src/app/api/entity-relation.service.js
@@ -28,6 +28,7 @@ function EntityRelationService($http, $q) {
         findInfoByFrom: findInfoByFrom,
         findByFromAndType: findByFromAndType,
         findByTo: findByTo,
+        findInfoByTo: findInfoByTo,
         findByToAndType: findByToAndType,
         findByQuery: findByQuery
     }
@@ -122,6 +123,18 @@ function EntityRelationService($http, $q) {
         return deferred.promise;
     }
 
+    function findInfoByTo(toId, toType) {
+        var deferred = $q.defer();
+        var url = '/api/relations/info?toId=' + toId;
+        url += '&toType=' + toType;
+        $http.get(url, null).then(function success(response) {
+            deferred.resolve(response.data);
+        }, function fail() {
+            deferred.reject();
+        });
+        return deferred.promise;
+    }
+
     function findByToAndType(toId, toType, relationType) {
         var deferred = $q.defer();
         var url = '/api/relations?toId=' + toId;
diff --git a/ui/src/app/customer/customers.tpl.html b/ui/src/app/customer/customers.tpl.html
index 9221984..6c70a70 100644
--- a/ui/src/app/customer/customers.tpl.html
+++ b/ui/src/app/customer/customers.tpl.html
@@ -55,5 +55,11 @@
 							default-event-type="{{vm.types.eventType.alarm.value}}">
 			</tb-event-table>
 		</md-tab>
+		<md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode" label="{{ 'relation.relations' | translate }}">
+			<tb-relation-table flex
+							   entity-id="vm.grid.operatingItem().id.id"
+							   entity-type="{{vm.types.entityType.customer}}">
+			</tb-relation-table>
+		</md-tab>
 	</md-tabs>
 </tb-grid>
diff --git a/ui/src/app/device/devices.tpl.html b/ui/src/app/device/devices.tpl.html
index 2f90db8..3ff6c1c 100644
--- a/ui/src/app/device/devices.tpl.html
+++ b/ui/src/app/device/devices.tpl.html
@@ -56,4 +56,10 @@
                             default-event-type="{{vm.types.eventType.alarm.value}}">
             </tb-event-table>
         </md-tab>
+        <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode" label="{{ 'relation.relations' | translate }}">
+            <tb-relation-table flex
+                               entity-id="vm.grid.operatingItem().id.id"
+                               entity-type="{{vm.types.entityType.device}}">
+            </tb-relation-table>
+        </md-tab>
 </tb-grid>
diff --git a/ui/src/app/entity/entity-filter.tpl.html b/ui/src/app/entity/entity-filter.tpl.html
index cbb997e..7e49ba9 100644
--- a/ui/src/app/entity/entity-filter.tpl.html
+++ b/ui/src/app/entity/entity-filter.tpl.html
@@ -41,7 +41,7 @@
                 </md-autocomplete>
                 <md-chip-template>
                     <span>
-                      <strong>{{itemName($chip)}}</strong>
+                      <strong>{{$chip.name}}</strong>
                     </span>
                 </md-chip-template>
             </md-chips>
diff --git a/ui/src/app/entity/entity-select.tpl.html b/ui/src/app/entity/entity-select.tpl.html
index ce0a16b..13e17e7 100644
--- a/ui/src/app/entity/entity-select.tpl.html
+++ b/ui/src/app/entity/entity-select.tpl.html
@@ -17,6 +17,9 @@
 -->
 <div layout='row' class="tb-entity-select">
     <tb-entity-type-select style="min-width: 100px;"
+                           the-form="theForm"
+                           ng-disabled="disabled"
+                           tb-required="tbRequired"
                            ng-model="model.entityType">
     </tb-entity-type-select>
     <tb-entity-autocomplete flex ng-if="model.entityType"
diff --git a/ui/src/app/entity/entity-type-select.directive.js b/ui/src/app/entity/entity-type-select.directive.js
index 3a595a3..1dc6741 100644
--- a/ui/src/app/entity/entity-type-select.directive.js
+++ b/ui/src/app/entity/entity-type-select.directive.js
@@ -29,6 +29,8 @@ export default function EntityTypeSelect($compile, $templateCache, utils, userSe
         var template = $templateCache.get(entityTypeSelectTemplate);
         element.html(template);
 
+        scope.tbRequired = angular.isDefined(scope.tbRequired) ? scope.tbRequired : false;
+
         if (angular.isDefined(attrs.hideLabel)) {
             scope.showLabel = false;
         } else {
@@ -103,6 +105,9 @@ export default function EntityTypeSelect($compile, $templateCache, utils, userSe
         require: "^ngModel",
         link: linker,
         scope: {
+            theForm: '=?',
+            tbRequired: '=?',
+            disabled:'=ngDisabled',
             allowedEntityTypes: "=?"
         }
     };
diff --git a/ui/src/app/entity/entity-type-select.tpl.html b/ui/src/app/entity/entity-type-select.tpl.html
index e31cbf5..86d0eeb 100644
--- a/ui/src/app/entity/entity-type-select.tpl.html
+++ b/ui/src/app/entity/entity-type-select.tpl.html
@@ -17,9 +17,13 @@
 -->
 <md-input-container>
     <label ng-if="showLabel">{{ 'entity.type' | translate }}</label>
-    <md-select ng-model="entityType" class="tb-entity-type-select" aria-label="{{ 'entity.type' | translate }}">
+    <md-select ng-required="tbRequired" ng-disabled="disabled" name="entityType"
+               ng-model="entityType" class="tb-entity-type-select" aria-label="{{ 'entity.type' | translate }}">
         <md-option ng-repeat="type in entityTypes" ng-value="type">
             {{typeName(type) | translate}}
         </md-option>
     </md-select>
-</md-input-container>
\ No newline at end of file
+    <div ng-messages="theForm.entityType.$error">
+        <div ng-message="required" translate>entity.type-required</div>
+    </div>
+</md-input-container>
diff --git a/ui/src/app/entity/index.js b/ui/src/app/entity/index.js
index bed9562..e8cc437 100644
--- a/ui/src/app/entity/index.js
+++ b/ui/src/app/entity/index.js
@@ -27,6 +27,7 @@ import AddAttributeDialogController from './attribute/add-attribute-dialog.contr
 import AddWidgetToDashboardDialogController from './attribute/add-widget-to-dashboard-dialog.controller';
 import AttributeTableDirective from './attribute/attribute-table.directive';
 import RelationTableDirective from './relation/relation-table.directive';
+import RelationTypeAutocompleteDirective from './relation/relation-type-autocomplete.directive';
 
 export default angular.module('thingsboard.entity', [])
     .controller('EntityAliasesController', EntityAliasesController)
@@ -42,4 +43,5 @@ export default angular.module('thingsboard.entity', [])
     .directive('tbAliasesEntitySelect', AliasesEntitySelectDirective)
     .directive('tbAttributeTable', AttributeTableDirective)
     .directive('tbRelationTable', RelationTableDirective)
+    .directive('tbRelationTypeAutocomplete', RelationTypeAutocompleteDirective)
     .name;
diff --git a/ui/src/app/entity/relation/add-relation-dialog.controller.js b/ui/src/app/entity/relation/add-relation-dialog.controller.js
index c331946..e05be52 100644
--- a/ui/src/app/entity/relation/add-relation-dialog.controller.js
+++ b/ui/src/app/entity/relation/add-relation-dialog.controller.js
@@ -14,14 +14,20 @@
  * limitations under the License.
  */
 /*@ngInject*/
-export default function AddRelationDialogController($scope, $mdDialog, types, entityRelationService, from) {
+export default function AddRelationDialogController($scope, $mdDialog, types, entityRelationService, direction, entityId) {
 
     var vm = this;
 
     vm.types = types;
+    vm.direction = direction;
+    vm.targetEntityId = {};
 
     vm.relation = {};
-    vm.relation.from = from;
+    if (vm.direction == vm.types.entitySearchDirection.from) {
+        vm.relation.from = entityId;
+    } else {
+        vm.relation.to = entityId;
+    }
     vm.relation.type = types.entityRelationType.contains;
 
     vm.add = add;
@@ -32,6 +38,11 @@ export default function AddRelationDialogController($scope, $mdDialog, types, en
     }
 
     function add() {
+        if (vm.direction == vm.types.entitySearchDirection.from) {
+            vm.relation.to = vm.targetEntityId;
+        } else {
+            vm.relation.from = vm.targetEntityId;
+        }
         $scope.theForm.$setPristine();
         entityRelationService.saveRelation(vm.relation).then(
             function success() {
diff --git a/ui/src/app/entity/relation/add-relation-dialog.tpl.html b/ui/src/app/entity/relation/add-relation-dialog.tpl.html
index b32d23a..b45013b 100644
--- a/ui/src/app/entity/relation/add-relation-dialog.tpl.html
+++ b/ui/src/app/entity/relation/add-relation-dialog.tpl.html
@@ -32,19 +32,16 @@
             <div class="md-dialog-content">
                 <md-content class="md-padding" layout="column">
                     <fieldset ng-disabled="loading">
-                        <md-input-container class="md-block">
-                            <label translate>relation.relation-type</label>
-                            <md-select required ng-model="vm.relation.type" ng-disabled="loading">
-                                <md-option ng-repeat="type in vm.types.entityRelationType" ng-value="type">
-                                    <span>{{('relation.relation-types.' + type) | translate}}</span>
-                                </md-option>
-                            </md-select>
-                        </md-input-container>
-                        <span class="tb-small">{{'entity.entity' | translate }}</span>
+                        <tb-relation-type-autocomplete ng-model="vm.relation.type"
+                                                       tb-required="true"
+                                                       ng-disabled="loading">
+                        </tb-relation-type-autocomplete>
+                        <small>{{(vm.direction == vm.types.entitySearchDirection.from ?
+                            'relation.to-entity' : 'relation.from-entity') | translate}}</small>
                         <tb-entity-select flex
                             the-form="theForm"
                             tb-required="true"
-                            ng-model="vm.relation.to">
+                            ng-model="vm.targetEntityId">
                         </tb-entity-select>
                     </fieldset>
                 </md-content>
diff --git a/ui/src/app/entity/relation/relation-table.directive.js b/ui/src/app/entity/relation/relation-table.directive.js
index bf4aa52..729ff36 100644
--- a/ui/src/app/entity/relation/relation-table.directive.js
+++ b/ui/src/app/entity/relation/relation-table.directive.js
@@ -45,13 +45,17 @@ function RelationTableController($scope, $q, $mdDialog, $document, $translate, $
 
     let vm = this;
 
+    vm.types = types;
+
+    vm.direction = vm.types.entitySearchDirection.from;
+
     vm.relations = [];
     vm.relationsCount = 0;
     vm.allRelations = [];
     vm.selectedRelations = [];
 
     vm.query = {
-        order: 'typeName',
+        order: 'type',
         limit: 5,
         page: 1,
         search: null
@@ -62,19 +66,23 @@ function RelationTableController($scope, $q, $mdDialog, $document, $translate, $
     vm.onReorder = onReorder;
     vm.onPaginate = onPaginate;
     vm.addRelation = addRelation;
-    vm.editRelation = editRelation;
     vm.deleteRelation = deleteRelation;
     vm.deleteRelations = deleteRelations;
     vm.reloadRelations = reloadRelations;
     vm.updateRelations = updateRelations;
 
-
     $scope.$watch("vm.entityId", function(newVal, prevVal) {
         if (newVal && !angular.equals(newVal, prevVal)) {
             reloadRelations();
         }
     });
 
+    $scope.$watch("vm.direction", function(newVal, prevVal) {
+        if (newVal && !angular.equals(newVal, prevVal)) {
+            reloadRelations();
+        }
+    });
+
     $scope.$watch("vm.query.search", function(newVal, prevVal) {
         if (!angular.equals(newVal, prevVal) && vm.query.search != null) {
             updateRelations();
@@ -102,7 +110,7 @@ function RelationTableController($scope, $q, $mdDialog, $document, $translate, $
         if ($event) {
             $event.stopPropagation();
         }
-        var from = {
+        var entityId = {
             id: vm.entityId,
             entityType: vm.entityType
         };
@@ -111,7 +119,7 @@ function RelationTableController($scope, $q, $mdDialog, $document, $translate, $
             controllerAs: 'vm',
             templateUrl: addRelationTemplate,
             parent: angular.element($document[0].body),
-            locals: { from: from },
+            locals: { direction: vm.direction, entityId: entityId },
             fullscreen: true,
             targetEvent: $event
         }).then(function () {
@@ -120,36 +128,100 @@ function RelationTableController($scope, $q, $mdDialog, $document, $translate, $
         });
     }
 
-    function editRelation($event, /*relation*/) {
+    function deleteRelation($event, relation) {
         if ($event) {
             $event.stopPropagation();
         }
-        //TODO:
-    }
+        if (relation) {
+            var title;
+            var content;
+            if (vm.direction == vm.types.entitySearchDirection.from) {
+                title = $translate.instant('relation.delete-to-relation-title', {entityName: relation.toName});
+                content = $translate.instant('relation.delete-to-relation-text', {entityName: relation.toName});
+            } else {
+                title = $translate.instant('relation.delete-from-relation-title', {entityName: relation.fromName});
+                content = $translate.instant('relation.delete-from-relation-text', {entityName: relation.fromName});
+            }
 
-    function deleteRelation($event, /*relation*/) {
-        if ($event) {
-            $event.stopPropagation();
+            var confirm = $mdDialog.confirm()
+                .targetEvent($event)
+                .title(title)
+                .htmlContent(content)
+                .ariaLabel(title)
+                .cancel($translate.instant('action.no'))
+                .ok($translate.instant('action.yes'));
+            $mdDialog.show(confirm).then(function () {
+                entityRelationService.deleteRelation(
+                    relation.from.id,
+                    relation.from.entityType,
+                    relation.type,
+                    relation.to.id,
+                    relation.to.entityType).then(
+                    function success() {
+                        reloadRelations();
+                    }
+                );
+            });
         }
-        //TODO:
     }
 
     function deleteRelations($event) {
         if ($event) {
             $event.stopPropagation();
         }
-        //TODO:
+        if (vm.selectedRelations && vm.selectedRelations.length > 0) {
+            var title;
+            var content;
+            if (vm.direction == vm.types.entitySearchDirection.from) {
+                title = $translate.instant('relation.delete-to-relations-title', {count: vm.selectedRelations.length}, 'messageformat');
+                content = $translate.instant('relation.delete-to-relations-text');
+            } else {
+                title = $translate.instant('relation.delete-from-relations-title', {count: vm.selectedRelations.length}, 'messageformat');
+                content = $translate.instant('relation.delete-from-relations-text');
+            }
+            var confirm = $mdDialog.confirm()
+                .targetEvent($event)
+                .title(title)
+                .htmlContent(content)
+                .ariaLabel(title)
+                .cancel($translate.instant('action.no'))
+                .ok($translate.instant('action.yes'));
+            $mdDialog.show(confirm).then(function () {
+                var tasks = [];
+                for (var i=0;i<vm.selectedRelations.length;i++) {
+                    var relation = vm.selectedRelations[i];
+                    tasks.push( entityRelationService.deleteRelation(
+                        relation.from.id,
+                        relation.from.entityType,
+                        relation.type,
+                        relation.to.id,
+                        relation.to.entityType));
+                }
+                $q.all(tasks).then(function () {
+                    reloadRelations();
+                });
+
+            });
+        }
     }
 
     function reloadRelations () {
         vm.allRelations.length = 0;
         vm.relations.length = 0;
-        vm.relationsPromise = entityRelationService.findInfoByFrom(vm.entityId, vm.entityType);
+        vm.relationsPromise;
+        if (vm.direction == vm.types.entitySearchDirection.from) {
+            vm.relationsPromise = entityRelationService.findInfoByFrom(vm.entityId, vm.entityType);
+        } else {
+            vm.relationsPromise = entityRelationService.findInfoByTo(vm.entityId, vm.entityType);
+        }
         vm.relationsPromise.then(
             function success(allRelations) {
                 allRelations.forEach(function(relation) {
-                    relation.typeName = $translate.instant('relation.relation-type.' + relation.type);
-                    relation.toEntityTypeName = $translate.instant(utils.entityTypeName(relation.to.entityType));
+                    if (vm.direction == vm.types.entitySearchDirection.from) {
+                        relation.toEntityTypeName = $translate.instant(utils.entityTypeName(relation.to.entityType));
+                    } else {
+                        relation.fromEntityTypeName = $translate.instant(utils.entityTypeName(relation.from.entityType));
+                    }
                 });
                 vm.allRelations = allRelations;
                 vm.selectedRelations = [];
diff --git a/ui/src/app/entity/relation/relation-table.tpl.html b/ui/src/app/entity/relation/relation-table.tpl.html
index dc0df57..c93755b 100644
--- a/ui/src/app/entity/relation/relation-table.tpl.html
+++ b/ui/src/app/entity/relation/relation-table.tpl.html
@@ -16,11 +16,22 @@
 
 -->
 <md-content flex class="md-padding tb-absolute-fill tb-relation-table tb-data-table" layout="column">
+    <section layout="row">
+        <md-input-container class="md-block" style="width: 200px;">
+            <label translate>relation.direction</label>
+            <md-select ng-model="vm.direction" ng-disabled="loading">
+                <md-option ng-repeat="direction in vm.types.entitySearchDirection" ng-value="direction">
+                    {{ ('relation.search-direction.' + direction) | translate}}
+                </md-option>
+            </md-select>
+        </md-input-container>
+    </section>
     <div layout="column" class="md-whiteframe-z1">
         <md-toolbar class="md-table-toolbar md-default" ng-show="!vm.selectedRelations.length
                                                                  && vm.query.search === null">
             <div class="md-toolbar-tools">
-                <span translate>relation.entity-relations</span>
+                <span>{{(vm.direction == vm.types.entitySearchDirection.from ?
+                    'relation.from-relations' : 'relation.to-relations') | translate}}</span>
                 <span flex></span>
                 <md-button class="md-icon-button" ng-click="vm.addRelation($event)">
                     <md-icon>add</md-icon>
@@ -66,7 +77,7 @@
         <md-toolbar class="md-table-toolbar alternate" ng-show="vm.selectedRelations.length">
             <div class="md-toolbar-tools">
                 <span translate
-                      translate-values="{count: selectedRelations.length}"
+                      translate-values="{count: vm.selectedRelations.length}"
                       translate-interpolation="messageformat">relation.selected-relations</span>
                 <span flex></span>
                 <md-button class="md-icon-button" ng-click="vm.deleteRelations($event)">
@@ -81,25 +92,26 @@
             <table md-table md-row-select multiple="" ng-model="vm.selectedRelations" md-progress="vm.relationsDeferred.promise">
                 <thead md-head md-order="vm.query.order" md-on-reorder="vm.onReorder">
                 <tr md-row>
-                    <th md-column md-order-by="typeName"><span translate>relation.type</span></th>
-                    <th md-column md-order-by="toEntityTypeName"><span translate>relation.to-entity-type</span></th>
-                    <th md-column md-order-by="toName"><span translate>relation.to-entity-name</span></th>
+                    <th md-column md-order-by="type"><span translate>relation.type</span></th>
+                    <th md-column ng-if="vm.direction == vm.types.entitySearchDirection.from"
+                        md-order-by="toEntityTypeName"><span translate>relation.to-entity-type</span></th>
+                    <th md-column ng-if="vm.direction == vm.types.entitySearchDirection.to"
+                        md-order-by="fromEntityTypeName"><span translate>relation.from-entity-type</span></th>
+                    <th md-column ng-if="vm.direction == vm.types.entitySearchDirection.from"
+                        md-order-by="toName"><span translate>relation.to-entity-name</span></th>
+                    <th md-column ng-if="vm.direction == vm.types.entitySearchDirection.to"
+                        md-order-by="fromName"><span translate>relation.from-entity-name</span></th>
                     <th md-column><span>&nbsp</span></th>
                 </tr>
                 </thead>
                 <tbody md-body>
                 <tr md-row md-select="relation" md-select-id="relation" md-auto-select ng-repeat="relation in vm.relations">
-                    <td md-cell>{{ relation.typeName }}</td>
-                    <td md-cell>{{ relation.toEntityTypeName }}</td>
-                    <td md-cell>{{ relation.toName }}</td>
+                    <td md-cell>{{ relation.type }}</td>
+                    <td md-cell ng-if="vm.direction == vm.types.entitySearchDirection.from">{{ relation.toEntityTypeName  }}</td>
+                    <td md-cell ng-if="vm.direction == vm.types.entitySearchDirection.to">{{ relation.fromEntityTypeName  }}</td>
+                    <td md-cell ng-if="vm.direction == vm.types.entitySearchDirection.from">{{ relation.toName }}</td>
+                    <td md-cell ng-if="vm.direction == vm.types.entitySearchDirection.to">{{ relation.fromName }}</td>
                     <td md-cell class="tb-action-cell">
-                        <md-button class="md-icon-button" aria-label="{{ 'action.edit' | translate }}"
-                                   ng-click="vm.editRelation($event, relation)">
-                            <md-icon aria-label="{{ 'action.edit' | translate }}" class="material-icons">edit</md-icon>
-                            <md-tooltip md-direction="top">
-                                {{ 'relation.edit' | translate }}
-                            </md-tooltip>
-                        </md-button>
                         <md-button class="md-icon-button" aria-label="{{ 'action.delete' | translate }}" ng-click="vm.deleteRelation($event, relation)">
                             <md-icon aria-label="{{ 'action.delete' | translate }}" class="material-icons">delete</md-icon>
                             <md-tooltip md-direction="top">
diff --git a/ui/src/app/entity/relation/relation-type-autocomplete.directive.js b/ui/src/app/entity/relation/relation-type-autocomplete.directive.js
new file mode 100644
index 0000000..a7e5ea4
--- /dev/null
+++ b/ui/src/app/entity/relation/relation-type-autocomplete.directive.js
@@ -0,0 +1,86 @@
+/*
+ * Copyright © 2016-2017 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.
+ */
+import './relation-type-autocomplete.scss';
+
+/* eslint-disable import/no-unresolved, import/default */
+
+import relationTypeAutocompleteTemplate from './relation-type-autocomplete.tpl.html';
+
+/* eslint-enable import/no-unresolved, import/default */
+
+/*@ngInject*/
+export default function RelationTypeAutocomplete($compile, $templateCache, $q, $filter, assetService, deviceService, types) {
+
+    var linker = function (scope, element, attrs, ngModelCtrl) {
+        var template = $templateCache.get(relationTypeAutocompleteTemplate);
+        element.html(template);
+
+        scope.tbRequired = angular.isDefined(scope.tbRequired) ? scope.tbRequired : false;
+        scope.relationType = null;
+        scope.relationTypeSearchText = '';
+        scope.relationTypes = [];
+        for (var type in types.entityRelationType) {
+            scope.relationTypes.push(types.entityRelationType[type]);
+        }
+
+        scope.fetchRelationTypes = function(searchText) {
+            var deferred = $q.defer();
+            var result = $filter('filter')(scope.relationTypes, {'$': searchText});
+            if (result && result.length) {
+                deferred.resolve(result);
+            } else {
+                deferred.resolve([searchText]);
+            }
+            return deferred.promise;
+        }
+
+        scope.relationTypeSearchTextChanged = function() {
+        }
+
+        scope.updateView = function () {
+            if (!scope.disabled) {
+                ngModelCtrl.$setViewValue(scope.relationType);
+            }
+        }
+
+        ngModelCtrl.$render = function () {
+            scope.relationType = ngModelCtrl.$viewValue;
+        }
+
+        scope.$watch('relationType', function (newValue, prevValue) {
+            if (!angular.equals(newValue, prevValue)) {
+                scope.updateView();
+            }
+        });
+
+        scope.$watch('disabled', function () {
+            scope.updateView();
+        });
+
+        $compile(element.contents())(scope);
+    }
+
+    return {
+        restrict: "E",
+        require: "^ngModel",
+        link: linker,
+        scope: {
+            theForm: '=?',
+            tbRequired: '=?',
+            disabled:'=ngDisabled'
+        }
+    };
+}
diff --git a/ui/src/app/entity/relation/relation-type-autocomplete.scss b/ui/src/app/entity/relation/relation-type-autocomplete.scss
new file mode 100644
index 0000000..9fd0fe0
--- /dev/null
+++ b/ui/src/app/entity/relation/relation-type-autocomplete.scss
@@ -0,0 +1,25 @@
+/**
+ * Copyright © 2016-2017 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.
+ */
+.tb-relation-type-autocomplete {
+  .tb-relation-type-item {
+    display: block;
+    height: 48px;
+  }
+  li {
+    height: auto !important;
+    white-space: normal !important;
+  }
+}
diff --git a/ui/src/app/entity/relation/relation-type-autocomplete.tpl.html b/ui/src/app/entity/relation/relation-type-autocomplete.tpl.html
new file mode 100644
index 0000000..f71c134
--- /dev/null
+++ b/ui/src/app/entity/relation/relation-type-autocomplete.tpl.html
@@ -0,0 +1,40 @@
+<!--
+
+    Copyright © 2016-2017 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.
+
+-->
+<md-autocomplete ng-required="tbRequired"
+                 ng-disabled="disabled"
+                 md-no-cache="true"
+                 md-input-name="relationType"
+                 ng-model="relationType"
+                 md-selected-item="relationType"
+                 md-search-text="relationTypeSearchText"
+                 md-search-text-change="relationTypeSearchTextChanged()"
+                 md-items="item in fetchRelationTypes(relationTypeSearchText)"
+                 md-item-text="item"
+                 md-min-length="0"
+                 md-floating-label="{{ 'relation.relation-type' | translate }}"
+                 md-select-on-match="true"
+                 md-menu-class="tb-relation-type-autocomplete">
+    <md-item-template>
+        <div class="tb-relation-type-item">
+            <span md-highlight-text="relationTypeSearchText" md-highlight-flags="^i">{{item}}</span>
+        </div>
+    </md-item-template>
+    <div ng-messages="theForm.relationType.$error">
+        <div translate ng-message="required">relation.relation-type-required</div>
+    </div>
+</md-autocomplete>
diff --git a/ui/src/app/locale/locale.constant.js b/ui/src/app/locale/locale.constant.js
index d25db5d..fcde13c 100644
--- a/ui/src/app/locale/locale.constant.js
+++ b/ui/src/app/locale/locale.constant.js
@@ -544,6 +544,7 @@ export default angular.module('thingsboard.locale', [])
                     "entity-name-filter-no-entity-matched": "No entities starting with '{{entity}}' were found.",
                     "all-subtypes": "All",
                     "type": "Type",
+                    "type-required": "Entity type is required.",
                     "type-device": "Device",
                     "type-asset": "Asset",
                     "type-rule": "Rule",
@@ -718,19 +719,33 @@ export default angular.module('thingsboard.locale', [])
                 },
                 "relation": {
                     "relations": "Relations",
-                    "entity-relations": "Entity relations",
+                    "direction": "Direction",
+                    "search-direction": {
+                        "FROM": "From",
+                        "TO": "To"
+                    },
+                    "from-relations": "Outbound relations",
+                    "to-relations": "Inbound relations",
                     "selected-relations": "{ count, select, 1 {1 relation} other {# relations} } selected",
                     "type": "Type",
-                    "to-entity-type": "Entity type",
-                    "to-entity-name": "Entity name",
-                    "edit": "Edit relation",
+                    "to-entity-type": "To entity type",
+                    "to-entity-name": "To entity name",
+                    "from-entity-type": "From entity type",
+                    "from-entity-name": "From entity name",
+                    "to-entity": "To entity",
+                    "from-entity": "From entity",
                     "delete": "Delete relation",
                     "relation-type": "Relation type",
-                    "relation-types": {
-                        "Contains": "Contains",
-                        "Manages": "Manages"
-                    },
-                    "add": "Add relation"
+                    "relation-type-required": "Relation type is required.",
+                    "add": "Add relation",
+                    "delete-to-relation-title": "Are you sure you want to delete relation to the entity '{{entityName}}'?",
+                    "delete-to-relation-text": "Be careful, after the confirmation the entity '{{entityName}}' will be unrelated from the current entity.",
+                    "delete-to-relations-title": "Are you sure you want to delete { count, select, 1 {1 relation} other {# relations} }?",
+                    "delete-to-relations-text": "Be careful, after the confirmation all selected relations will be removed and corresponding entities will be unrelated from the current entity.",
+                    "delete-from-relation-title": "Are you sure you want to delete relation from the entity '{{entityName}}'?",
+                    "delete-from-relation-text": "Be careful, after the confirmation current entity will be unrelated from the entity '{{entityName}}'.",
+                    "delete-from-relations-title": "Are you sure you want to delete { count, select, 1 {1 relation} other {# relations} }?",
+                    "delete-from-relations-text": "Be careful, after the confirmation all selected relations will be removed and current entity will be unrelated from the corresponding entities."
                 },
                 "rule": {
                     "rule": "Rule",
diff --git a/ui/src/app/plugin/plugins.tpl.html b/ui/src/app/plugin/plugins.tpl.html
index bd8cf74..d04ebcb 100644
--- a/ui/src/app/plugin/plugins.tpl.html
+++ b/ui/src/app/plugin/plugins.tpl.html
@@ -56,5 +56,11 @@
                             disabled-event-types="{{vm.types.eventType.alarm.value}}">
             </tb-event-table>
         </md-tab>
+        <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode" label="{{ 'relation.relations' | translate }}">
+            <tb-relation-table flex
+                               entity-id="vm.grid.operatingItem().id.id"
+                               entity-type="{{vm.types.entityType.plugin}}">
+            </tb-relation-table>
+        </md-tab>
     </md-tabs>
 </tb-grid>
diff --git a/ui/src/app/rule/rules.tpl.html b/ui/src/app/rule/rules.tpl.html
index bd7ea48..16097cc 100644
--- a/ui/src/app/rule/rules.tpl.html
+++ b/ui/src/app/rule/rules.tpl.html
@@ -56,5 +56,11 @@
                             disabled-event-types="{{vm.types.eventType.alarm.value}}">
             </tb-event-table>
         </md-tab>
+        <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode" label="{{ 'relation.relations' | translate }}">
+            <tb-relation-table flex
+                               entity-id="vm.grid.operatingItem().id.id"
+                               entity-type="{{vm.types.entityType.rule}}">
+            </tb-relation-table>
+        </md-tab>
     </md-tabs>
 </tb-grid>
diff --git a/ui/src/app/tenant/tenants.tpl.html b/ui/src/app/tenant/tenants.tpl.html
index ada2a3f..00350a4 100644
--- a/ui/src/app/tenant/tenants.tpl.html
+++ b/ui/src/app/tenant/tenants.tpl.html
@@ -53,5 +53,11 @@
 							default-event-type="{{vm.types.eventType.alarm.value}}">
 			</tb-event-table>
 		</md-tab>
+		<md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode" label="{{ 'relation.relations' | translate }}">
+			<tb-relation-table flex
+							   entity-id="vm.grid.operatingItem().id.id"
+							   entity-type="{{vm.types.entityType.tenant}}">
+			</tb-relation-table>
+		</md-tab>
 	</md-tabs>
 </tb-grid>
diff --git a/ui/src/scss/main.scss b/ui/src/scss/main.scss
index c062d4e..dbe3543 100644
--- a/ui/src/scss/main.scss
+++ b/ui/src/scss/main.scss
@@ -436,6 +436,7 @@ md-tabs.tb-headless {
  ***********************/
 
 section.tb-header-buttons {
+  pointer-events: none;
   position: absolute;
   right: 0px;
   top: 86px;