Browse Source

Rule Node Debug UI

pull/725/head
Igor Kulikov 9 years ago
parent
commit
4bbcffdf63
  1. 71
      application/src/main/java/org/thingsboard/server/actors/ActorSystemContext.java
  2. 2
      application/src/test/java/org/thingsboard/server/controller/AbstractRuleEngineControllerTest.java
  3. 2
      common/data/src/main/java/org/thingsboard/server/common/data/DataConstants.java
  4. 30
      ui/src/app/common/types.constant.js
  5. 19
      ui/src/app/components/details-sidenav.directive.js
  6. 1
      ui/src/app/components/details-sidenav.tpl.html
  7. 17
      ui/src/app/event/event-content-dialog.controller.js
  8. 27
      ui/src/app/event/event-header-debug-rulenode.tpl.html
  9. 7
      ui/src/app/event/event-header.directive.js
  10. 63
      ui/src/app/event/event-row-debug-rulenode.tpl.html
  11. 16
      ui/src/app/event/event-row.directive.js
  12. 18
      ui/src/app/event/event-table.directive.js
  13. 15
      ui/src/app/locale/locale.constant.js
  14. 15
      ui/src/app/rulechain/rulechain.controller.js
  15. 18
      ui/src/app/rulechain/rulechain.tpl.html
  16. 3
      ui/src/app/rulechain/rulechains.tpl.html

71
application/src/main/java/org/thingsboard/server/actors/ActorSystemContext.java

@ -25,6 +25,7 @@ import com.typesafe.config.Config;
import com.typesafe.config.ConfigFactory; import com.typesafe.config.ConfigFactory;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@ -38,6 +39,7 @@ import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent;
import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsg;
import org.thingsboard.server.common.msg.TbMsgDataType;
import org.thingsboard.server.common.msg.cluster.ServerAddress; import org.thingsboard.server.common.msg.cluster.ServerAddress;
import org.thingsboard.server.common.transport.auth.DeviceAuthService; import org.thingsboard.server.common.transport.auth.DeviceAuthService;
import org.thingsboard.server.controller.plugin.PluginWebSocketMsgEndpoint; import org.thingsboard.server.controller.plugin.PluginWebSocketMsgEndpoint;
@ -60,11 +62,13 @@ import org.thingsboard.server.service.cluster.routing.ClusterRoutingService;
import org.thingsboard.server.service.cluster.rpc.ClusterRpcService; import org.thingsboard.server.service.cluster.rpc.ClusterRpcService;
import org.thingsboard.server.service.component.ComponentDiscoveryService; import org.thingsboard.server.service.component.ComponentDiscoveryService;
import java.io.IOException;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.io.StringWriter; import java.io.StringWriter;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.Optional; import java.util.Optional;
@Slf4j
@Component @Component
public class ActorSystemContext { public class ActorSystemContext {
private static final String AKKA_CONF_FILE_NAME = "actor-system.conf"; private static final String AKKA_CONF_FILE_NAME = "actor-system.conf";
@ -292,38 +296,49 @@ public class ActorSystemContext {
} }
private void persistDebug(TenantId tenantId, EntityId entityId, String type, TbMsg tbMsg, Throwable error) { private void persistDebug(TenantId tenantId, EntityId entityId, String type, TbMsg tbMsg, Throwable error) {
Event event = new Event(); try {
event.setTenantId(tenantId); Event event = new Event();
event.setEntityId(entityId); event.setTenantId(tenantId);
event.setType(DataConstants.DEBUG); event.setEntityId(entityId);
event.setType(DataConstants.DEBUG_RULE_NODE);
ObjectNode node = mapper.createObjectNode()
.put("type", type) String metadata = mapper.writeValueAsString(tbMsg.getMetaData().getData());
.put("server", getServerAddress())
.put("entityId", tbMsg.getOriginator().getId().toString()) ObjectNode node = mapper.createObjectNode()
.put("entityName", tbMsg.getOriginator().getEntityType().name()) .put("type", type)
.put("msgId", tbMsg.getId().toString()) .put("server", getServerAddress())
.put("msgType", tbMsg.getType()) .put("entityId", tbMsg.getOriginator().getId().toString())
.put("dataType", tbMsg.getDataType().name()); .put("entityName", tbMsg.getOriginator().getEntityType().name())
.put("msgId", tbMsg.getId().toString())
ObjectNode mdNode = node.putObject("metadata"); .put("msgType", tbMsg.getType())
tbMsg.getMetaData().getData().forEach(mdNode::put); .put("dataType", tbMsg.getDataType().name())
.put("data", convertToString(tbMsg.getDataType(), tbMsg.getData()))
.put("metadata", metadata);
if (error != null) {
node = node.put("error", toString(error));
}
event.setBody(node);
eventService.save(event);
} catch (IOException ex) {
log.warn("Failed to persist rule node debug message", ex);
}
}
switch (tbMsg.getDataType()) { private String convertToString(TbMsgDataType messageType, byte[] data) {
if (data == null) {
return null;
}
switch (messageType) {
case JSON:
case TEXT:
return new String(data, StandardCharsets.UTF_8);
case BINARY: case BINARY:
node.put("data", Base64Utils.encodeUrlSafe(tbMsg.getData())); return Base64Utils.encodeToString(data);
break;
default: default:
node.put("data", new String(tbMsg.getData(), StandardCharsets.UTF_8)); throw new RuntimeException("Message type: " + messageType + " is not supported!");
break;
}
if (error != null) {
node = node.put("error", toString(error));
} }
event.setBody(node);
eventService.save(event);
} }
public static Exception toException(Throwable error) { public static Exception toException(Throwable error) {

2
application/src/test/java/org/thingsboard/server/controller/AbstractRuleEngineControllerTest.java

@ -51,6 +51,6 @@ public class AbstractRuleEngineControllerTest extends AbstractControllerTest {
TimePageLink pageLink = new TimePageLink(limit); TimePageLink pageLink = new TimePageLink(limit);
return doGetTypedWithTimePageLink("/api/events/{entityType}/{entityId}/{eventType}?tenantId={tenantId}&", return doGetTypedWithTimePageLink("/api/events/{entityType}/{entityId}/{eventType}?tenantId={tenantId}&",
new TypeReference<TimePageData<Event>>() { new TypeReference<TimePageData<Event>>() {
}, pageLink, entityId.getEntityType(), entityId.getId(), DataConstants.DEBUG, tenantId.getId()); }, pageLink, entityId.getEntityType(), entityId.getId(), DataConstants.DEBUG_RULE_NODE, tenantId.getId());
} }
} }

2
common/data/src/main/java/org/thingsboard/server/common/data/DataConstants.java

@ -37,7 +37,7 @@ public class DataConstants {
public static final String ERROR = "ERROR"; public static final String ERROR = "ERROR";
public static final String LC_EVENT = "LC_EVENT"; public static final String LC_EVENT = "LC_EVENT";
public static final String STATS = "STATS"; public static final String STATS = "STATS";
public static final String DEBUG = "DEBUG"; public static final String DEBUG_RULE_NODE = "DEBUG_RULE_NODE";
public static final String ONEWAY = "ONEWAY"; public static final String ONEWAY = "ONEWAY";
public static final String TWOWAY = "TWOWAY"; public static final String TWOWAY = "TWOWAY";

30
ui/src/app/common/types.constant.js

@ -279,6 +279,23 @@ export default angular.module('thingsboard.types', [])
function: "function", function: "function",
alarm: "alarm" alarm: "alarm"
}, },
contentType: {
"JSON": {
value: "JSON",
name: "content-type.json",
code: "json"
},
"TEXT": {
value: "TEXT",
name: "content-type.text",
code: "text"
},
"BINARY": {
value: "BINARY",
name: "content-type.binary",
code: "text"
}
},
componentType: { componentType: {
filter: "FILTER", filter: "FILTER",
processor: "PROCESSOR", processor: "PROCESSOR",
@ -295,7 +312,8 @@ export default angular.module('thingsboard.types', [])
user: "USER", user: "USER",
dashboard: "DASHBOARD", dashboard: "DASHBOARD",
alarm: "ALARM", alarm: "ALARM",
rulechain: "RULE_CHAIN" rulechain: "RULE_CHAIN",
rulenode: "RULE_NODE"
}, },
aliasEntityType: { aliasEntityType: {
current_customer: "CURRENT_CUSTOMER" current_customer: "CURRENT_CUSTOMER"
@ -388,6 +406,16 @@ export default angular.module('thingsboard.types', [])
name: "event.type-stats" name: "event.type-stats"
} }
}, },
debugEventType: {
debugRuleNode: {
value: "DEBUG_RULE_NODE",
name: "event.type-debug-rule-node"
},
debugRuleChain: {
value: "DEBUG_RULE_CHAIN",
name: "event.type-debug-rule-chain"
}
},
extensionType: { extensionType: {
http: "HTTP", http: "HTTP",
mqtt: "MQTT", mqtt: "MQTT",

19
ui/src/app/components/details-sidenav.directive.js

@ -26,7 +26,7 @@ export default angular.module('thingsboard.directives.detailsSidenav', [])
.name; .name;
/*@ngInject*/ /*@ngInject*/
function DetailsSidenav($timeout) { function DetailsSidenav($timeout, $window) {
var linker = function (scope, element, attrs) { var linker = function (scope, element, attrs) {
@ -42,6 +42,23 @@ function DetailsSidenav($timeout) {
scope.isEdit = true; scope.isEdit = true;
} }
if (angular.isDefined(attrs.closeOnClickOutside && attrs.closeOnClickOutside)) {
scope.closeOnClickOutside = true;
var clickOutsideHandler = function() {
scope.closeDetails();
};
angular.element($window).click(clickOutsideHandler);
scope.$on("$destroy", function () {
angular.element($window).unbind('click', clickOutsideHandler);
});
}
scope.onClick = function($event) {
if (scope.closeOnClickOutside) {
$event.stopPropagation();
}
};
scope.toggleDetailsEditMode = function () { scope.toggleDetailsEditMode = function () {
if (!scope.isAlwaysEdit) { if (!scope.isAlwaysEdit) {
if (!scope.isEdit) { if (!scope.isEdit) {

1
ui/src/app/components/details-sidenav.tpl.html

@ -19,6 +19,7 @@
md-disable-backdrop="true" md-disable-backdrop="true"
md-is-open="isOpen" md-is-open="isOpen"
md-component-id="right" md-component-id="right"
ng-click="onClick($event)"
layout="column"> layout="column">
<header> <header>
<md-toolbar class="md-theme-light" ng-style="{'height':headerHeightPx+'px'}"> <md-toolbar class="md-theme-light" ng-style="{'height':headerHeightPx+'px'}">

17
ui/src/app/event/event-content-dialog.controller.js

@ -17,11 +17,14 @@ import $ from 'jquery';
import 'brace/ext/language_tools'; import 'brace/ext/language_tools';
import 'brace/mode/java'; import 'brace/mode/java';
import 'brace/theme/github'; import 'brace/theme/github';
import beautify from 'js-beautify';
/* eslint-disable angular/angularelement */ /* eslint-disable angular/angularelement */
const js_beautify = beautify.js;
/*@ngInject*/ /*@ngInject*/
export default function EventContentDialogController($mdDialog, content, title, showingCallback) { export default function EventContentDialogController($mdDialog, types, content, contentType, title, showingCallback) {
var vm = this; var vm = this;
@ -32,9 +35,19 @@ export default function EventContentDialogController($mdDialog, content, title,
vm.content = content; vm.content = content;
vm.title = title; vm.title = title;
var mode;
if (contentType) {
mode = types.contentType[contentType].code;
if (contentType == types.contentType.JSON.value && vm.content) {
vm.content = js_beautify(vm.content, {indent_size: 4});
}
} else {
mode = 'java';
}
vm.contentOptions = { vm.contentOptions = {
useWrapMode: false, useWrapMode: false,
mode: 'java', mode: mode,
showGutter: false, showGutter: false,
showPrintMargin: false, showPrintMargin: false,
theme: 'github', theme: 'github',

27
ui/src/app/event/event-header-debug-rulenode.tpl.html

@ -0,0 +1,27 @@
<!--
Copyright © 2016-2018 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.
-->
<div hide-xs hide-sm translate class="tb-cell" flex="30">event.event-time</div>
<div translate class="tb-cell" flex="20">event.server</div>
<div translate class="tb-cell" flex="20">event.type</div>
<div translate class="tb-cell" flex="20">event.entity</div>
<div translate class="tb-cell" flex="20">event.message-id</div>
<div translate class="tb-cell" flex="20">event.message-type</div>
<div translate class="tb-cell" flex="20">event.data-type</div>
<div translate class="tb-cell" flex="20">event.data</div>
<div translate class="tb-cell" flex="20">event.metadata</div>
<div translate class="tb-cell" flex="20">event.error</div>

7
ui/src/app/event/event-header.directive.js

@ -18,6 +18,7 @@
import eventHeaderLcEventTemplate from './event-header-lc-event.tpl.html'; import eventHeaderLcEventTemplate from './event-header-lc-event.tpl.html';
import eventHeaderStatsTemplate from './event-header-stats.tpl.html'; import eventHeaderStatsTemplate from './event-header-stats.tpl.html';
import eventHeaderErrorTemplate from './event-header-error.tpl.html'; import eventHeaderErrorTemplate from './event-header-error.tpl.html';
import eventHeaderDebugRuleNodeTemplate from './event-header-debug-rulenode.tpl.html';
/* eslint-enable import/no-unresolved, import/default */ /* eslint-enable import/no-unresolved, import/default */
@ -38,6 +39,12 @@ export default function EventHeaderDirective($compile, $templateCache, types) {
case types.eventType.error.value: case types.eventType.error.value:
template = eventHeaderErrorTemplate; template = eventHeaderErrorTemplate;
break; break;
case types.debugEventType.debugRuleNode.value:
template = eventHeaderDebugRuleNodeTemplate;
break;
case types.debugEventType.debugRuleChain.value:
template = eventHeaderDebugRuleNodeTemplate;
break;
} }
return $templateCache.get(template); return $templateCache.get(template);
} }

63
ui/src/app/event/event-row-debug-rulenode.tpl.html

@ -0,0 +1,63 @@
<!--
Copyright © 2016-2018 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.
-->
<div hide-xs hide-sm class="tb-cell" flex="30">{{event.createdTime | date : 'yyyy-MM-dd HH:mm:ss'}}</div>
<div class="tb-cell" flex="20">{{event.body.server}}</div>
<div class="tb-cell" flex="20">{{event.body.type}}</div>
<div class="tb-cell" flex="20">{{event.body.entityName}}</div>
<div class="tb-cell" flex="20">{{event.body.msgId}}</div>
<div class="tb-cell" flex="20">{{event.body.msgType}}</div>
<div class="tb-cell" flex="20">{{event.body.dataType}}</div>
<div class="tb-cell" flex="20">
<md-button ng-if="event.body.data" class="md-icon-button md-primary"
ng-click="showContent($event, event.body.data, 'event.data', event.body.msgType)"
aria-label="{{ 'action.view' | translate }}">
<md-tooltip md-direction="top">
{{ 'action.view' | translate }}
</md-tooltip>
<md-icon aria-label="{{ 'action.view' | translate }}"
class="material-icons">
more_horiz
</md-icon>
</md-button>
</div>
<div class="tb-cell" flex="20">
<md-button ng-if="event.body.metadata" class="md-icon-button md-primary"
ng-click="showContent($event, event.body.metadata, 'event.metadata', 'JSON')"
aria-label="{{ 'action.view' | translate }}">
<md-tooltip md-direction="top">
{{ 'action.view' | translate }}
</md-tooltip>
<md-icon aria-label="{{ 'action.view' | translate }}"
class="material-icons">
more_horiz
</md-icon>
</md-button>
</div>
<div class="tb-cell" flex="20">
<md-button ng-if="event.body.error" class="md-icon-button md-primary"
ng-click="showContent($event, event.body.error, 'event.error')"
aria-label="{{ 'action.view' | translate }}">
<md-tooltip md-direction="top">
{{ 'action.view' | translate }}
</md-tooltip>
<md-icon aria-label="{{ 'action.view' | translate }}"
class="material-icons">
more_horiz
</md-icon>
</md-button>
</div>

16
ui/src/app/event/event-row.directive.js

@ -20,6 +20,7 @@ import eventErrorDialogTemplate from './event-content-dialog.tpl.html';
import eventRowLcEventTemplate from './event-row-lc-event.tpl.html'; import eventRowLcEventTemplate from './event-row-lc-event.tpl.html';
import eventRowStatsTemplate from './event-row-stats.tpl.html'; import eventRowStatsTemplate from './event-row-stats.tpl.html';
import eventRowErrorTemplate from './event-row-error.tpl.html'; import eventRowErrorTemplate from './event-row-error.tpl.html';
import eventRowDebugRuleNodeTemplate from './event-row-debug-rulenode.tpl.html';
/* eslint-enable import/no-unresolved, import/default */ /* eslint-enable import/no-unresolved, import/default */
@ -40,6 +41,12 @@ export default function EventRowDirective($compile, $templateCache, $mdDialog, $
case types.eventType.error.value: case types.eventType.error.value:
template = eventRowErrorTemplate; template = eventRowErrorTemplate;
break; break;
case types.debugEventType.debugRuleNode.value:
template = eventRowDebugRuleNodeTemplate;
break;
case types.debugEventType.debugRuleChain.value:
template = eventRowDebugRuleNodeTemplate;
break;
} }
return $templateCache.get(template); return $templateCache.get(template);
} }
@ -53,17 +60,22 @@ export default function EventRowDirective($compile, $templateCache, $mdDialog, $
scope.loadTemplate(); scope.loadTemplate();
}); });
scope.types = types;
scope.event = attrs.event; scope.event = attrs.event;
scope.showContent = function($event, content, title) { scope.showContent = function($event, content, title, contentType) {
var onShowingCallback = { var onShowingCallback = {
onShowing: function(){} onShowing: function(){}
} }
if (!contentType) {
contentType = null;
}
$mdDialog.show({ $mdDialog.show({
controller: 'EventContentDialogController', controller: 'EventContentDialogController',
controllerAs: 'vm', controllerAs: 'vm',
templateUrl: eventErrorDialogTemplate, templateUrl: eventErrorDialogTemplate,
locals: {content: content, title: title, showingCallback: onShowingCallback}, locals: {content: content, title: title, contentType: contentType, showingCallback: onShowingCallback},
parent: angular.element($document[0].body), parent: angular.element($document[0].body),
fullscreen: true, fullscreen: true,
targetEvent: $event, targetEvent: $event,

18
ui/src/app/event/event-table.directive.js

@ -36,8 +36,8 @@ export default function EventTableDirective($compile, $templateCache, $rootScope
for (var type in types.eventType) { for (var type in types.eventType) {
var eventType = types.eventType[type]; var eventType = types.eventType[type];
var enabled = true; var enabled = true;
for (var disabledType in disabledEventTypes) { for (var i=0;i<disabledEventTypes.length;i++) {
if (eventType.value === disabledEventTypes[disabledType]) { if (eventType.value === disabledEventTypes[i]) {
enabled = false; enabled = false;
break; break;
} }
@ -47,7 +47,19 @@ export default function EventTableDirective($compile, $templateCache, $rootScope
} }
} }
} else { } else {
scope.eventTypes = types.eventType; scope.eventTypes = angular.copy(types.eventType);
}
if (attrs.debugEventTypes) {
var debugEventTypes = attrs.debugEventTypes.split(',');
for (i=0;i<debugEventTypes.length;i++) {
for (type in types.debugEventType) {
eventType = types.debugEventType[type];
if (eventType.value === debugEventTypes[i]) {
scope.eventTypes[type] = eventType;
}
}
}
} }
scope.eventType = attrs.defaultEventType; scope.eventType = attrs.defaultEventType;

15
ui/src/app/locale/locale.constant.js

@ -341,6 +341,11 @@ export default angular.module('thingsboard.locale', [])
"enter-password": "Enter password", "enter-password": "Enter password",
"enter-search": "Enter search" "enter-search": "Enter search"
}, },
"content-type": {
"json": "Json",
"text": "Text",
"binary": "Binary (Base64)"
},
"customer": { "customer": {
"customer": "Customer", "customer": "Customer",
"customers": "Customers", "customers": "Customers",
@ -762,6 +767,8 @@ export default angular.module('thingsboard.locale', [])
"type-error": "Error", "type-error": "Error",
"type-lc-event": "Lifecycle event", "type-lc-event": "Lifecycle event",
"type-stats": "Statistics", "type-stats": "Statistics",
"type-debug-rule-node": "Debug",
"type-debug-rule-chain": "Debug",
"no-events-prompt": "No events found", "no-events-prompt": "No events found",
"error": "Error", "error": "Error",
"alarm": "Alarm", "alarm": "Alarm",
@ -769,6 +776,13 @@ export default angular.module('thingsboard.locale', [])
"server": "Server", "server": "Server",
"body": "Body", "body": "Body",
"method": "Method", "method": "Method",
"type": "Type",
"entity": "Entity",
"message-id": "Message Id",
"message-type": "Message Type",
"data-type": "Data Type",
"metadata": "Metadata",
"data": "Data",
"event": "Event", "event": "Event",
"status": "Status", "status": "Status",
"success": "Success", "success": "Success",
@ -1172,6 +1186,7 @@ export default angular.module('thingsboard.locale', [])
}, },
"rulenode": { "rulenode": {
"details": "Details", "details": "Details",
"events": "Events",
"add": "Add rule node", "add": "Add rule node",
"name": "Name", "name": "Name",
"name-required": "Name is required.", "name-required": "Name is required.",

15
ui/src/app/rulechain/rulechain.controller.js

@ -28,7 +28,7 @@ import addRuleNodeLinkTemplate from './add-link.tpl.html';
/* eslint-enable import/no-unresolved, import/default */ /* eslint-enable import/no-unresolved, import/default */
/*@ngInject*/ /*@ngInject*/
export function RuleChainController($stateParams, $scope, $compile, $q, $mdUtil, $timeout, $mdExpansionPanel, $document, $mdDialog, export function RuleChainController($stateParams, $scope, $compile, $q, $mdUtil, $timeout, $mdExpansionPanel, $window, $document, $mdDialog,
$filter, $translate, hotkeys, types, ruleChainService, Modelfactory, flowchartConstants, $filter, $translate, hotkeys, types, ruleChainService, Modelfactory, flowchartConstants,
ruleChain, ruleChainMetaData, ruleNodeComponents) { ruleChain, ruleChainMetaData, ruleNodeComponents) {
@ -77,6 +77,8 @@ export function RuleChainController($stateParams, $scope, $compile, $q, $mdUtil,
vm.objectsSelected = objectsSelected; vm.objectsSelected = objectsSelected;
vm.deleteSelected = deleteSelected; vm.deleteSelected = deleteSelected;
vm.triggerResize = triggerResize;
initHotKeys(); initHotKeys();
function initHotKeys() { function initHotKeys() {
@ -129,18 +131,17 @@ export function RuleChainController($stateParams, $scope, $compile, $q, $mdUtil,
} }
vm.onEditRuleNodeClosed = function() { vm.onEditRuleNodeClosed = function() {
vm.editingRuleNode = null; //vm.editingRuleNode = null;
}; };
vm.onEditRuleNodeLinkClosed = function() { vm.onEditRuleNodeLinkClosed = function() {
vm.editingRuleNodeLink = null; //vm.editingRuleNodeLink = null;
}; };
vm.saveRuleNode = function(theForm) { vm.saveRuleNode = function(theForm) {
$scope.$broadcast('form-submit'); $scope.$broadcast('form-submit');
if (theForm.$valid) { if (theForm.$valid) {
theForm.$setPristine(); theForm.$setPristine();
vm.isEditingRuleNode = false;
vm.ruleChainModel.nodes[vm.editingRuleNodeIndex] = vm.editingRuleNode; vm.ruleChainModel.nodes[vm.editingRuleNodeIndex] = vm.editingRuleNode;
vm.editingRuleNode = angular.copy(vm.editingRuleNode); vm.editingRuleNode = angular.copy(vm.editingRuleNode);
} }
@ -148,7 +149,6 @@ export function RuleChainController($stateParams, $scope, $compile, $q, $mdUtil,
vm.saveRuleNodeLink = function(theForm) { vm.saveRuleNodeLink = function(theForm) {
theForm.$setPristine(); theForm.$setPristine();
vm.isEditingRuleNodeLink = false;
vm.ruleChainModel.edges[vm.editingRuleNodeLinkIndex] = vm.editingRuleNodeLink; vm.ruleChainModel.edges[vm.editingRuleNodeLinkIndex] = vm.editingRuleNodeLink;
vm.editingRuleNodeLink = angular.copy(vm.editingRuleNodeLink); vm.editingRuleNodeLink = angular.copy(vm.editingRuleNodeLink);
}; };
@ -663,6 +663,11 @@ export function RuleChainController($stateParams, $scope, $compile, $q, $mdUtil,
function deleteSelected() { function deleteSelected() {
vm.modelservice.deleteSelected(); vm.modelservice.deleteSelected();
} }
function triggerResize() {
var w = angular.element($window);
w.triggerHandler('resize');
}
} }
/*@ngInject*/ /*@ngInject*/

18
ui/src/app/rulechain/rulechain.tpl.html

@ -67,8 +67,9 @@
header-title="{{vm.editingRuleNode.name}}" header-title="{{vm.editingRuleNode.name}}"
header-subtitle="{{(vm.types.ruleNodeType[vm.editingRuleNode.component.type].name | translate) header-subtitle="{{(vm.types.ruleNodeType[vm.editingRuleNode.component.type].name | translate)
+ ' - ' + vm.editingRuleNode.component.name}}" + ' - ' + vm.editingRuleNode.component.name}}"
is-read-only="false" is-read-only="vm.selectedRuleNodeTabIndex > 0"
is-open="vm.isEditingRuleNode" is-open="vm.isEditingRuleNode"
close-on-click-outside="true"
is-always-edit="true" is-always-edit="true"
on-close-details="vm.onEditRuleNodeClosed()" on-close-details="vm.onEditRuleNodeClosed()"
on-toggle-details-edit-mode="vm.onRevertRuleNodeEdit(vm.ruleNodeForm)" on-toggle-details-edit-mode="vm.onRevertRuleNodeEdit(vm.ruleNodeForm)"
@ -77,9 +78,10 @@
<details-buttons tb-help="vm.helpLinkIdForRuleNodeType()" help-container-id="help-container"> <details-buttons tb-help="vm.helpLinkIdForRuleNodeType()" help-container-id="help-container">
<div id="help-container"></div> <div id="help-container"></div>
</details-buttons> </details-buttons>
<md-tabs id="ruleNodeTabs" md-border-bottom flex class="tb-absolute-fill"> <md-tabs md-selected="vm.selectedRuleNodeTabIndex"
id="ruleNodeTabs" md-border-bottom flex class="tb-absolute-fill" ng-if="vm.isEditingRuleNode">
<md-tab label="{{ 'rulenode.details' | translate }}"> <md-tab label="{{ 'rulenode.details' | translate }}">
<form name="vm.ruleNodeForm" ng-if="vm.isEditingRuleNode"> <form name="vm.ruleNodeForm">
<tb-rule-node <tb-rule-node
rule-node="vm.editingRuleNode" rule-node="vm.editingRuleNode"
rule-chain-id="vm.ruleChain.id.id" rule-chain-id="vm.ruleChain.id.id"
@ -90,6 +92,15 @@
</tb-rule-node> </tb-rule-node>
</form> </form>
</md-tab> </md-tab>
<md-tab ng-if="vm.isEditingRuleNode && vm.editingRuleNode.ruleNodeId"
md-on-select="vm.triggerResize()" label="{{ 'rulenode.events' | translate }}">
<tb-event-table flex entity-type="vm.types.entityType.rulenode"
entity-id="vm.editingRuleNode.ruleNodeId.id"
tenant-id="vm.ruleChain.tenantId.id"
debug-event-types="{{vm.types.debugEventType.debugRuleNode.value}}"
default-event-type="{{vm.types.debugEventType.debugRuleNode.value}}">
</tb-event-table>
</md-tab>
</md-tabs> </md-tabs>
</tb-details-sidenav> </tb-details-sidenav>
<tb-details-sidenav class="tb-rulenode-link-details-sidenav" <tb-details-sidenav class="tb-rulenode-link-details-sidenav"
@ -97,6 +108,7 @@
header-subtitle="{{'rulenode.link-details' | translate}}" header-subtitle="{{'rulenode.link-details' | translate}}"
is-read-only="false" is-read-only="false"
is-open="vm.isEditingRuleNodeLink" is-open="vm.isEditingRuleNodeLink"
close-on-click-outside="true"
is-always-edit="true" is-always-edit="true"
on-close-details="vm.onEditRuleNodeLinkClosed()" on-close-details="vm.onEditRuleNodeLinkClosed()"
on-toggle-details-edit-mode="vm.onRevertRuleNodeLinkEdit(vm.ruleNodeLinkForm)" on-toggle-details-edit-mode="vm.onRevertRuleNodeLinkEdit(vm.ruleNodeLinkForm)"

3
ui/src/app/rulechain/rulechains.tpl.html

@ -55,7 +55,8 @@
<tb-event-table flex entity-type="vm.types.entityType.rulechain" <tb-event-table flex entity-type="vm.types.entityType.rulechain"
entity-id="vm.grid.operatingItem().id.id" entity-id="vm.grid.operatingItem().id.id"
tenant-id="vm.grid.operatingItem().tenantId.id" tenant-id="vm.grid.operatingItem().tenantId.id"
default-event-type="{{vm.types.eventType.lcEvent.value}}"> debug-event-types="{{vm.types.debugEventType.debugRuleChain.value}}"
default-event-type="{{vm.types.debugEventType.debugRuleChain.value}}">
</tb-event-table> </tb-event-table>
</md-tab> </md-tab>
<md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode && vm.isRuleChainEditable(vm.grid.operatingItem())" md-on-select="vm.grid.triggerResize()" label="{{ 'relation.relations' | translate }}"> <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode && vm.isRuleChainEditable(vm.grid.operatingItem())" md-on-select="vm.grid.triggerResize()" label="{{ 'relation.relations' | translate }}">

Loading…
Cancel
Save