Showing
11 changed files
with
65 additions
and
18 deletions
@@ -326,7 +326,19 @@ public final class PluginProcessingContext implements PluginContext { | @@ -326,7 +326,19 @@ public final class PluginProcessingContext implements PluginContext { | ||
326 | callback.onSuccess(this, Boolean.FALSE); | 326 | callback.onSuccess(this, Boolean.FALSE); |
327 | } else { | 327 | } else { |
328 | ListenableFuture<RuleMetaData> ruleFuture = pluginCtx.ruleService.findRuleByIdAsync(new RuleId(entityId.getId())); | 328 | ListenableFuture<RuleMetaData> ruleFuture = pluginCtx.ruleService.findRuleByIdAsync(new RuleId(entityId.getId())); |
329 | - Futures.addCallback(ruleFuture, getCallback(callback, rule -> rule != null && rule.getTenantId().equals(ctx.getTenantId()))); | 329 | + Futures.addCallback(ruleFuture, getCallback(callback, rule -> { |
330 | + if (rule == null) { | ||
331 | + return Boolean.FALSE; | ||
332 | + } else { | ||
333 | + if (ctx.isTenantAdmin() && !rule.getTenantId().equals(ctx.getTenantId())) { | ||
334 | + return Boolean.FALSE; | ||
335 | + } else if (ctx.isSystemAdmin() && !rule.getTenantId().isNullUid()) { | ||
336 | + return Boolean.FALSE; | ||
337 | + } else { | ||
338 | + return Boolean.TRUE; | ||
339 | + } | ||
340 | + } | ||
341 | + })); | ||
330 | } | 342 | } |
331 | return; | 343 | return; |
332 | case PLUGIN: | 344 | case PLUGIN: |
@@ -334,7 +346,19 @@ public final class PluginProcessingContext implements PluginContext { | @@ -334,7 +346,19 @@ public final class PluginProcessingContext implements PluginContext { | ||
334 | callback.onSuccess(this, Boolean.FALSE); | 346 | callback.onSuccess(this, Boolean.FALSE); |
335 | } else { | 347 | } else { |
336 | ListenableFuture<PluginMetaData> pluginFuture = pluginCtx.pluginService.findPluginByIdAsync(new PluginId(entityId.getId())); | 348 | ListenableFuture<PluginMetaData> pluginFuture = pluginCtx.pluginService.findPluginByIdAsync(new PluginId(entityId.getId())); |
337 | - Futures.addCallback(pluginFuture, getCallback(callback, plugin -> plugin != null && plugin.getTenantId().equals(ctx.getTenantId()))); | 349 | + Futures.addCallback(pluginFuture, getCallback(callback, plugin -> { |
350 | + if (plugin == null) { | ||
351 | + return Boolean.FALSE; | ||
352 | + } else { | ||
353 | + if (ctx.isTenantAdmin() && !plugin.getTenantId().equals(ctx.getTenantId())) { | ||
354 | + return Boolean.FALSE; | ||
355 | + } else if (ctx.isSystemAdmin() && !plugin.getTenantId().isNullUid()) { | ||
356 | + return Boolean.FALSE; | ||
357 | + } else { | ||
358 | + return Boolean.TRUE; | ||
359 | + } | ||
360 | + } | ||
361 | + })); | ||
338 | } | 362 | } |
339 | return; | 363 | return; |
340 | case CUSTOMER: | 364 | case CUSTOMER: |
@@ -91,4 +91,13 @@ public class DeviceAttributes { | @@ -91,4 +91,13 @@ public class DeviceAttributes { | ||
91 | } | 91 | } |
92 | return map; | 92 | return map; |
93 | } | 93 | } |
94 | + | ||
95 | + @Override | ||
96 | + public String toString() { | ||
97 | + return "DeviceAttributes{" + | ||
98 | + "clientSideAttributesMap=" + clientSideAttributesMap + | ||
99 | + ", serverPrivateAttributesMap=" + serverPrivateAttributesMap + | ||
100 | + ", serverPublicAttributesMap=" + serverPublicAttributesMap + | ||
101 | + '}'; | ||
102 | + } | ||
94 | } | 103 | } |
@@ -15,6 +15,7 @@ | @@ -15,6 +15,7 @@ | ||
15 | */ | 15 | */ |
16 | package org.thingsboard.server.extensions.core.action.template; | 16 | package org.thingsboard.server.extensions.core.action.template; |
17 | 17 | ||
18 | +import lombok.extern.slf4j.Slf4j; | ||
18 | import org.apache.velocity.Template; | 19 | import org.apache.velocity.Template; |
19 | import org.apache.velocity.VelocityContext; | 20 | import org.apache.velocity.VelocityContext; |
20 | import org.apache.velocity.runtime.parser.ParseException; | 21 | import org.apache.velocity.runtime.parser.ParseException; |
@@ -35,6 +36,7 @@ import java.util.Optional; | @@ -35,6 +36,7 @@ import java.util.Optional; | ||
35 | /** | 36 | /** |
36 | * @author Andrew Shvayka | 37 | * @author Andrew Shvayka |
37 | */ | 38 | */ |
39 | +@Slf4j | ||
38 | public abstract class AbstractTemplatePluginAction<T extends TemplateActionConfiguration> extends SimpleRuleLifecycleComponent implements PluginAction<T> { | 40 | public abstract class AbstractTemplatePluginAction<T extends TemplateActionConfiguration> extends SimpleRuleLifecycleComponent implements PluginAction<T> { |
39 | protected T configuration; | 41 | protected T configuration; |
40 | protected Template template; | 42 | protected Template template; |
@@ -69,6 +71,7 @@ public abstract class AbstractTemplatePluginAction<T extends TemplateActionConfi | @@ -69,6 +71,7 @@ public abstract class AbstractTemplatePluginAction<T extends TemplateActionConfi | ||
69 | } | 71 | } |
70 | 72 | ||
71 | protected String getMsgBody(RuleContext ctx, ToDeviceActorMsg msg) { | 73 | protected String getMsgBody(RuleContext ctx, ToDeviceActorMsg msg) { |
74 | + log.trace("Creating context for: {} and payload {}", ctx.getDeviceAttributes(), msg.getPayload()); | ||
72 | VelocityContext context = VelocityUtils.createContext(ctx.getDeviceAttributes(), msg.getPayload()); | 75 | VelocityContext context = VelocityUtils.createContext(ctx.getDeviceAttributes(), msg.getPayload()); |
73 | return VelocityUtils.merge(template, context); | 76 | return VelocityUtils.merge(template, context); |
74 | } | 77 | } |
@@ -16,6 +16,7 @@ | @@ -16,6 +16,7 @@ | ||
16 | package org.thingsboard.server.extensions.kafka.plugin; | 16 | package org.thingsboard.server.extensions.kafka.plugin; |
17 | 17 | ||
18 | import lombok.RequiredArgsConstructor; | 18 | import lombok.RequiredArgsConstructor; |
19 | +import lombok.extern.slf4j.Slf4j; | ||
19 | import org.apache.kafka.clients.producer.Producer; | 20 | import org.apache.kafka.clients.producer.Producer; |
20 | import org.apache.kafka.clients.producer.ProducerRecord; | 21 | import org.apache.kafka.clients.producer.ProducerRecord; |
21 | import org.thingsboard.server.common.data.id.RuleId; | 22 | import org.thingsboard.server.common.data.id.RuleId; |
@@ -30,6 +31,7 @@ import org.thingsboard.server.extensions.kafka.action.KafkaActionMsg; | @@ -30,6 +31,7 @@ import org.thingsboard.server.extensions.kafka.action.KafkaActionMsg; | ||
30 | import org.thingsboard.server.extensions.kafka.action.KafkaActionPayload; | 31 | import org.thingsboard.server.extensions.kafka.action.KafkaActionPayload; |
31 | 32 | ||
32 | @RequiredArgsConstructor | 33 | @RequiredArgsConstructor |
34 | +@Slf4j | ||
33 | public class KafkaMsgHandler implements RuleMsgHandler { | 35 | public class KafkaMsgHandler implements RuleMsgHandler { |
34 | 36 | ||
35 | private final Producer<?, String> producer; | 37 | private final Producer<?, String> producer; |
@@ -40,7 +42,7 @@ public class KafkaMsgHandler implements RuleMsgHandler { | @@ -40,7 +42,7 @@ public class KafkaMsgHandler implements RuleMsgHandler { | ||
40 | throw new RuleException("Unsupported message type " + msg.getClass().getName() + "!"); | 42 | throw new RuleException("Unsupported message type " + msg.getClass().getName() + "!"); |
41 | } | 43 | } |
42 | KafkaActionPayload payload = ((KafkaActionMsg) msg).getPayload(); | 44 | KafkaActionPayload payload = ((KafkaActionMsg) msg).getPayload(); |
43 | - | 45 | + log.debug("Processing kafka payload: {}", payload); |
44 | try { | 46 | try { |
45 | producer.send(new ProducerRecord<>(payload.getTopic(), payload.getMsgBody()), | 47 | producer.send(new ProducerRecord<>(payload.getTopic(), payload.getMsgBody()), |
46 | (metadata, e) -> { | 48 | (metadata, e) -> { |
@@ -78,6 +78,7 @@ public class GatewaySessionCtx { | @@ -78,6 +78,7 @@ public class GatewaySessionCtx { | ||
78 | Device newDevice = new Device(); | 78 | Device newDevice = new Device(); |
79 | newDevice.setTenantId(gateway.getTenantId()); | 79 | newDevice.setTenantId(gateway.getTenantId()); |
80 | newDevice.setName(deviceName); | 80 | newDevice.setName(deviceName); |
81 | + newDevice.setType("default"); | ||
81 | return deviceService.saveDevice(newDevice); | 82 | return deviceService.saveDevice(newDevice); |
82 | }); | 83 | }); |
83 | GatewayDeviceSessionCtx ctx = new GatewayDeviceSessionCtx(this, device); | 84 | GatewayDeviceSessionCtx ctx = new GatewayDeviceSessionCtx(this, device); |
@@ -51,7 +51,6 @@ export default function AttributeTableDirective($compile, $templateCache, $rootS | @@ -51,7 +51,6 @@ export default function AttributeTableDirective($compile, $templateCache, $rootS | ||
51 | scope.types = types; | 51 | scope.types = types; |
52 | 52 | ||
53 | scope.entityType = attrs.entityType; | 53 | scope.entityType = attrs.entityType; |
54 | - scope.attributeScope = getAttributeScopeByValue(attrs.defaultAttributeScope); | ||
55 | 54 | ||
56 | if (scope.entityType === types.entityType.device) { | 55 | if (scope.entityType === types.entityType.device) { |
57 | scope.attributeScopes = types.attributesScope; | 56 | scope.attributeScopes = types.attributesScope; |
@@ -60,8 +59,13 @@ export default function AttributeTableDirective($compile, $templateCache, $rootS | @@ -60,8 +59,13 @@ export default function AttributeTableDirective($compile, $templateCache, $rootS | ||
60 | scope.attributeScopes = {}; | 59 | scope.attributeScopes = {}; |
61 | scope.attributeScopes.server = types.attributesScope.server; | 60 | scope.attributeScopes.server = types.attributesScope.server; |
62 | scope.attributeScopeSelectionReadonly = true; | 61 | scope.attributeScopeSelectionReadonly = true; |
62 | + } | ||
63 | + | ||
64 | + scope.attributeScope = getAttributeScopeByValue(attrs.defaultAttributeScope); | ||
65 | + | ||
66 | + if (scope.entityType != types.entityType.device) { | ||
63 | if (scope.attributeScope != types.latestTelemetry) { | 67 | if (scope.attributeScope != types.latestTelemetry) { |
64 | - scope.attributeScope = scope.attributeScopes.server.value; | 68 | + scope.attributeScope = scope.attributeScopes.server; |
65 | } | 69 | } |
66 | } | 70 | } |
67 | 71 | ||
@@ -81,8 +85,8 @@ export default function AttributeTableDirective($compile, $templateCache, $rootS | @@ -81,8 +85,8 @@ export default function AttributeTableDirective($compile, $templateCache, $rootS | ||
81 | search: null | 85 | search: null |
82 | }; | 86 | }; |
83 | 87 | ||
84 | - scope.$watch("entityId", function(newVal, prevVal) { | ||
85 | - if (newVal && !angular.equals(newVal, prevVal)) { | 88 | + scope.$watch("entityId", function(newVal) { |
89 | + if (newVal) { | ||
86 | scope.resetFilter(); | 90 | scope.resetFilter(); |
87 | scope.getEntityAttributes(false, true); | 91 | scope.getEntityAttributes(false, true); |
88 | } | 92 | } |
@@ -190,7 +190,7 @@ export default angular.module('thingsboard.locale', []) | @@ -190,7 +190,7 @@ export default angular.module('thingsboard.locale', []) | ||
190 | "attribute": { | 190 | "attribute": { |
191 | "attributes": "Attributes", | 191 | "attributes": "Attributes", |
192 | "latest-telemetry": "Latest telemetry", | 192 | "latest-telemetry": "Latest telemetry", |
193 | - "attributes-scope": "Device attributes scope", | 193 | + "attributes-scope": "Entity attributes scope", |
194 | "scope-latest-telemetry": "Latest telemetry", | 194 | "scope-latest-telemetry": "Latest telemetry", |
195 | "scope-client": "Client attributes", | 195 | "scope-client": "Client attributes", |
196 | "scope-server": "Server attributes", | 196 | "scope-server": "Server attributes", |
@@ -138,6 +138,8 @@ export default function PluginController(pluginService, userService, importExpor | @@ -138,6 +138,8 @@ export default function PluginController(pluginService, userService, importExpor | ||
138 | vm.pluginGridConfig.topIndex = $stateParams.topIndex; | 138 | vm.pluginGridConfig.topIndex = $stateParams.topIndex; |
139 | } | 139 | } |
140 | 140 | ||
141 | + vm.isPluginEditable = isPluginEditable; | ||
142 | + | ||
141 | vm.activatePlugin = activatePlugin; | 143 | vm.activatePlugin = activatePlugin; |
142 | vm.suspendPlugin = suspendPlugin; | 144 | vm.suspendPlugin = suspendPlugin; |
143 | vm.exportPlugin = exportPlugin; | 145 | vm.exportPlugin = exportPlugin; |
@@ -19,7 +19,7 @@ | @@ -19,7 +19,7 @@ | ||
19 | <details-buttons tb-help="vm.helpLinkIdForPlugin()" help-container-id="help-container"> | 19 | <details-buttons tb-help="vm.helpLinkIdForPlugin()" help-container-id="help-container"> |
20 | <div id="help-container"></div> | 20 | <div id="help-container"></div> |
21 | </details-buttons> | 21 | </details-buttons> |
22 | - <md-tabs ng-class="{'tb-headless': vm.grid.detailsConfig.isDetailsEditMode}" | 22 | + <md-tabs ng-class="{'tb-headless': (vm.grid.detailsConfig.isDetailsEditMode || !vm.isPluginEditable(vm.grid.operatingItem()))}" |
23 | id="tabs" md-border-bottom flex class="tb-absolute-fill"> | 23 | id="tabs" md-border-bottom flex class="tb-absolute-fill"> |
24 | <md-tab label="{{ 'plugin.details' | translate }}"> | 24 | <md-tab label="{{ 'plugin.details' | translate }}"> |
25 | <tb-plugin plugin="vm.grid.operatingItem()" | 25 | <tb-plugin plugin="vm.grid.operatingItem()" |
@@ -31,7 +31,7 @@ | @@ -31,7 +31,7 @@ | ||
31 | on-export-plugin="vm.exportPlugin(event, vm.grid.detailsConfig.currentItem)" | 31 | on-export-plugin="vm.exportPlugin(event, vm.grid.detailsConfig.currentItem)" |
32 | on-delete-plugin="vm.grid.deleteItem(event, vm.grid.detailsConfig.currentItem)"></tb-plugin> | 32 | on-delete-plugin="vm.grid.deleteItem(event, vm.grid.detailsConfig.currentItem)"></tb-plugin> |
33 | </md-tab> | 33 | </md-tab> |
34 | - <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode" label="{{ 'attribute.attributes' | translate }}"> | 34 | + <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode && vm.isPluginEditable(vm.grid.operatingItem())" label="{{ 'attribute.attributes' | translate }}"> |
35 | <tb-attribute-table flex | 35 | <tb-attribute-table flex |
36 | entity-id="vm.grid.operatingItem().id.id" | 36 | entity-id="vm.grid.operatingItem().id.id" |
37 | entity-type="{{vm.types.entityType.plugin}}" | 37 | entity-type="{{vm.types.entityType.plugin}}" |
@@ -39,7 +39,7 @@ | @@ -39,7 +39,7 @@ | ||
39 | default-attribute-scope="{{vm.types.attributesScope.server.value}}"> | 39 | default-attribute-scope="{{vm.types.attributesScope.server.value}}"> |
40 | </tb-attribute-table> | 40 | </tb-attribute-table> |
41 | </md-tab> | 41 | </md-tab> |
42 | - <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode" label="{{ 'attribute.latest-telemetry' | translate }}"> | 42 | + <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode && vm.isPluginEditable(vm.grid.operatingItem())" label="{{ 'attribute.latest-telemetry' | translate }}"> |
43 | <tb-attribute-table flex | 43 | <tb-attribute-table flex |
44 | entity-id="vm.grid.operatingItem().id.id" | 44 | entity-id="vm.grid.operatingItem().id.id" |
45 | entity-type="{{vm.types.entityType.plugin}}" | 45 | entity-type="{{vm.types.entityType.plugin}}" |
@@ -48,7 +48,7 @@ | @@ -48,7 +48,7 @@ | ||
48 | disable-attribute-scope-selection="true"> | 48 | disable-attribute-scope-selection="true"> |
49 | </tb-attribute-table> | 49 | </tb-attribute-table> |
50 | </md-tab> | 50 | </md-tab> |
51 | - <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode" label="{{ 'plugin.events' | translate }}"> | 51 | + <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode && vm.isPluginEditable(vm.grid.operatingItem())" label="{{ 'plugin.events' | translate }}"> |
52 | <tb-event-table flex entity-type="vm.types.entityType.plugin" | 52 | <tb-event-table flex entity-type="vm.types.entityType.plugin" |
53 | entity-id="vm.grid.operatingItem().id.id" | 53 | entity-id="vm.grid.operatingItem().id.id" |
54 | tenant-id="vm.grid.operatingItem().tenantId.id" | 54 | tenant-id="vm.grid.operatingItem().tenantId.id" |
@@ -56,7 +56,7 @@ | @@ -56,7 +56,7 @@ | ||
56 | disabled-event-types="{{vm.types.eventType.alarm.value}}"> | 56 | disabled-event-types="{{vm.types.eventType.alarm.value}}"> |
57 | </tb-event-table> | 57 | </tb-event-table> |
58 | </md-tab> | 58 | </md-tab> |
59 | - <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode" label="{{ 'relation.relations' | translate }}"> | 59 | + <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode && vm.isPluginEditable(vm.grid.operatingItem())" label="{{ 'relation.relations' | translate }}"> |
60 | <tb-relation-table flex | 60 | <tb-relation-table flex |
61 | entity-id="vm.grid.operatingItem().id.id" | 61 | entity-id="vm.grid.operatingItem().id.id" |
62 | entity-type="{{vm.types.entityType.plugin}}"> | 62 | entity-type="{{vm.types.entityType.plugin}}"> |
@@ -134,6 +134,8 @@ export default function RuleController(ruleService, userService, importExport, $ | @@ -134,6 +134,8 @@ export default function RuleController(ruleService, userService, importExport, $ | ||
134 | vm.ruleGridConfig.topIndex = $stateParams.topIndex; | 134 | vm.ruleGridConfig.topIndex = $stateParams.topIndex; |
135 | } | 135 | } |
136 | 136 | ||
137 | + vm.isRuleEditable = isRuleEditable; | ||
138 | + | ||
137 | vm.activateRule = activateRule; | 139 | vm.activateRule = activateRule; |
138 | vm.suspendRule = suspendRule; | 140 | vm.suspendRule = suspendRule; |
139 | vm.exportRule = exportRule; | 141 | vm.exportRule = exportRule; |
@@ -19,7 +19,7 @@ | @@ -19,7 +19,7 @@ | ||
19 | <details-buttons tb-help="'rules'" help-container-id="help-container"> | 19 | <details-buttons tb-help="'rules'" help-container-id="help-container"> |
20 | <div id="help-container"></div> | 20 | <div id="help-container"></div> |
21 | </details-buttons> | 21 | </details-buttons> |
22 | - <md-tabs ng-class="{'tb-headless': vm.grid.detailsConfig.isDetailsEditMode}" | 22 | + <md-tabs ng-class="{'tb-headless': (vm.grid.detailsConfig.isDetailsEditMode || !vm.isRuleEditable(vm.grid.operatingItem()))}" |
23 | id="tabs" md-border-bottom flex class="tb-absolute-fill"> | 23 | id="tabs" md-border-bottom flex class="tb-absolute-fill"> |
24 | <md-tab label="{{ 'rule.details' | translate }}"> | 24 | <md-tab label="{{ 'rule.details' | translate }}"> |
25 | <tb-rule rule="vm.grid.operatingItem()" | 25 | <tb-rule rule="vm.grid.operatingItem()" |
@@ -31,7 +31,7 @@ | @@ -31,7 +31,7 @@ | ||
31 | on-export-rule="vm.exportRule(event, vm.grid.detailsConfig.currentItem)" | 31 | on-export-rule="vm.exportRule(event, vm.grid.detailsConfig.currentItem)" |
32 | on-delete-rule="vm.grid.deleteItem(event, vm.grid.detailsConfig.currentItem)"></tb-rule> | 32 | on-delete-rule="vm.grid.deleteItem(event, vm.grid.detailsConfig.currentItem)"></tb-rule> |
33 | </md-tab> | 33 | </md-tab> |
34 | - <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode" label="{{ 'attribute.attributes' | translate }}"> | 34 | + <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode && vm.isRuleEditable(vm.grid.operatingItem())" label="{{ 'attribute.attributes' | translate }}"> |
35 | <tb-attribute-table flex | 35 | <tb-attribute-table flex |
36 | entity-id="vm.grid.operatingItem().id.id" | 36 | entity-id="vm.grid.operatingItem().id.id" |
37 | entity-type="{{vm.types.entityType.rule}}" | 37 | entity-type="{{vm.types.entityType.rule}}" |
@@ -39,7 +39,7 @@ | @@ -39,7 +39,7 @@ | ||
39 | default-attribute-scope="{{vm.types.attributesScope.server.value}}"> | 39 | default-attribute-scope="{{vm.types.attributesScope.server.value}}"> |
40 | </tb-attribute-table> | 40 | </tb-attribute-table> |
41 | </md-tab> | 41 | </md-tab> |
42 | - <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode" label="{{ 'attribute.latest-telemetry' | translate }}"> | 42 | + <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode && vm.isRuleEditable(vm.grid.operatingItem())" label="{{ 'attribute.latest-telemetry' | translate }}"> |
43 | <tb-attribute-table flex | 43 | <tb-attribute-table flex |
44 | entity-id="vm.grid.operatingItem().id.id" | 44 | entity-id="vm.grid.operatingItem().id.id" |
45 | entity-type="{{vm.types.entityType.rule}}" | 45 | entity-type="{{vm.types.entityType.rule}}" |
@@ -48,7 +48,7 @@ | @@ -48,7 +48,7 @@ | ||
48 | disable-attribute-scope-selection="true"> | 48 | disable-attribute-scope-selection="true"> |
49 | </tb-attribute-table> | 49 | </tb-attribute-table> |
50 | </md-tab> | 50 | </md-tab> |
51 | - <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode" label="{{ 'rule.events' | translate }}"> | 51 | + <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode && vm.isRuleEditable(vm.grid.operatingItem())" label="{{ 'rule.events' | translate }}"> |
52 | <tb-event-table flex entity-type="vm.types.entityType.rule" | 52 | <tb-event-table flex entity-type="vm.types.entityType.rule" |
53 | entity-id="vm.grid.operatingItem().id.id" | 53 | entity-id="vm.grid.operatingItem().id.id" |
54 | tenant-id="vm.grid.operatingItem().tenantId.id" | 54 | tenant-id="vm.grid.operatingItem().tenantId.id" |
@@ -56,7 +56,7 @@ | @@ -56,7 +56,7 @@ | ||
56 | disabled-event-types="{{vm.types.eventType.alarm.value}}"> | 56 | disabled-event-types="{{vm.types.eventType.alarm.value}}"> |
57 | </tb-event-table> | 57 | </tb-event-table> |
58 | </md-tab> | 58 | </md-tab> |
59 | - <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode" label="{{ 'relation.relations' | translate }}"> | 59 | + <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode && vm.isRuleEditable(vm.grid.operatingItem())" label="{{ 'relation.relations' | translate }}"> |
60 | <tb-relation-table flex | 60 | <tb-relation-table flex |
61 | entity-id="vm.grid.operatingItem().id.id" | 61 | entity-id="vm.grid.operatingItem().id.id" |
62 | entity-type="{{vm.types.entityType.rule}}"> | 62 | entity-type="{{vm.types.entityType.rule}}"> |