Showing
16 changed files
with
276 additions
and
48 deletions
@@ -25,6 +25,7 @@ import com.typesafe.config.Config; | @@ -25,6 +25,7 @@ import com.typesafe.config.Config; | ||
25 | import com.typesafe.config.ConfigFactory; | 25 | import com.typesafe.config.ConfigFactory; |
26 | import lombok.Getter; | 26 | import lombok.Getter; |
27 | import lombok.Setter; | 27 | import lombok.Setter; |
28 | +import lombok.extern.slf4j.Slf4j; | ||
28 | import org.springframework.beans.factory.annotation.Autowired; | 29 | import org.springframework.beans.factory.annotation.Autowired; |
29 | import org.springframework.beans.factory.annotation.Value; | 30 | import org.springframework.beans.factory.annotation.Value; |
30 | import org.springframework.stereotype.Component; | 31 | import org.springframework.stereotype.Component; |
@@ -38,6 +39,7 @@ import org.thingsboard.server.common.data.id.EntityId; | @@ -38,6 +39,7 @@ import org.thingsboard.server.common.data.id.EntityId; | ||
38 | import org.thingsboard.server.common.data.id.TenantId; | 39 | import org.thingsboard.server.common.data.id.TenantId; |
39 | import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; | 40 | import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; |
40 | import org.thingsboard.server.common.msg.TbMsg; | 41 | import org.thingsboard.server.common.msg.TbMsg; |
42 | +import org.thingsboard.server.common.msg.TbMsgDataType; | ||
41 | import org.thingsboard.server.common.msg.cluster.ServerAddress; | 43 | import org.thingsboard.server.common.msg.cluster.ServerAddress; |
42 | import org.thingsboard.server.common.transport.auth.DeviceAuthService; | 44 | import org.thingsboard.server.common.transport.auth.DeviceAuthService; |
43 | import org.thingsboard.server.controller.plugin.PluginWebSocketMsgEndpoint; | 45 | import org.thingsboard.server.controller.plugin.PluginWebSocketMsgEndpoint; |
@@ -60,11 +62,13 @@ import org.thingsboard.server.service.cluster.routing.ClusterRoutingService; | @@ -60,11 +62,13 @@ import org.thingsboard.server.service.cluster.routing.ClusterRoutingService; | ||
60 | import org.thingsboard.server.service.cluster.rpc.ClusterRpcService; | 62 | import org.thingsboard.server.service.cluster.rpc.ClusterRpcService; |
61 | import org.thingsboard.server.service.component.ComponentDiscoveryService; | 63 | import org.thingsboard.server.service.component.ComponentDiscoveryService; |
62 | 64 | ||
65 | +import java.io.IOException; | ||
63 | import java.io.PrintWriter; | 66 | import java.io.PrintWriter; |
64 | import java.io.StringWriter; | 67 | import java.io.StringWriter; |
65 | import java.nio.charset.StandardCharsets; | 68 | import java.nio.charset.StandardCharsets; |
66 | import java.util.Optional; | 69 | import java.util.Optional; |
67 | 70 | ||
71 | +@Slf4j | ||
68 | @Component | 72 | @Component |
69 | public class ActorSystemContext { | 73 | public class ActorSystemContext { |
70 | private static final String AKKA_CONF_FILE_NAME = "actor-system.conf"; | 74 | private static final String AKKA_CONF_FILE_NAME = "actor-system.conf"; |
@@ -292,38 +296,49 @@ public class ActorSystemContext { | @@ -292,38 +296,49 @@ public class ActorSystemContext { | ||
292 | } | 296 | } |
293 | 297 | ||
294 | private void persistDebug(TenantId tenantId, EntityId entityId, String type, TbMsg tbMsg, Throwable error) { | 298 | private void persistDebug(TenantId tenantId, EntityId entityId, String type, TbMsg tbMsg, Throwable error) { |
295 | - Event event = new Event(); | ||
296 | - event.setTenantId(tenantId); | ||
297 | - event.setEntityId(entityId); | ||
298 | - event.setType(DataConstants.DEBUG); | ||
299 | - | ||
300 | - ObjectNode node = mapper.createObjectNode() | ||
301 | - .put("type", type) | ||
302 | - .put("server", getServerAddress()) | ||
303 | - .put("entityId", tbMsg.getOriginator().getId().toString()) | ||
304 | - .put("entityName", tbMsg.getOriginator().getEntityType().name()) | ||
305 | - .put("msgId", tbMsg.getId().toString()) | ||
306 | - .put("msgType", tbMsg.getType()) | ||
307 | - .put("dataType", tbMsg.getDataType().name()); | ||
308 | - | ||
309 | - ObjectNode mdNode = node.putObject("metadata"); | ||
310 | - tbMsg.getMetaData().getData().forEach(mdNode::put); | 299 | + try { |
300 | + Event event = new Event(); | ||
301 | + event.setTenantId(tenantId); | ||
302 | + event.setEntityId(entityId); | ||
303 | + event.setType(DataConstants.DEBUG_RULE_NODE); | ||
304 | + | ||
305 | + String metadata = mapper.writeValueAsString(tbMsg.getMetaData().getData()); | ||
306 | + | ||
307 | + ObjectNode node = mapper.createObjectNode() | ||
308 | + .put("type", type) | ||
309 | + .put("server", getServerAddress()) | ||
310 | + .put("entityId", tbMsg.getOriginator().getId().toString()) | ||
311 | + .put("entityName", tbMsg.getOriginator().getEntityType().name()) | ||
312 | + .put("msgId", tbMsg.getId().toString()) | ||
313 | + .put("msgType", tbMsg.getType()) | ||
314 | + .put("dataType", tbMsg.getDataType().name()) | ||
315 | + .put("data", convertToString(tbMsg.getDataType(), tbMsg.getData())) | ||
316 | + .put("metadata", metadata); | ||
317 | + | ||
318 | + if (error != null) { | ||
319 | + node = node.put("error", toString(error)); | ||
320 | + } | ||
321 | + | ||
322 | + event.setBody(node); | ||
323 | + eventService.save(event); | ||
324 | + } catch (IOException ex) { | ||
325 | + log.warn("Failed to persist rule node debug message", ex); | ||
326 | + } | ||
327 | + } | ||
311 | 328 | ||
312 | - switch (tbMsg.getDataType()) { | 329 | + private String convertToString(TbMsgDataType messageType, byte[] data) { |
330 | + if (data == null) { | ||
331 | + return null; | ||
332 | + } | ||
333 | + switch (messageType) { | ||
334 | + case JSON: | ||
335 | + case TEXT: | ||
336 | + return new String(data, StandardCharsets.UTF_8); | ||
313 | case BINARY: | 337 | case BINARY: |
314 | - node.put("data", Base64Utils.encodeUrlSafe(tbMsg.getData())); | ||
315 | - break; | 338 | + return Base64Utils.encodeToString(data); |
316 | default: | 339 | default: |
317 | - node.put("data", new String(tbMsg.getData(), StandardCharsets.UTF_8)); | ||
318 | - break; | ||
319 | - } | ||
320 | - | ||
321 | - if (error != null) { | ||
322 | - node = node.put("error", toString(error)); | 340 | + throw new RuntimeException("Message type: " + messageType + " is not supported!"); |
323 | } | 341 | } |
324 | - | ||
325 | - event.setBody(node); | ||
326 | - eventService.save(event); | ||
327 | } | 342 | } |
328 | 343 | ||
329 | public static Exception toException(Throwable error) { | 344 | public static Exception toException(Throwable error) { |
@@ -51,6 +51,6 @@ public class AbstractRuleEngineControllerTest extends AbstractControllerTest { | @@ -51,6 +51,6 @@ public class AbstractRuleEngineControllerTest extends AbstractControllerTest { | ||
51 | TimePageLink pageLink = new TimePageLink(limit); | 51 | TimePageLink pageLink = new TimePageLink(limit); |
52 | return doGetTypedWithTimePageLink("/api/events/{entityType}/{entityId}/{eventType}?tenantId={tenantId}&", | 52 | return doGetTypedWithTimePageLink("/api/events/{entityType}/{entityId}/{eventType}?tenantId={tenantId}&", |
53 | new TypeReference<TimePageData<Event>>() { | 53 | new TypeReference<TimePageData<Event>>() { |
54 | - }, pageLink, entityId.getEntityType(), entityId.getId(), DataConstants.DEBUG, tenantId.getId()); | 54 | + }, pageLink, entityId.getEntityType(), entityId.getId(), DataConstants.DEBUG_RULE_NODE, tenantId.getId()); |
55 | } | 55 | } |
56 | } | 56 | } |
@@ -37,7 +37,7 @@ public class DataConstants { | @@ -37,7 +37,7 @@ public class DataConstants { | ||
37 | public static final String ERROR = "ERROR"; | 37 | public static final String ERROR = "ERROR"; |
38 | public static final String LC_EVENT = "LC_EVENT"; | 38 | public static final String LC_EVENT = "LC_EVENT"; |
39 | public static final String STATS = "STATS"; | 39 | public static final String STATS = "STATS"; |
40 | - public static final String DEBUG = "DEBUG"; | 40 | + public static final String DEBUG_RULE_NODE = "DEBUG_RULE_NODE"; |
41 | 41 | ||
42 | public static final String ONEWAY = "ONEWAY"; | 42 | public static final String ONEWAY = "ONEWAY"; |
43 | public static final String TWOWAY = "TWOWAY"; | 43 | public static final String TWOWAY = "TWOWAY"; |
@@ -279,6 +279,23 @@ export default angular.module('thingsboard.types', []) | @@ -279,6 +279,23 @@ export default angular.module('thingsboard.types', []) | ||
279 | function: "function", | 279 | function: "function", |
280 | alarm: "alarm" | 280 | alarm: "alarm" |
281 | }, | 281 | }, |
282 | + contentType: { | ||
283 | + "JSON": { | ||
284 | + value: "JSON", | ||
285 | + name: "content-type.json", | ||
286 | + code: "json" | ||
287 | + }, | ||
288 | + "TEXT": { | ||
289 | + value: "TEXT", | ||
290 | + name: "content-type.text", | ||
291 | + code: "text" | ||
292 | + }, | ||
293 | + "BINARY": { | ||
294 | + value: "BINARY", | ||
295 | + name: "content-type.binary", | ||
296 | + code: "text" | ||
297 | + } | ||
298 | + }, | ||
282 | componentType: { | 299 | componentType: { |
283 | filter: "FILTER", | 300 | filter: "FILTER", |
284 | processor: "PROCESSOR", | 301 | processor: "PROCESSOR", |
@@ -295,7 +312,8 @@ export default angular.module('thingsboard.types', []) | @@ -295,7 +312,8 @@ export default angular.module('thingsboard.types', []) | ||
295 | user: "USER", | 312 | user: "USER", |
296 | dashboard: "DASHBOARD", | 313 | dashboard: "DASHBOARD", |
297 | alarm: "ALARM", | 314 | alarm: "ALARM", |
298 | - rulechain: "RULE_CHAIN" | 315 | + rulechain: "RULE_CHAIN", |
316 | + rulenode: "RULE_NODE" | ||
299 | }, | 317 | }, |
300 | aliasEntityType: { | 318 | aliasEntityType: { |
301 | current_customer: "CURRENT_CUSTOMER" | 319 | current_customer: "CURRENT_CUSTOMER" |
@@ -388,6 +406,16 @@ export default angular.module('thingsboard.types', []) | @@ -388,6 +406,16 @@ export default angular.module('thingsboard.types', []) | ||
388 | name: "event.type-stats" | 406 | name: "event.type-stats" |
389 | } | 407 | } |
390 | }, | 408 | }, |
409 | + debugEventType: { | ||
410 | + debugRuleNode: { | ||
411 | + value: "DEBUG_RULE_NODE", | ||
412 | + name: "event.type-debug-rule-node" | ||
413 | + }, | ||
414 | + debugRuleChain: { | ||
415 | + value: "DEBUG_RULE_CHAIN", | ||
416 | + name: "event.type-debug-rule-chain" | ||
417 | + } | ||
418 | + }, | ||
391 | extensionType: { | 419 | extensionType: { |
392 | http: "HTTP", | 420 | http: "HTTP", |
393 | mqtt: "MQTT", | 421 | mqtt: "MQTT", |
@@ -26,7 +26,7 @@ export default angular.module('thingsboard.directives.detailsSidenav', []) | @@ -26,7 +26,7 @@ export default angular.module('thingsboard.directives.detailsSidenav', []) | ||
26 | .name; | 26 | .name; |
27 | 27 | ||
28 | /*@ngInject*/ | 28 | /*@ngInject*/ |
29 | -function DetailsSidenav($timeout) { | 29 | +function DetailsSidenav($timeout, $window) { |
30 | 30 | ||
31 | var linker = function (scope, element, attrs) { | 31 | var linker = function (scope, element, attrs) { |
32 | 32 | ||
@@ -42,6 +42,23 @@ function DetailsSidenav($timeout) { | @@ -42,6 +42,23 @@ function DetailsSidenav($timeout) { | ||
42 | scope.isEdit = true; | 42 | scope.isEdit = true; |
43 | } | 43 | } |
44 | 44 | ||
45 | + if (angular.isDefined(attrs.closeOnClickOutside && attrs.closeOnClickOutside)) { | ||
46 | + scope.closeOnClickOutside = true; | ||
47 | + var clickOutsideHandler = function() { | ||
48 | + scope.closeDetails(); | ||
49 | + }; | ||
50 | + angular.element($window).click(clickOutsideHandler); | ||
51 | + scope.$on("$destroy", function () { | ||
52 | + angular.element($window).unbind('click', clickOutsideHandler); | ||
53 | + }); | ||
54 | + } | ||
55 | + | ||
56 | + scope.onClick = function($event) { | ||
57 | + if (scope.closeOnClickOutside) { | ||
58 | + $event.stopPropagation(); | ||
59 | + } | ||
60 | + }; | ||
61 | + | ||
45 | scope.toggleDetailsEditMode = function () { | 62 | scope.toggleDetailsEditMode = function () { |
46 | if (!scope.isAlwaysEdit) { | 63 | if (!scope.isAlwaysEdit) { |
47 | if (!scope.isEdit) { | 64 | if (!scope.isEdit) { |
@@ -19,6 +19,7 @@ | @@ -19,6 +19,7 @@ | ||
19 | md-disable-backdrop="true" | 19 | md-disable-backdrop="true" |
20 | md-is-open="isOpen" | 20 | md-is-open="isOpen" |
21 | md-component-id="right" | 21 | md-component-id="right" |
22 | + ng-click="onClick($event)" | ||
22 | layout="column"> | 23 | layout="column"> |
23 | <header> | 24 | <header> |
24 | <md-toolbar class="md-theme-light" ng-style="{'height':headerHeightPx+'px'}"> | 25 | <md-toolbar class="md-theme-light" ng-style="{'height':headerHeightPx+'px'}"> |
@@ -17,11 +17,14 @@ import $ from 'jquery'; | @@ -17,11 +17,14 @@ import $ from 'jquery'; | ||
17 | import 'brace/ext/language_tools'; | 17 | import 'brace/ext/language_tools'; |
18 | import 'brace/mode/java'; | 18 | import 'brace/mode/java'; |
19 | import 'brace/theme/github'; | 19 | import 'brace/theme/github'; |
20 | +import beautify from 'js-beautify'; | ||
20 | 21 | ||
21 | /* eslint-disable angular/angularelement */ | 22 | /* eslint-disable angular/angularelement */ |
22 | 23 | ||
24 | +const js_beautify = beautify.js; | ||
25 | + | ||
23 | /*@ngInject*/ | 26 | /*@ngInject*/ |
24 | -export default function EventContentDialogController($mdDialog, content, title, showingCallback) { | 27 | +export default function EventContentDialogController($mdDialog, types, content, contentType, title, showingCallback) { |
25 | 28 | ||
26 | var vm = this; | 29 | var vm = this; |
27 | 30 | ||
@@ -32,9 +35,19 @@ export default function EventContentDialogController($mdDialog, content, title, | @@ -32,9 +35,19 @@ export default function EventContentDialogController($mdDialog, content, title, | ||
32 | vm.content = content; | 35 | vm.content = content; |
33 | vm.title = title; | 36 | vm.title = title; |
34 | 37 | ||
38 | + var mode; | ||
39 | + if (contentType) { | ||
40 | + mode = types.contentType[contentType].code; | ||
41 | + if (contentType == types.contentType.JSON.value && vm.content) { | ||
42 | + vm.content = js_beautify(vm.content, {indent_size: 4}); | ||
43 | + } | ||
44 | + } else { | ||
45 | + mode = 'java'; | ||
46 | + } | ||
47 | + | ||
35 | vm.contentOptions = { | 48 | vm.contentOptions = { |
36 | useWrapMode: false, | 49 | useWrapMode: false, |
37 | - mode: 'java', | 50 | + mode: mode, |
38 | showGutter: false, | 51 | showGutter: false, |
39 | showPrintMargin: false, | 52 | showPrintMargin: false, |
40 | theme: 'github', | 53 | theme: 'github', |
1 | +<!-- | ||
2 | + | ||
3 | + Copyright © 2016-2018 The Thingsboard Authors | ||
4 | + | ||
5 | + Licensed under the Apache License, Version 2.0 (the "License"); | ||
6 | + you may not use this file except in compliance with the License. | ||
7 | + You may obtain a copy of the License at | ||
8 | + | ||
9 | + http://www.apache.org/licenses/LICENSE-2.0 | ||
10 | + | ||
11 | + Unless required by applicable law or agreed to in writing, software | ||
12 | + distributed under the License is distributed on an "AS IS" BASIS, | ||
13 | + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
14 | + See the License for the specific language governing permissions and | ||
15 | + limitations under the License. | ||
16 | + | ||
17 | +--> | ||
18 | +<div hide-xs hide-sm translate class="tb-cell" flex="30">event.event-time</div> | ||
19 | +<div translate class="tb-cell" flex="20">event.server</div> | ||
20 | +<div translate class="tb-cell" flex="20">event.type</div> | ||
21 | +<div translate class="tb-cell" flex="20">event.entity</div> | ||
22 | +<div translate class="tb-cell" flex="20">event.message-id</div> | ||
23 | +<div translate class="tb-cell" flex="20">event.message-type</div> | ||
24 | +<div translate class="tb-cell" flex="20">event.data-type</div> | ||
25 | +<div translate class="tb-cell" flex="20">event.data</div> | ||
26 | +<div translate class="tb-cell" flex="20">event.metadata</div> | ||
27 | +<div translate class="tb-cell" flex="20">event.error</div> |
@@ -18,6 +18,7 @@ | @@ -18,6 +18,7 @@ | ||
18 | import eventHeaderLcEventTemplate from './event-header-lc-event.tpl.html'; | 18 | import eventHeaderLcEventTemplate from './event-header-lc-event.tpl.html'; |
19 | import eventHeaderStatsTemplate from './event-header-stats.tpl.html'; | 19 | import eventHeaderStatsTemplate from './event-header-stats.tpl.html'; |
20 | import eventHeaderErrorTemplate from './event-header-error.tpl.html'; | 20 | import eventHeaderErrorTemplate from './event-header-error.tpl.html'; |
21 | +import eventHeaderDebugRuleNodeTemplate from './event-header-debug-rulenode.tpl.html'; | ||
21 | 22 | ||
22 | /* eslint-enable import/no-unresolved, import/default */ | 23 | /* eslint-enable import/no-unresolved, import/default */ |
23 | 24 | ||
@@ -38,6 +39,12 @@ export default function EventHeaderDirective($compile, $templateCache, types) { | @@ -38,6 +39,12 @@ export default function EventHeaderDirective($compile, $templateCache, types) { | ||
38 | case types.eventType.error.value: | 39 | case types.eventType.error.value: |
39 | template = eventHeaderErrorTemplate; | 40 | template = eventHeaderErrorTemplate; |
40 | break; | 41 | break; |
42 | + case types.debugEventType.debugRuleNode.value: | ||
43 | + template = eventHeaderDebugRuleNodeTemplate; | ||
44 | + break; | ||
45 | + case types.debugEventType.debugRuleChain.value: | ||
46 | + template = eventHeaderDebugRuleNodeTemplate; | ||
47 | + break; | ||
41 | } | 48 | } |
42 | return $templateCache.get(template); | 49 | return $templateCache.get(template); |
43 | } | 50 | } |
1 | +<!-- | ||
2 | + | ||
3 | + Copyright © 2016-2018 The Thingsboard Authors | ||
4 | + | ||
5 | + Licensed under the Apache License, Version 2.0 (the "License"); | ||
6 | + you may not use this file except in compliance with the License. | ||
7 | + You may obtain a copy of the License at | ||
8 | + | ||
9 | + http://www.apache.org/licenses/LICENSE-2.0 | ||
10 | + | ||
11 | + Unless required by applicable law or agreed to in writing, software | ||
12 | + distributed under the License is distributed on an "AS IS" BASIS, | ||
13 | + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
14 | + See the License for the specific language governing permissions and | ||
15 | + limitations under the License. | ||
16 | + | ||
17 | +--> | ||
18 | +<div hide-xs hide-sm class="tb-cell" flex="30">{{event.createdTime | date : 'yyyy-MM-dd HH:mm:ss'}}</div> | ||
19 | +<div class="tb-cell" flex="20">{{event.body.server}}</div> | ||
20 | +<div class="tb-cell" flex="20">{{event.body.type}}</div> | ||
21 | +<div class="tb-cell" flex="20">{{event.body.entityName}}</div> | ||
22 | +<div class="tb-cell" flex="20">{{event.body.msgId}}</div> | ||
23 | +<div class="tb-cell" flex="20">{{event.body.msgType}}</div> | ||
24 | +<div class="tb-cell" flex="20">{{event.body.dataType}}</div> | ||
25 | +<div class="tb-cell" flex="20"> | ||
26 | + <md-button ng-if="event.body.data" class="md-icon-button md-primary" | ||
27 | + ng-click="showContent($event, event.body.data, 'event.data', event.body.msgType)" | ||
28 | + aria-label="{{ 'action.view' | translate }}"> | ||
29 | + <md-tooltip md-direction="top"> | ||
30 | + {{ 'action.view' | translate }} | ||
31 | + </md-tooltip> | ||
32 | + <md-icon aria-label="{{ 'action.view' | translate }}" | ||
33 | + class="material-icons"> | ||
34 | + more_horiz | ||
35 | + </md-icon> | ||
36 | + </md-button> | ||
37 | +</div> | ||
38 | +<div class="tb-cell" flex="20"> | ||
39 | + <md-button ng-if="event.body.metadata" class="md-icon-button md-primary" | ||
40 | + ng-click="showContent($event, event.body.metadata, 'event.metadata', 'JSON')" | ||
41 | + aria-label="{{ 'action.view' | translate }}"> | ||
42 | + <md-tooltip md-direction="top"> | ||
43 | + {{ 'action.view' | translate }} | ||
44 | + </md-tooltip> | ||
45 | + <md-icon aria-label="{{ 'action.view' | translate }}" | ||
46 | + class="material-icons"> | ||
47 | + more_horiz | ||
48 | + </md-icon> | ||
49 | + </md-button> | ||
50 | +</div> | ||
51 | +<div class="tb-cell" flex="20"> | ||
52 | + <md-button ng-if="event.body.error" class="md-icon-button md-primary" | ||
53 | + ng-click="showContent($event, event.body.error, 'event.error')" | ||
54 | + aria-label="{{ 'action.view' | translate }}"> | ||
55 | + <md-tooltip md-direction="top"> | ||
56 | + {{ 'action.view' | translate }} | ||
57 | + </md-tooltip> | ||
58 | + <md-icon aria-label="{{ 'action.view' | translate }}" | ||
59 | + class="material-icons"> | ||
60 | + more_horiz | ||
61 | + </md-icon> | ||
62 | + </md-button> | ||
63 | +</div> |
@@ -20,6 +20,7 @@ import eventErrorDialogTemplate from './event-content-dialog.tpl.html'; | @@ -20,6 +20,7 @@ import eventErrorDialogTemplate from './event-content-dialog.tpl.html'; | ||
20 | import eventRowLcEventTemplate from './event-row-lc-event.tpl.html'; | 20 | import eventRowLcEventTemplate from './event-row-lc-event.tpl.html'; |
21 | import eventRowStatsTemplate from './event-row-stats.tpl.html'; | 21 | import eventRowStatsTemplate from './event-row-stats.tpl.html'; |
22 | import eventRowErrorTemplate from './event-row-error.tpl.html'; | 22 | import eventRowErrorTemplate from './event-row-error.tpl.html'; |
23 | +import eventRowDebugRuleNodeTemplate from './event-row-debug-rulenode.tpl.html'; | ||
23 | 24 | ||
24 | /* eslint-enable import/no-unresolved, import/default */ | 25 | /* eslint-enable import/no-unresolved, import/default */ |
25 | 26 | ||
@@ -40,6 +41,12 @@ export default function EventRowDirective($compile, $templateCache, $mdDialog, $ | @@ -40,6 +41,12 @@ export default function EventRowDirective($compile, $templateCache, $mdDialog, $ | ||
40 | case types.eventType.error.value: | 41 | case types.eventType.error.value: |
41 | template = eventRowErrorTemplate; | 42 | template = eventRowErrorTemplate; |
42 | break; | 43 | break; |
44 | + case types.debugEventType.debugRuleNode.value: | ||
45 | + template = eventRowDebugRuleNodeTemplate; | ||
46 | + break; | ||
47 | + case types.debugEventType.debugRuleChain.value: | ||
48 | + template = eventRowDebugRuleNodeTemplate; | ||
49 | + break; | ||
43 | } | 50 | } |
44 | return $templateCache.get(template); | 51 | return $templateCache.get(template); |
45 | } | 52 | } |
@@ -53,17 +60,22 @@ export default function EventRowDirective($compile, $templateCache, $mdDialog, $ | @@ -53,17 +60,22 @@ export default function EventRowDirective($compile, $templateCache, $mdDialog, $ | ||
53 | scope.loadTemplate(); | 60 | scope.loadTemplate(); |
54 | }); | 61 | }); |
55 | 62 | ||
63 | + scope.types = types; | ||
64 | + | ||
56 | scope.event = attrs.event; | 65 | scope.event = attrs.event; |
57 | 66 | ||
58 | - scope.showContent = function($event, content, title) { | 67 | + scope.showContent = function($event, content, title, contentType) { |
59 | var onShowingCallback = { | 68 | var onShowingCallback = { |
60 | onShowing: function(){} | 69 | onShowing: function(){} |
61 | } | 70 | } |
71 | + if (!contentType) { | ||
72 | + contentType = null; | ||
73 | + } | ||
62 | $mdDialog.show({ | 74 | $mdDialog.show({ |
63 | controller: 'EventContentDialogController', | 75 | controller: 'EventContentDialogController', |
64 | controllerAs: 'vm', | 76 | controllerAs: 'vm', |
65 | templateUrl: eventErrorDialogTemplate, | 77 | templateUrl: eventErrorDialogTemplate, |
66 | - locals: {content: content, title: title, showingCallback: onShowingCallback}, | 78 | + locals: {content: content, title: title, contentType: contentType, showingCallback: onShowingCallback}, |
67 | parent: angular.element($document[0].body), | 79 | parent: angular.element($document[0].body), |
68 | fullscreen: true, | 80 | fullscreen: true, |
69 | targetEvent: $event, | 81 | targetEvent: $event, |
@@ -36,8 +36,8 @@ export default function EventTableDirective($compile, $templateCache, $rootScope | @@ -36,8 +36,8 @@ export default function EventTableDirective($compile, $templateCache, $rootScope | ||
36 | for (var type in types.eventType) { | 36 | for (var type in types.eventType) { |
37 | var eventType = types.eventType[type]; | 37 | var eventType = types.eventType[type]; |
38 | var enabled = true; | 38 | var enabled = true; |
39 | - for (var disabledType in disabledEventTypes) { | ||
40 | - if (eventType.value === disabledEventTypes[disabledType]) { | 39 | + for (var i=0;i<disabledEventTypes.length;i++) { |
40 | + if (eventType.value === disabledEventTypes[i]) { | ||
41 | enabled = false; | 41 | enabled = false; |
42 | break; | 42 | break; |
43 | } | 43 | } |
@@ -47,7 +47,19 @@ export default function EventTableDirective($compile, $templateCache, $rootScope | @@ -47,7 +47,19 @@ export default function EventTableDirective($compile, $templateCache, $rootScope | ||
47 | } | 47 | } |
48 | } | 48 | } |
49 | } else { | 49 | } else { |
50 | - scope.eventTypes = types.eventType; | 50 | + scope.eventTypes = angular.copy(types.eventType); |
51 | + } | ||
52 | + | ||
53 | + if (attrs.debugEventTypes) { | ||
54 | + var debugEventTypes = attrs.debugEventTypes.split(','); | ||
55 | + for (i=0;i<debugEventTypes.length;i++) { | ||
56 | + for (type in types.debugEventType) { | ||
57 | + eventType = types.debugEventType[type]; | ||
58 | + if (eventType.value === debugEventTypes[i]) { | ||
59 | + scope.eventTypes[type] = eventType; | ||
60 | + } | ||
61 | + } | ||
62 | + } | ||
51 | } | 63 | } |
52 | 64 | ||
53 | scope.eventType = attrs.defaultEventType; | 65 | scope.eventType = attrs.defaultEventType; |
@@ -341,6 +341,11 @@ export default angular.module('thingsboard.locale', []) | @@ -341,6 +341,11 @@ export default angular.module('thingsboard.locale', []) | ||
341 | "enter-password": "Enter password", | 341 | "enter-password": "Enter password", |
342 | "enter-search": "Enter search" | 342 | "enter-search": "Enter search" |
343 | }, | 343 | }, |
344 | + "content-type": { | ||
345 | + "json": "Json", | ||
346 | + "text": "Text", | ||
347 | + "binary": "Binary (Base64)" | ||
348 | + }, | ||
344 | "customer": { | 349 | "customer": { |
345 | "customer": "Customer", | 350 | "customer": "Customer", |
346 | "customers": "Customers", | 351 | "customers": "Customers", |
@@ -762,6 +767,8 @@ export default angular.module('thingsboard.locale', []) | @@ -762,6 +767,8 @@ export default angular.module('thingsboard.locale', []) | ||
762 | "type-error": "Error", | 767 | "type-error": "Error", |
763 | "type-lc-event": "Lifecycle event", | 768 | "type-lc-event": "Lifecycle event", |
764 | "type-stats": "Statistics", | 769 | "type-stats": "Statistics", |
770 | + "type-debug-rule-node": "Debug", | ||
771 | + "type-debug-rule-chain": "Debug", | ||
765 | "no-events-prompt": "No events found", | 772 | "no-events-prompt": "No events found", |
766 | "error": "Error", | 773 | "error": "Error", |
767 | "alarm": "Alarm", | 774 | "alarm": "Alarm", |
@@ -769,6 +776,13 @@ export default angular.module('thingsboard.locale', []) | @@ -769,6 +776,13 @@ export default angular.module('thingsboard.locale', []) | ||
769 | "server": "Server", | 776 | "server": "Server", |
770 | "body": "Body", | 777 | "body": "Body", |
771 | "method": "Method", | 778 | "method": "Method", |
779 | + "type": "Type", | ||
780 | + "entity": "Entity", | ||
781 | + "message-id": "Message Id", | ||
782 | + "message-type": "Message Type", | ||
783 | + "data-type": "Data Type", | ||
784 | + "metadata": "Metadata", | ||
785 | + "data": "Data", | ||
772 | "event": "Event", | 786 | "event": "Event", |
773 | "status": "Status", | 787 | "status": "Status", |
774 | "success": "Success", | 788 | "success": "Success", |
@@ -1172,6 +1186,7 @@ export default angular.module('thingsboard.locale', []) | @@ -1172,6 +1186,7 @@ export default angular.module('thingsboard.locale', []) | ||
1172 | }, | 1186 | }, |
1173 | "rulenode": { | 1187 | "rulenode": { |
1174 | "details": "Details", | 1188 | "details": "Details", |
1189 | + "events": "Events", | ||
1175 | "add": "Add rule node", | 1190 | "add": "Add rule node", |
1176 | "name": "Name", | 1191 | "name": "Name", |
1177 | "name-required": "Name is required.", | 1192 | "name-required": "Name is required.", |
@@ -28,7 +28,7 @@ import addRuleNodeLinkTemplate from './add-link.tpl.html'; | @@ -28,7 +28,7 @@ import addRuleNodeLinkTemplate from './add-link.tpl.html'; | ||
28 | /* eslint-enable import/no-unresolved, import/default */ | 28 | /* eslint-enable import/no-unresolved, import/default */ |
29 | 29 | ||
30 | /*@ngInject*/ | 30 | /*@ngInject*/ |
31 | -export function RuleChainController($stateParams, $scope, $compile, $q, $mdUtil, $timeout, $mdExpansionPanel, $document, $mdDialog, | 31 | +export function RuleChainController($stateParams, $scope, $compile, $q, $mdUtil, $timeout, $mdExpansionPanel, $window, $document, $mdDialog, |
32 | $filter, $translate, hotkeys, types, ruleChainService, Modelfactory, flowchartConstants, | 32 | $filter, $translate, hotkeys, types, ruleChainService, Modelfactory, flowchartConstants, |
33 | ruleChain, ruleChainMetaData, ruleNodeComponents) { | 33 | ruleChain, ruleChainMetaData, ruleNodeComponents) { |
34 | 34 | ||
@@ -77,6 +77,8 @@ export function RuleChainController($stateParams, $scope, $compile, $q, $mdUtil, | @@ -77,6 +77,8 @@ export function RuleChainController($stateParams, $scope, $compile, $q, $mdUtil, | ||
77 | vm.objectsSelected = objectsSelected; | 77 | vm.objectsSelected = objectsSelected; |
78 | vm.deleteSelected = deleteSelected; | 78 | vm.deleteSelected = deleteSelected; |
79 | 79 | ||
80 | + vm.triggerResize = triggerResize; | ||
81 | + | ||
80 | initHotKeys(); | 82 | initHotKeys(); |
81 | 83 | ||
82 | function initHotKeys() { | 84 | function initHotKeys() { |
@@ -129,18 +131,17 @@ export function RuleChainController($stateParams, $scope, $compile, $q, $mdUtil, | @@ -129,18 +131,17 @@ export function RuleChainController($stateParams, $scope, $compile, $q, $mdUtil, | ||
129 | } | 131 | } |
130 | 132 | ||
131 | vm.onEditRuleNodeClosed = function() { | 133 | vm.onEditRuleNodeClosed = function() { |
132 | - vm.editingRuleNode = null; | 134 | + //vm.editingRuleNode = null; |
133 | }; | 135 | }; |
134 | 136 | ||
135 | vm.onEditRuleNodeLinkClosed = function() { | 137 | vm.onEditRuleNodeLinkClosed = function() { |
136 | - vm.editingRuleNodeLink = null; | 138 | + //vm.editingRuleNodeLink = null; |
137 | }; | 139 | }; |
138 | 140 | ||
139 | vm.saveRuleNode = function(theForm) { | 141 | vm.saveRuleNode = function(theForm) { |
140 | $scope.$broadcast('form-submit'); | 142 | $scope.$broadcast('form-submit'); |
141 | if (theForm.$valid) { | 143 | if (theForm.$valid) { |
142 | theForm.$setPristine(); | 144 | theForm.$setPristine(); |
143 | - vm.isEditingRuleNode = false; | ||
144 | vm.ruleChainModel.nodes[vm.editingRuleNodeIndex] = vm.editingRuleNode; | 145 | vm.ruleChainModel.nodes[vm.editingRuleNodeIndex] = vm.editingRuleNode; |
145 | vm.editingRuleNode = angular.copy(vm.editingRuleNode); | 146 | vm.editingRuleNode = angular.copy(vm.editingRuleNode); |
146 | } | 147 | } |
@@ -148,7 +149,6 @@ export function RuleChainController($stateParams, $scope, $compile, $q, $mdUtil, | @@ -148,7 +149,6 @@ export function RuleChainController($stateParams, $scope, $compile, $q, $mdUtil, | ||
148 | 149 | ||
149 | vm.saveRuleNodeLink = function(theForm) { | 150 | vm.saveRuleNodeLink = function(theForm) { |
150 | theForm.$setPristine(); | 151 | theForm.$setPristine(); |
151 | - vm.isEditingRuleNodeLink = false; | ||
152 | vm.ruleChainModel.edges[vm.editingRuleNodeLinkIndex] = vm.editingRuleNodeLink; | 152 | vm.ruleChainModel.edges[vm.editingRuleNodeLinkIndex] = vm.editingRuleNodeLink; |
153 | vm.editingRuleNodeLink = angular.copy(vm.editingRuleNodeLink); | 153 | vm.editingRuleNodeLink = angular.copy(vm.editingRuleNodeLink); |
154 | }; | 154 | }; |
@@ -663,6 +663,11 @@ export function RuleChainController($stateParams, $scope, $compile, $q, $mdUtil, | @@ -663,6 +663,11 @@ export function RuleChainController($stateParams, $scope, $compile, $q, $mdUtil, | ||
663 | function deleteSelected() { | 663 | function deleteSelected() { |
664 | vm.modelservice.deleteSelected(); | 664 | vm.modelservice.deleteSelected(); |
665 | } | 665 | } |
666 | + | ||
667 | + function triggerResize() { | ||
668 | + var w = angular.element($window); | ||
669 | + w.triggerHandler('resize'); | ||
670 | + } | ||
666 | } | 671 | } |
667 | 672 | ||
668 | /*@ngInject*/ | 673 | /*@ngInject*/ |
@@ -67,8 +67,9 @@ | @@ -67,8 +67,9 @@ | ||
67 | header-title="{{vm.editingRuleNode.name}}" | 67 | header-title="{{vm.editingRuleNode.name}}" |
68 | header-subtitle="{{(vm.types.ruleNodeType[vm.editingRuleNode.component.type].name | translate) | 68 | header-subtitle="{{(vm.types.ruleNodeType[vm.editingRuleNode.component.type].name | translate) |
69 | + ' - ' + vm.editingRuleNode.component.name}}" | 69 | + ' - ' + vm.editingRuleNode.component.name}}" |
70 | - is-read-only="false" | 70 | + is-read-only="vm.selectedRuleNodeTabIndex > 0" |
71 | is-open="vm.isEditingRuleNode" | 71 | is-open="vm.isEditingRuleNode" |
72 | + close-on-click-outside="true" | ||
72 | is-always-edit="true" | 73 | is-always-edit="true" |
73 | on-close-details="vm.onEditRuleNodeClosed()" | 74 | on-close-details="vm.onEditRuleNodeClosed()" |
74 | on-toggle-details-edit-mode="vm.onRevertRuleNodeEdit(vm.ruleNodeForm)" | 75 | on-toggle-details-edit-mode="vm.onRevertRuleNodeEdit(vm.ruleNodeForm)" |
@@ -77,9 +78,10 @@ | @@ -77,9 +78,10 @@ | ||
77 | <details-buttons tb-help="vm.helpLinkIdForRuleNodeType()" help-container-id="help-container"> | 78 | <details-buttons tb-help="vm.helpLinkIdForRuleNodeType()" help-container-id="help-container"> |
78 | <div id="help-container"></div> | 79 | <div id="help-container"></div> |
79 | </details-buttons> | 80 | </details-buttons> |
80 | - <md-tabs id="ruleNodeTabs" md-border-bottom flex class="tb-absolute-fill"> | 81 | + <md-tabs md-selected="vm.selectedRuleNodeTabIndex" |
82 | + id="ruleNodeTabs" md-border-bottom flex class="tb-absolute-fill" ng-if="vm.isEditingRuleNode"> | ||
81 | <md-tab label="{{ 'rulenode.details' | translate }}"> | 83 | <md-tab label="{{ 'rulenode.details' | translate }}"> |
82 | - <form name="vm.ruleNodeForm" ng-if="vm.isEditingRuleNode"> | 84 | + <form name="vm.ruleNodeForm"> |
83 | <tb-rule-node | 85 | <tb-rule-node |
84 | rule-node="vm.editingRuleNode" | 86 | rule-node="vm.editingRuleNode" |
85 | rule-chain-id="vm.ruleChain.id.id" | 87 | rule-chain-id="vm.ruleChain.id.id" |
@@ -90,6 +92,15 @@ | @@ -90,6 +92,15 @@ | ||
90 | </tb-rule-node> | 92 | </tb-rule-node> |
91 | </form> | 93 | </form> |
92 | </md-tab> | 94 | </md-tab> |
95 | + <md-tab ng-if="vm.isEditingRuleNode && vm.editingRuleNode.ruleNodeId" | ||
96 | + md-on-select="vm.triggerResize()" label="{{ 'rulenode.events' | translate }}"> | ||
97 | + <tb-event-table flex entity-type="vm.types.entityType.rulenode" | ||
98 | + entity-id="vm.editingRuleNode.ruleNodeId.id" | ||
99 | + tenant-id="vm.ruleChain.tenantId.id" | ||
100 | + debug-event-types="{{vm.types.debugEventType.debugRuleNode.value}}" | ||
101 | + default-event-type="{{vm.types.debugEventType.debugRuleNode.value}}"> | ||
102 | + </tb-event-table> | ||
103 | + </md-tab> | ||
93 | </md-tabs> | 104 | </md-tabs> |
94 | </tb-details-sidenav> | 105 | </tb-details-sidenav> |
95 | <tb-details-sidenav class="tb-rulenode-link-details-sidenav" | 106 | <tb-details-sidenav class="tb-rulenode-link-details-sidenav" |
@@ -97,6 +108,7 @@ | @@ -97,6 +108,7 @@ | ||
97 | header-subtitle="{{'rulenode.link-details' | translate}}" | 108 | header-subtitle="{{'rulenode.link-details' | translate}}" |
98 | is-read-only="false" | 109 | is-read-only="false" |
99 | is-open="vm.isEditingRuleNodeLink" | 110 | is-open="vm.isEditingRuleNodeLink" |
111 | + close-on-click-outside="true" | ||
100 | is-always-edit="true" | 112 | is-always-edit="true" |
101 | on-close-details="vm.onEditRuleNodeLinkClosed()" | 113 | on-close-details="vm.onEditRuleNodeLinkClosed()" |
102 | on-toggle-details-edit-mode="vm.onRevertRuleNodeLinkEdit(vm.ruleNodeLinkForm)" | 114 | on-toggle-details-edit-mode="vm.onRevertRuleNodeLinkEdit(vm.ruleNodeLinkForm)" |
@@ -55,7 +55,8 @@ | @@ -55,7 +55,8 @@ | ||
55 | <tb-event-table flex entity-type="vm.types.entityType.rulechain" | 55 | <tb-event-table flex entity-type="vm.types.entityType.rulechain" |
56 | entity-id="vm.grid.operatingItem().id.id" | 56 | entity-id="vm.grid.operatingItem().id.id" |
57 | tenant-id="vm.grid.operatingItem().tenantId.id" | 57 | tenant-id="vm.grid.operatingItem().tenantId.id" |
58 | - default-event-type="{{vm.types.eventType.lcEvent.value}}"> | 58 | + debug-event-types="{{vm.types.debugEventType.debugRuleChain.value}}" |
59 | + default-event-type="{{vm.types.debugEventType.debugRuleChain.value}}"> | ||
59 | </tb-event-table> | 60 | </tb-event-table> |
60 | </md-tab> | 61 | </md-tab> |
61 | <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode && vm.isRuleChainEditable(vm.grid.operatingItem())" md-on-select="vm.grid.triggerResize()" label="{{ 'relation.relations' | translate }}"> | 62 | <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode && vm.isRuleChainEditable(vm.grid.operatingItem())" md-on-select="vm.grid.triggerResize()" label="{{ 'relation.relations' | translate }}"> |