+
-
function({{ functionArgsString }}) {
+
- }
-
-
\ No newline at end of file
+
+
+
diff --git a/ui/src/app/locale/locale.constant.js b/ui/src/app/locale/locale.constant.js
index 5dce7872e8..b511b56c33 100644
--- a/ui/src/app/locale/locale.constant.js
+++ b/ui/src/app/locale/locale.constant.js
@@ -1198,7 +1198,9 @@ export default angular.module('thingsboard.locale', [])
"type-action": "Action",
"type-action-details": "Perform special action",
"type-rule-chain": "Rule Chain",
- "type-rule-chain-details": "Forwards incoming messages to specified Rule Chain"
+ "type-rule-chain-details": "Forwards incoming messages to specified Rule Chain",
+ "directive-is-not-loaded": "Defined configuration directive '{{directiveName}}' is not available.",
+ "ui-resources-load-error": "Failed to load configuration ui resources."
},
"rule-plugin": {
"management": "Rules and plugins management"
diff --git a/ui/src/app/rulechain/index.js b/ui/src/app/rulechain/index.js
index 7306762572..c674467d35 100644
--- a/ui/src/app/rulechain/index.js
+++ b/ui/src/app/rulechain/index.js
@@ -18,6 +18,8 @@ import RuleChainRoutes from './rulechain.routes';
import RuleChainsController from './rulechains.controller';
import {RuleChainController, AddRuleNodeController, AddRuleNodeLinkController} from './rulechain.controller';
import RuleChainDirective from './rulechain.directive';
+import RuleNodeDefinedConfigDirective from './rulenode-defined-config.directive';
+import RuleNodeConfigDirective from './rulenode-config.directive';
import RuleNodeDirective from './rulenode.directive';
import LinkDirective from './link.directive';
@@ -28,6 +30,8 @@ export default angular.module('thingsboard.ruleChain', [])
.controller('AddRuleNodeController', AddRuleNodeController)
.controller('AddRuleNodeLinkController', AddRuleNodeLinkController)
.directive('tbRuleChain', RuleChainDirective)
+ .directive('tbRuleNodeDefinedConfig', RuleNodeDefinedConfigDirective)
+ .directive('tbRuleNodeConfig', RuleNodeConfigDirective)
.directive('tbRuleNode', RuleNodeDirective)
.directive('tbRuleNodeLink', LinkDirective)
.name;
diff --git a/ui/src/app/rulechain/rulechain.controller.js b/ui/src/app/rulechain/rulechain.controller.js
index 4eba5b2c52..dd48bb007a 100644
--- a/ui/src/app/rulechain/rulechain.controller.js
+++ b/ui/src/app/rulechain/rulechain.controller.js
@@ -137,10 +137,13 @@ export function RuleChainController($stateParams, $scope, $compile, $q, $mdUtil,
};
vm.saveRuleNode = function(theForm) {
- theForm.$setPristine();
- vm.isEditingRuleNode = false;
- vm.ruleChainModel.nodes[vm.editingRuleNodeIndex] = vm.editingRuleNode;
- vm.editingRuleNode = angular.copy(vm.editingRuleNode);
+ $scope.$broadcast('form-submit');
+ if (theForm.$valid) {
+ theForm.$setPristine();
+ vm.isEditingRuleNode = false;
+ vm.ruleChainModel.nodes[vm.editingRuleNodeIndex] = vm.editingRuleNode;
+ vm.editingRuleNode = angular.copy(vm.editingRuleNode);
+ }
};
vm.saveRuleNodeLink = function(theForm) {
@@ -309,7 +312,7 @@ export function RuleChainController($stateParams, $scope, $compile, $q, $mdUtil,
var componentType = ruleNodeComponent.type;
var model = vm.ruleNodeTypesModel[componentType].model;
var node = {
- id: model.nodes.length,
+ id: 'node-lib-' + componentType + '-' + model.nodes.length,
component: ruleNodeComponent,
name: '',
nodeClass: vm.types.ruleNodeType[componentType].nodeClass,
@@ -358,7 +361,7 @@ export function RuleChainController($stateParams, $scope, $compile, $q, $mdUtil,
vm.ruleChainModel.nodes.push(
{
- id: vm.nextNodeID++,
+ id: 'rule-chain-node-' + vm.nextNodeID++,
component: types.inputNodeComponent,
name: "",
nodeClass: types.ruleNodeType.INPUT.nodeClass,
@@ -389,7 +392,7 @@ export function RuleChainController($stateParams, $scope, $compile, $q, $mdUtil,
var component = ruleChainService.getRuleNodeComponentByClazz(ruleNode.type);
if (component) {
var node = {
- id: vm.nextNodeID++,
+ id: 'rule-chain-node-' + vm.nextNodeID++,
ruleNodeId: ruleNode.id,
additionalInfo: ruleNode.additionalInfo,
configuration: ruleNode.configuration,
@@ -466,7 +469,7 @@ export function RuleChainController($stateParams, $scope, $compile, $q, $mdUtil,
var ruleChainNode = ruleChainNodesMap[ruleChainConnection.additionalInfo.ruleChainNodeId];
if (!ruleChainNode) {
ruleChainNode = {
- id: vm.nextNodeID++,
+ id: 'rule-chain-node-' + vm.nextNodeID++,
additionalInfo: ruleChainConnection.additionalInfo,
targetRuleChainId: ruleChainConnection.targetRuleChainId.id,
x: ruleChainConnection.additionalInfo.layoutX,
@@ -611,7 +614,7 @@ export function RuleChainController($stateParams, $scope, $compile, $q, $mdUtil,
fullscreen: true,
targetEvent: $event
}).then(function (ruleNode) {
- ruleNode.id = vm.nextNodeID++;
+ ruleNode.id = 'rule-chain-node-' + vm.nextNodeID++;
ruleNode.connectors = [];
if (ruleNode.component.configurationDescriptor.nodeDefinition.inEnabled) {
ruleNode.connectors.push(
diff --git a/ui/src/app/rulechain/rulenode-config.directive.js b/ui/src/app/rulechain/rulenode-config.directive.js
new file mode 100644
index 0000000000..4b75c793f1
--- /dev/null
+++ b/ui/src/app/rulechain/rulenode-config.directive.js
@@ -0,0 +1,73 @@
+/*
+ * 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.
+ */
+
+/* eslint-disable import/no-unresolved, import/default */
+
+import ruleNodeConfigTemplate from './rulenode-config.tpl.html';
+
+/* eslint-enable import/no-unresolved, import/default */
+
+/*@ngInject*/
+export default function RuleNodeConfigDirective($compile, $templateCache, $injector, $translate) {
+
+ var linker = function (scope, element, attrs, ngModelCtrl) {
+ var template = $templateCache.get(ruleNodeConfigTemplate);
+ element.html(template);
+
+ scope.$watch('configuration', function (newVal, prevVal) {
+ if (!angular.equals(newVal, prevVal)) {
+ ngModelCtrl.$setViewValue(scope.configuration);
+ }
+ });
+
+ ngModelCtrl.$render = function () {
+ scope.configuration = ngModelCtrl.$viewValue;
+ };
+
+ scope.useDefinedDirective = function() {
+ return scope.nodeDefinition.configDirective && !scope.definedDirectiveError;
+ };
+
+ validateDefinedDirective();
+
+ function validateDefinedDirective() {
+ if (scope.nodeDefinition.uiResourceLoadError && scope.nodeDefinition.uiResourceLoadError.length) {
+ scope.definedDirectiveError = scope.nodeDefinition.uiResourceLoadError;
+ } else {
+ var definedDirective = scope.nodeDefinition.configDirective;
+ if (definedDirective && definedDirective.length) {
+ if (!$injector.has(definedDirective + 'Directive')) {
+ scope.definedDirectiveError = $translate.instant('rulenode.directive-is-not-loaded', {directiveName: definedDirective});
+ }
+ }
+ }
+ }
+
+ $compile(element.contents())(scope);
+ };
+
+ return {
+ restrict: "E",
+ require: "^ngModel",
+ scope: {
+ nodeDefinition:'=',
+ required:'=ngRequired',
+ readonly:'=ngReadonly'
+ },
+ link: linker
+ };
+
+}
diff --git a/ui/src/app/rulechain/rulenode-config.tpl.html b/ui/src/app/rulechain/rulenode-config.tpl.html
new file mode 100644
index 0000000000..32d5347b43
--- /dev/null
+++ b/ui/src/app/rulechain/rulenode-config.tpl.html
@@ -0,0 +1,32 @@
+
+
+