Commit 344f6045a64dd2f3ff9aaeade9629868fd63754d

Authored by Igor Kulikov
1 parent a5c59e5c

Use ComponentDescriptors in RuleChain UI

... ... @@ -71,6 +71,7 @@ import javax.servlet.http.HttpServletRequest;
71 71 import javax.servlet.http.HttpServletResponse;
72 72 import java.util.List;
73 73 import java.util.Optional;
  74 +import java.util.Set;
74 75 import java.util.UUID;
75 76
76 77 import static org.thingsboard.server.dao.service.Validator.validateId;
... ... @@ -480,6 +481,15 @@ public abstract class BaseController {
480 481 }
481 482 }
482 483
  484 + List<ComponentDescriptor> checkComponentDescriptorsByTypes(Set<ComponentType> types) throws ThingsboardException {
  485 + try {
  486 + log.debug("[{}] Lookup component descriptors", types);
  487 + return componentDescriptorService.getComponents(types);
  488 + } catch (Exception e) {
  489 + throw handleException(e, false);
  490 + }
  491 + }
  492 +
483 493 List<ComponentDescriptor> checkPluginActionsByPluginClazz(String pluginClazz) throws ThingsboardException {
484 494 try {
485 495 checkComponentDescriptorByClazz(pluginClazz);
... ...
... ... @@ -21,7 +21,9 @@ import org.thingsboard.server.common.data.plugin.ComponentDescriptor;
21 21 import org.thingsboard.server.common.data.plugin.ComponentType;
22 22 import org.thingsboard.server.exception.ThingsboardException;
23 23
  24 +import java.util.HashSet;
24 25 import java.util.List;
  26 +import java.util.Set;
25 27
26 28 @RestController
27 29 @RequestMapping("/api")
... ... @@ -52,6 +54,22 @@ public class ComponentDescriptorController extends BaseController {
52 54 }
53 55
54 56 @PreAuthorize("hasAnyAuthority('SYS_ADMIN','TENANT_ADMIN')")
  57 + @RequestMapping(value = "/components", params = {"componentTypes"}, method = RequestMethod.GET)
  58 + @ResponseBody
  59 + public List<ComponentDescriptor> getComponentDescriptorsByTypes(@RequestParam("componentTypes") String[] strComponentTypes) throws ThingsboardException {
  60 + checkArrayParameter("componentTypes", strComponentTypes);
  61 + try {
  62 + Set<ComponentType> componentTypes = new HashSet<>();
  63 + for (String strComponentType : strComponentTypes) {
  64 + componentTypes.add(ComponentType.valueOf(strComponentType));
  65 + }
  66 + return checkComponentDescriptorsByTypes(componentTypes);
  67 + } catch (Exception e) {
  68 + throw handleException(e);
  69 + }
  70 + }
  71 +
  72 + @PreAuthorize("hasAnyAuthority('SYS_ADMIN','TENANT_ADMIN')")
55 73 @RequestMapping(value = "/components/actions/{pluginClazz:.+}", method = RequestMethod.GET)
56 74 @ResponseBody
57 75 public List<ComponentDescriptor> getPluginActionsByPluginClazz(@PathVariable("pluginClazz") String pluginClazz) throws ThingsboardException {
... ...
... ... @@ -204,6 +204,15 @@ public class AnnotationComponentDiscoveryService implements ComponentDiscoverySe
204 204 }
205 205
206 206 @Override
  207 + public List<ComponentDescriptor> getComponents(Set<ComponentType> types) {
  208 + List<ComponentDescriptor> result = new ArrayList<>();
  209 + for (ComponentType type : types) {
  210 + result.addAll(componentsMap.get(type));
  211 + }
  212 + return Collections.unmodifiableList(result);
  213 + }
  214 +
  215 + @Override
207 216 public Optional<ComponentDescriptor> getComponent(String clazz) {
208 217 return Optional.ofNullable(components.get(clazz));
209 218 }
... ...
... ... @@ -20,6 +20,7 @@ import org.thingsboard.server.common.data.plugin.ComponentType;
20 20
21 21 import java.util.List;
22 22 import java.util.Optional;
  23 +import java.util.Set;
23 24
24 25 /**
25 26 * @author Andrew Shvayka
... ... @@ -30,6 +31,8 @@ public interface ComponentDiscoveryService {
30 31
31 32 List<ComponentDescriptor> getComponents(ComponentType type);
32 33
  34 + List<ComponentDescriptor> getComponents(Set<ComponentType> types);
  35 +
33 36 Optional<ComponentDescriptor> getComponent(String clazz);
34 37
35 38 List<ComponentDescriptor> getPluginActions(String pluginClazz);
... ...
... ... @@ -26,7 +26,8 @@ function ComponentDescriptorService($http, $q) {
26 26 var service = {
27 27 getComponentDescriptorsByType: getComponentDescriptorsByType,
28 28 getComponentDescriptorByClazz: getComponentDescriptorByClazz,
29   - getPluginActionsByPluginClazz: getPluginActionsByPluginClazz
  29 + getPluginActionsByPluginClazz: getPluginActionsByPluginClazz,
  30 + getComponentDescriptorsByTypes: getComponentDescriptorsByTypes
30 31 }
31 32
32 33 return service;
... ... @@ -52,6 +53,41 @@ function ComponentDescriptorService($http, $q) {
52 53 return deferred.promise;
53 54 }
54 55
  56 + function getComponentDescriptorsByTypes(componentTypes) {
  57 + var deferred = $q.defer();
  58 + var result = [];
  59 + for (var i=componentTypes.length-1;i>=0;i--) {
  60 + var componentType = componentTypes[i];
  61 + if (componentsByType[componentType]) {
  62 + result = result.concat(componentsByType[componentType]);
  63 + componentTypes.splice(i, 1);
  64 + }
  65 + }
  66 + if (!componentTypes.length) {
  67 + deferred.resolve(result);
  68 + } else {
  69 + var url = '/api/components?componentTypes=' + componentTypes.join(',');
  70 + $http.get(url, null).then(function success(response) {
  71 + var components = response.data;
  72 + for (var i = 0; i < components.length; i++) {
  73 + var component = components[i];
  74 + var componentsList = componentsByType[component.type];
  75 + if (!componentsList) {
  76 + componentsList = [];
  77 + componentsByType[component.type] = componentsList;
  78 + }
  79 + componentsList.push(component);
  80 + componentsByClazz[component.clazz] = component;
  81 + }
  82 + result = result.concat(components);
  83 + deferred.resolve(components);
  84 + }, function fail() {
  85 + deferred.reject();
  86 + });
  87 + }
  88 + return deferred.promise;
  89 + }
  90 +
55 91 function getComponentDescriptorByClazz(componentDescriptorClazz) {
56 92 var deferred = $q.defer();
57 93 if (componentsByClazz[componentDescriptorClazz]) {
... ...
... ... @@ -17,9 +17,9 @@ export default angular.module('thingsboard.api.ruleChain', [])
17 17 .factory('ruleChainService', RuleChainService).name;
18 18
19 19 /*@ngInject*/
20   -function RuleChainService($http, $q, $filter, types) {
  20 +function RuleChainService($http, $q, $filter, types, componentDescriptorService) {
21 21
22   - var ruleNodeTypes = null;
  22 + var ruleNodeComponents = null;
23 23
24 24 var service = {
25 25 getSystemRuleChains: getSystemRuleChains,
... ... @@ -30,8 +30,8 @@ function RuleChainService($http, $q, $filter, types) {
30 30 deleteRuleChain: deleteRuleChain,
31 31 getRuleChainMetaData: getRuleChainMetaData,
32 32 saveRuleChainMetaData: saveRuleChainMetaData,
33   - getRuleNodeTypes: getRuleNodeTypes,
34   - getRuleNodeComponentType: getRuleNodeComponentType,
  33 + getRuleNodeComponents: getRuleNodeComponents,
  34 + getRuleNodeComponentByClazz: getRuleNodeComponentByClazz,
35 35 getRuleNodeSupportedLinks: getRuleNodeSupportedLinks,
36 36 resolveTargetRuleChains: resolveTargetRuleChains
37 37 };
... ... @@ -165,21 +165,18 @@ function RuleChainService($http, $q, $filter, types) {
165 165 return deferred.promise;
166 166 }
167 167
168   - function getRuleNodeTypes() {
  168 + function getRuleNodeComponents() {
169 169 var deferred = $q.defer();
170   - if (ruleNodeTypes) {
171   - deferred.resolve(ruleNodeTypes);
  170 + if (ruleNodeComponents) {
  171 + deferred.resolve(ruleNodeComponents);
172 172 } else {
173   - loadRuleNodeTypes().then(
174   - (nodeTypes) => {
175   - ruleNodeTypes = nodeTypes;
176   - ruleNodeTypes.push(
177   - {
178   - nodeType: types.ruleNodeType.RULE_CHAIN.value,
179   - type: 'Rule chain'
180   - }
  173 + loadRuleNodeComponents().then(
  174 + (components) => {
  175 + ruleNodeComponents = components;
  176 + ruleNodeComponents.push(
  177 + types.ruleChainNodeComponent
181 178 );
182   - deferred.resolve(ruleNodeTypes);
  179 + deferred.resolve(ruleNodeComponents);
183 180 },
184 181 () => {
185 182 deferred.reject();
... ... @@ -189,10 +186,10 @@ function RuleChainService($http, $q, $filter, types) {
189 186 return deferred.promise;
190 187 }
191 188
192   - function getRuleNodeComponentType(type) {
193   - var res = $filter('filter')(ruleNodeTypes, {type: type}, true);
  189 + function getRuleNodeComponentByClazz(clazz) {
  190 + var res = $filter('filter')(ruleNodeComponents, {clazz: clazz}, true);
194 191 if (res && res.length) {
195   - return res[0].nodeType;
  192 + return res[0];
196 193 }
197 194 return null;
198 195 }
... ... @@ -222,61 +219,8 @@ function RuleChainService($http, $q, $filter, types) {
222 219 return deferred.promise;
223 220 }
224 221
225   - function loadRuleNodeTypes() {
226   - var deferred = $q.defer();
227   - deferred.resolve(
228   - [
229   - {
230   - nodeType: types.ruleNodeType.FILTER.value,
231   - type: 'Filter'
232   - },
233   - {
234   - nodeType: types.ruleNodeType.FILTER.value,
235   - type: 'Switch'
236   - },
237   - {
238   - nodeType: types.ruleNodeType.ENRICHMENT.value,
239   - type: 'Self'
240   - },
241   - {
242   - nodeType: types.ruleNodeType.ENRICHMENT.value,
243   - type: 'Tenant/Customer'
244   - },
245   - {
246   - nodeType: types.ruleNodeType.ENRICHMENT.value,
247   - type: 'Related Entity'
248   - },
249   - {
250   - nodeType: types.ruleNodeType.ENRICHMENT.value,
251   - type: 'Last Telemetry'
252   - },
253   - {
254   - nodeType: types.ruleNodeType.TRANSFORMATION.value,
255   - type: 'Modify'
256   - },
257   - {
258   - nodeType: types.ruleNodeType.TRANSFORMATION.value,
259   - type: 'New/Update'
260   - },
261   - {
262   - nodeType: types.ruleNodeType.ACTION.value,
263   - type: 'Telemetry'
264   - },
265   - {
266   - nodeType: types.ruleNodeType.ACTION.value,
267   - type: 'RPC call'
268   - },
269   - {
270   - nodeType: types.ruleNodeType.ACTION.value,
271   - type: 'Send email'
272   - },
273   - {
274   - nodeType: types.ruleNodeType.ACTION.value,
275   - type: 'Alarm'
276   - }
277   - ]
278   - );
279   - return deferred.promise;
  222 + function loadRuleNodeComponents() {
  223 + return componentDescriptorService.getComponentDescriptorsByTypes(types.ruleNodeTypeComponentTypes);
280 224 }
281 225
282 226
... ...
... ... @@ -457,6 +457,17 @@ export default angular.module('thingsboard.types', [])
457 457 clientSide: false
458 458 }
459 459 },
  460 + ruleNodeTypeComponentTypes: ["FILTER", "ENRICHMENT", "TRANSFORMATION", "ACTION"],
  461 + ruleChainNodeComponent: {
  462 + type: 'RULE_CHAIN',
  463 + name: 'Rule chain',
  464 + clazz: 'tb.internal.RuleChain'
  465 + },
  466 + inputNodeComponent: {
  467 + type: 'INPUT',
  468 + name: 'Input',
  469 + clazz: 'tb.internal.Input'
  470 + },
460 471 ruleNodeType: {
461 472 FILTER: {
462 473 value: "FILTER",
... ...
... ... @@ -1167,7 +1167,8 @@ export default angular.module('thingsboard.locale', [])
1167 1167 "select-rulechain": "Select rule chain",
1168 1168 "no-rulechains-matching": "No rule chains matching '{{entity}}' were found.",
1169 1169 "rulechain-required": "Rule chain is required",
1170   - "management": "Rules management"
  1170 + "management": "Rules management",
  1171 + "debug-mode": "Debug mode"
1171 1172 },
1172 1173 "rulenode": {
1173 1174 "add": "Add rule node",
... ... @@ -1177,6 +1178,7 @@ export default angular.module('thingsboard.locale', [])
1177 1178 "description": "Description",
1178 1179 "delete": "Delete rule node",
1179 1180 "rulenode-details": "Rule node details",
  1181 + "debug-mode": "Debug mode",
1180 1182 "link-details": "Rule node link details",
1181 1183 "add-link": "Add link",
1182 1184 "link-label": "Link label",
... ...
... ... @@ -42,6 +42,11 @@
42 42 </div>
43 43 </md-input-container>
44 44 <md-input-container class="md-block">
  45 + <md-checkbox ng-disabled="$root.loading || !isEdit" aria-label="{{ 'rulechain.debug-mode' | translate }}"
  46 + ng-model="ruleChain.debugMode">{{ 'rulechain.debug-mode' | translate }}
  47 + </md-checkbox>
  48 + </md-input-container>
  49 + <md-input-container class="md-block">
45 50 <label translate>rulechain.description</label>
46 51 <textarea ng-model="ruleChain.additionalInfo.description" rows="2"></textarea>
47 52 </md-input-container>
... ...
... ... @@ -54,6 +54,7 @@ export function RuleChainController($stateParams, $scope, $q, $mdUtil, $mdExpans
54 54 };
55 55
56 56 vm.ruleNodeTypesModel = {};
  57 + vm.ruleChainLibraryLoaded = false;
57 58 for (var type in types.ruleNodeType) {
58 59 if (!types.ruleNodeType[type].special) {
59 60 vm.ruleNodeTypesModel[type] = {
... ... @@ -141,8 +142,8 @@ export function RuleChainController($stateParams, $scope, $q, $mdUtil, $mdExpans
141 142 vm.editCallbacks = {
142 143 edgeDoubleClick: function (event, edge) {
143 144 var sourceNode = vm.modelservice.nodes.getNodeByConnectorId(edge.source);
144   - if (sourceNode.nodeType != types.ruleNodeType.INPUT.value) {
145   - ruleChainService.getRuleNodeSupportedLinks(sourceNode.type).then(
  145 + if (sourceNode.component.type != types.ruleNodeType.INPUT.value) {
  146 + ruleChainService.getRuleNodeSupportedLinks(sourceNode.component.clazz).then(
146 147 (labels) => {
147 148 vm.isEditingRuleNode = false;
148 149 vm.editingRuleNode = null;
... ... @@ -156,7 +157,7 @@ export function RuleChainController($stateParams, $scope, $q, $mdUtil, $mdExpans
156 157 },
157 158 nodeCallbacks: {
158 159 'doubleClick': function (event, node) {
159   - if (node.nodeType != types.ruleNodeType.INPUT.value) {
  160 + if (node.component.type != types.ruleNodeType.INPUT.value) {
160 161 vm.isEditingRuleNodeLink = false;
161 162 vm.editingRuleNodeLink = null;
162 163 vm.isEditingRuleNode = true;
... ... @@ -171,9 +172,9 @@ export function RuleChainController($stateParams, $scope, $q, $mdUtil, $mdExpans
171 172 createEdge: function (event, edge) {
172 173 var deferred = $q.defer();
173 174 var sourceNode = vm.modelservice.nodes.getNodeByConnectorId(edge.source);
174   - if (sourceNode.nodeType == types.ruleNodeType.INPUT.value) {
  175 + if (sourceNode.component.type == types.ruleNodeType.INPUT.value) {
175 176 var destNode = vm.modelservice.nodes.getNodeByConnectorId(edge.destination);
176   - if (destNode.nodeType == types.ruleNodeType.RULE_CHAIN.value) {
  177 + if (destNode.component.type == types.ruleNodeType.RULE_CHAIN.value) {
177 178 deferred.reject();
178 179 } else {
179 180 var res = $filter('filter')(vm.ruleChainModel.edges, {source: vm.inputConnectorId});
... ... @@ -183,7 +184,7 @@ export function RuleChainController($stateParams, $scope, $q, $mdUtil, $mdExpans
183 184 deferred.resolve(edge);
184 185 }
185 186 } else {
186   - ruleChainService.getRuleNodeSupportedLinks(sourceNode.type).then(
  187 + ruleChainService.getRuleNodeSupportedLinks(sourceNode.component.clazz).then(
187 188 (labels) => {
188 189 addRuleNodeLink(event, edge, labels).then(
189 190 (link) => {
... ... @@ -209,24 +210,23 @@ export function RuleChainController($stateParams, $scope, $q, $mdUtil, $mdExpans
209 210 loadRuleChainLibrary();
210 211
211 212 function loadRuleChainLibrary() {
212   - ruleChainService.getRuleNodeTypes().then(
213   - (ruleNodeTypes) => {
214   - for (var i=0;i<ruleNodeTypes.length;i++) {
215   - var ruleNodeType = ruleNodeTypes[i];
216   - var nodeType = ruleNodeType.nodeType;
217   - var model = vm.ruleNodeTypesModel[nodeType].model;
  213 + ruleChainService.getRuleNodeComponents().then(
  214 + (ruleNodeComponents) => {
  215 + for (var i=0;i<ruleNodeComponents.length;i++) {
  216 + var ruleNodeComponent = ruleNodeComponents[i];
  217 + var componentType = ruleNodeComponent.type;
  218 + var model = vm.ruleNodeTypesModel[componentType].model;
218 219 var node = {
219 220 id: model.nodes.length,
220   - nodeType: nodeType,
221   - type: ruleNodeType.type,
  221 + component: ruleNodeComponent,
222 222 name: '',
223   - nodeClass: vm.types.ruleNodeType[nodeType].nodeClass,
224   - icon: vm.types.ruleNodeType[nodeType].icon,
  223 + nodeClass: vm.types.ruleNodeType[componentType].nodeClass,
  224 + icon: vm.types.ruleNodeType[componentType].icon,
225 225 x: 30,
226 226 y: 10+50*model.nodes.length,
227 227 connectors: []
228 228 };
229   - if (nodeType == types.ruleNodeType.RULE_CHAIN.value) {
  229 + if (componentType == types.ruleNodeType.RULE_CHAIN.value) {
230 230 node.connectors.push(
231 231 {
232 232 type: flowchartConstants.leftConnectorType,
... ... @@ -249,6 +249,7 @@ export function RuleChainController($stateParams, $scope, $q, $mdUtil, $mdExpans
249 249 }
250 250 model.nodes.push(node);
251 251 }
  252 + vm.ruleChainLibraryLoaded = true;
252 253 prepareRuleChain();
253 254 }
254 255 );
... ... @@ -273,9 +274,8 @@ export function RuleChainController($stateParams, $scope, $q, $mdUtil, $mdExpans
273 274 vm.ruleChainModel.nodes.push(
274 275 {
275 276 id: vm.nextNodeID++,
276   - type: "Input",
  277 + component: types.inputNodeComponent,
277 278 name: "",
278   - nodeType: types.ruleNodeType.INPUT.value,
279 279 nodeClass: types.ruleNodeType.INPUT.nodeClass,
280 280 icon: types.ruleNodeType.INPUT.icon,
281 281 readonly: true,
... ... @@ -301,20 +301,20 @@ export function RuleChainController($stateParams, $scope, $q, $mdUtil, $mdExpans
301 301 var nodes = [];
302 302 for (var i=0;i<vm.ruleChainMetaData.nodes.length;i++) {
303 303 var ruleNode = vm.ruleChainMetaData.nodes[i];
304   - var nodeType = ruleChainService.getRuleNodeComponentType(ruleNode.type);
305   - if (nodeType) {
  304 + var component = ruleChainService.getRuleNodeComponentByClazz(ruleNode.type);
  305 + if (component) {
306 306 var node = {
307 307 id: vm.nextNodeID++,
308 308 ruleNodeId: ruleNode.id,
309 309 additionalInfo: ruleNode.additionalInfo,
310 310 configuration: ruleNode.configuration,
  311 + debugMode: ruleNode.debugMode,
311 312 x: ruleNode.additionalInfo.layoutX,
312 313 y: ruleNode.additionalInfo.layoutY,
313   - type: ruleNode.type,
  314 + component: component,
314 315 name: ruleNode.name,
315   - nodeType: nodeType,
316   - nodeClass: vm.types.ruleNodeType[nodeType].nodeClass,
317   - icon: vm.types.ruleNodeType[nodeType].icon,
  316 + nodeClass: vm.types.ruleNodeType[component.type].nodeClass,
  317 + icon: vm.types.ruleNodeType[component.type].icon,
318 318 connectors: [
319 319 {
320 320 type: flowchartConstants.leftConnectorType,
... ... @@ -347,7 +347,7 @@ export function RuleChainController($stateParams, $scope, $q, $mdUtil, $mdExpans
347 347
348 348 if (vm.ruleChainMetaData.connections) {
349 349 for (i = 0; i < vm.ruleChainMetaData.connections.length; i++) {
350   - var connection = vm.ruleChainMetaData.connections[0];
  350 + var connection = vm.ruleChainMetaData.connections[i];
351 351 var sourceNode = nodes[connection.fromIndex];
352 352 destNode = nodes[connection.toIndex];
353 353 if (sourceNode && destNode) {
... ... @@ -379,9 +379,8 @@ export function RuleChainController($stateParams, $scope, $q, $mdUtil, $mdExpans
379 379 targetRuleChainId: ruleChainConnection.targetRuleChainId.id,
380 380 x: ruleChainConnection.additionalInfo.layoutX,
381 381 y: ruleChainConnection.additionalInfo.layoutY,
382   - type: 'Rule chain',
  382 + component: types.ruleChainNodeComponent,
383 383 name: ruleChain.name,
384   - nodeType: vm.types.ruleNodeType.RULE_CHAIN.value,
385 384 nodeClass: vm.types.ruleNodeType.RULE_CHAIN.nodeClass,
386 385 icon: vm.types.ruleNodeType.RULE_CHAIN.icon,
387 386 connectors: [
... ... @@ -410,7 +409,9 @@ export function RuleChainController($stateParams, $scope, $q, $mdUtil, $mdExpans
410 409 }
411 410 }
412 411
413   - vm.canvasControl.adjustCanvasSize();
  412 + if (vm.canvasControl.adjustCanvasSize) {
  413 + vm.canvasControl.adjustCanvasSize();
  414 + }
414 415
415 416 vm.isDirty = false;
416 417
... ... @@ -437,15 +438,16 @@ export function RuleChainController($stateParams, $scope, $q, $mdUtil, $mdExpans
437 438
438 439 for (var i=0;i<vm.ruleChainModel.nodes.length;i++) {
439 440 var node = vm.ruleChainModel.nodes[i];
440   - if (node.nodeType != types.ruleNodeType.INPUT.value && node.nodeType != types.ruleNodeType.RULE_CHAIN.value) {
  441 + if (node.component.type != types.ruleNodeType.INPUT.value && node.component.type != types.ruleNodeType.RULE_CHAIN.value) {
441 442 var ruleNode = {};
442 443 if (node.ruleNodeId) {
443 444 ruleNode.id = node.ruleNodeId;
444 445 }
445   - ruleNode.type = node.type;
  446 + ruleNode.type = node.component.clazz;
446 447 ruleNode.name = node.name;
447 448 ruleNode.configuration = node.configuration;
448 449 ruleNode.additionalInfo = node.additionalInfo;
  450 + ruleNode.debugMode = node.debugMode;
449 451 if (!ruleNode.additionalInfo) {
450 452 ruleNode.additionalInfo = {};
451 453 }
... ... @@ -465,9 +467,9 @@ export function RuleChainController($stateParams, $scope, $q, $mdUtil, $mdExpans
465 467 var edge = vm.ruleChainModel.edges[i];
466 468 var sourceNode = vm.modelservice.nodes.getNodeByConnectorId(edge.source);
467 469 var destNode = vm.modelservice.nodes.getNodeByConnectorId(edge.destination);
468   - if (sourceNode.nodeType != types.ruleNodeType.INPUT.value) {
  470 + if (sourceNode.component.type != types.ruleNodeType.INPUT.value) {
469 471 var fromIndex = nodes.indexOf(sourceNode);
470   - if (destNode.nodeType == types.ruleNodeType.RULE_CHAIN.value) {
  472 + if (destNode.component.type == types.ruleNodeType.RULE_CHAIN.value) {
471 473 var ruleChainConnection = {
472 474 fromIndex: fromIndex,
473 475 targetRuleChainId: {entityType: vm.types.entityType.rulechain, id: destNode.targetRuleChainId},
... ... @@ -522,7 +524,7 @@ export function RuleChainController($stateParams, $scope, $q, $mdUtil, $mdExpans
522 524 type: flowchartConstants.leftConnectorType
523 525 }
524 526 );
525   - if (ruleNode.nodeType != types.ruleNodeType.RULE_CHAIN.value) {
  527 + if (ruleNode.component.type != types.ruleNodeType.RULE_CHAIN.value) {
526 528 ruleNode.connectors.push(
527 529 {
528 530 id: vm.nextConnectorID++,
... ...
... ... @@ -21,7 +21,7 @@
21 21 <section class="tb-rulechain-container" flex layout="column">
22 22 <div class="tb-rulechain-layout" flex layout="row">
23 23 <div class="tb-rulechain-library">
24   - <md-expansion-panel-group class="tb-rulechain-library-panel-group" md-component-id="libraryPanelGroup" auto-expand="true" multiple>
  24 + <md-expansion-panel-group ng-if="vm.ruleChainLibraryLoaded" class="tb-rulechain-library-panel-group" md-component-id="libraryPanelGroup" auto-expand="true" multiple>
25 25 <md-expansion-panel md-component-id="{{typeId}}" id="{{typeId}}" ng-repeat="(typeId, typeModel) in vm.ruleNodeTypesModel">
26 26 <md-expansion-panel-collapsed>
27 27 <div class="tb-panel-title" translate>{{vm.types.ruleNodeType[typeId].name}}</div>
... ...
... ... @@ -23,9 +23,9 @@
23 23 <fieldset ng-disabled="$root.loading || !isEdit || isReadOnly">
24 24 <md-input-container class="md-block">
25 25 <label translate>rulenode.type</label>
26   - <input readonly name="type" ng-model="ruleNode.type">
  26 + <input readonly name="type" ng-model="ruleNode.component.name">
27 27 </md-input-container>
28   - <section ng-if="ruleNode.nodeType != types.ruleNodeType.RULE_CHAIN.value">
  28 + <section ng-if="ruleNode.component.type != types.ruleNodeType.RULE_CHAIN.value">
29 29 <md-input-container class="md-block">
30 30 <label translate>rulenode.name</label>
31 31 <input required name="name" ng-model="ruleNode.name">
... ... @@ -34,11 +34,16 @@
34 34 </div>
35 35 </md-input-container>
36 36 <md-input-container class="md-block">
  37 + <md-checkbox ng-disabled="$root.loading || !isEdit" aria-label="{{ 'rulenode.debug-mode' | translate }}"
  38 + ng-model="ruleNode.debugMode">{{ 'rulenode.debug-mode' | translate }}
  39 + </md-checkbox>
  40 + </md-input-container>
  41 + <md-input-container class="md-block">
37 42 <label translate>rulenode.description</label>
38 43 <textarea ng-model="ruleNode.additionalInfo.description" rows="2"></textarea>
39 44 </md-input-container>
40 45 </section>
41   - <section ng-if="ruleNode.nodeType == types.ruleNodeType.RULE_CHAIN.value">
  46 + <section ng-if="ruleNode.component.type == types.ruleNodeType.RULE_CHAIN.value">
42 47 <tb-entity-autocomplete the-form="theForm"
43 48 ng-disabled="$root.loading || !isEdit || isReadOnly"
44 49 tb-required="true"
... ...
... ... @@ -33,7 +33,7 @@ export default function RuleNodeDirective($compile, $templateCache, ruleChainSer
33 33 };
34 34
35 35 scope.$watch('ruleNode', function() {
36   - if (scope.ruleNode && scope.ruleNode.nodeType == types.ruleNodeType.RULE_CHAIN.value) {
  36 + if (scope.ruleNode && scope.ruleNode.component.type == types.ruleNodeType.RULE_CHAIN.value) {
37 37 scope.params.targetRuleChainId = scope.ruleNode.targetRuleChainId;
38 38 watchTargetRuleChain();
39 39 } else {
... ...
... ... @@ -23,7 +23,7 @@
23 23 <md-icon aria-label="node-type-icon" flex="15"
24 24 class="material-icons">{{node.icon}}</md-icon>
25 25 <div layout="column" flex="85" layout-align="center">
26   - <span class="tb-node-type">{{ node.type }}</span>
  26 + <span class="tb-node-type">{{ node.component.name }}</span>
27 27 <span class="tb-node-title" ng-if="node.name">{{ node.name }}</span>
28 28 </div>
29 29 <div class="{{flowchartConstants.leftConnectorClass}}">
... ...