Commit b578402f116bebccb4189ce893036666ba1b1861

Authored by Igor Kulikov
1 parent 164dbd68

Rule chain edit improvements.

@@ -18,17 +18,17 @@ export default angular.module('thingsboard.directives.confirmOnExit', []) @@ -18,17 +18,17 @@ export default angular.module('thingsboard.directives.confirmOnExit', [])
18 .name; 18 .name;
19 19
20 /*@ngInject*/ 20 /*@ngInject*/
21 -function ConfirmOnExit($state, $mdDialog, $window, $filter, userService) { 21 +function ConfirmOnExit($state, $mdDialog, $window, $filter, $parse, userService) {
22 return { 22 return {
23 - link: function ($scope) {  
24 - 23 + link: function ($scope, $element, $attributes) {
  24 + $scope.confirmForm = $scope.$eval($attributes.confirmForm);
25 $window.onbeforeunload = function () { 25 $window.onbeforeunload = function () {
26 - if (userService.isAuthenticated() && (($scope.confirmForm && $scope.confirmForm.$dirty) || $scope.isDirty)) { 26 + if (userService.isAuthenticated() && (($scope.confirmForm && $scope.confirmForm.$dirty) || $scope.$eval($attributes.isDirty))) {
27 return $filter('translate')('confirm-on-exit.message'); 27 return $filter('translate')('confirm-on-exit.message');
28 } 28 }
29 } 29 }
30 $scope.$on('$stateChangeStart', function (event, next, current, params) { 30 $scope.$on('$stateChangeStart', function (event, next, current, params) {
31 - if (userService.isAuthenticated() && (($scope.confirmForm && $scope.confirmForm.$dirty) || $scope.isDirty)) { 31 + if (userService.isAuthenticated() && (($scope.confirmForm && $scope.confirmForm.$dirty) || $scope.$eval($attributes.isDirty))) {
32 event.preventDefault(); 32 event.preventDefault();
33 var confirm = $mdDialog.confirm() 33 var confirm = $mdDialog.confirm()
34 .title($filter('translate')('confirm-on-exit.title')) 34 .title($filter('translate')('confirm-on-exit.title'))
@@ -40,7 +40,9 @@ function ConfirmOnExit($state, $mdDialog, $window, $filter, userService) { @@ -40,7 +40,9 @@ function ConfirmOnExit($state, $mdDialog, $window, $filter, userService) {
40 if ($scope.confirmForm) { 40 if ($scope.confirmForm) {
41 $scope.confirmForm.$setPristine(); 41 $scope.confirmForm.$setPristine();
42 } else { 42 } else {
43 - $scope.isDirty = false; 43 + var remoteSetter = $parse($attributes.isDirty).assign;
  44 + remoteSetter($scope, false);
  45 + //$scope.isDirty = false;
44 } 46 }
45 $state.go(next.name, params); 47 $state.go(next.name, params);
46 }, function () { 48 }, function () {
@@ -48,9 +50,6 @@ function ConfirmOnExit($state, $mdDialog, $window, $filter, userService) { @@ -48,9 +50,6 @@ function ConfirmOnExit($state, $mdDialog, $window, $filter, userService) {
48 } 50 }
49 }); 51 });
50 }, 52 },
51 - scope: {  
52 - confirmForm: '=',  
53 - isDirty: '='  
54 - } 53 + scope: false
55 }; 54 };
56 } 55 }
@@ -1177,6 +1177,8 @@ export default angular.module('thingsboard.locale', []) @@ -1177,6 +1177,8 @@ export default angular.module('thingsboard.locale', [])
1177 "type": "Type", 1177 "type": "Type",
1178 "description": "Description", 1178 "description": "Description",
1179 "delete": "Delete rule node", 1179 "delete": "Delete rule node",
  1180 + "select-all": "Select all nodes and connections",
  1181 + "deselect-all": "Deselect all nodes and connections",
1180 "delete-selected-objects": "Delete selected nodes and connections", 1182 "delete-selected-objects": "Delete selected nodes and connections",
1181 "rulenode-details": "Rule node details", 1183 "rulenode-details": "Rule node details",
1182 "debug-mode": "Debug mode", 1184 "debug-mode": "Debug mode",
@@ -27,15 +27,10 @@ import addRuleNodeLinkTemplate from './add-link.tpl.html'; @@ -27,15 +27,10 @@ import addRuleNodeLinkTemplate from './add-link.tpl.html';
27 27
28 /* eslint-enable import/no-unresolved, import/default */ 28 /* eslint-enable import/no-unresolved, import/default */
29 29
30 -  
31 -const deleteKeyCode = 46;  
32 -const ctrlKeyCode = 17;  
33 -const aKeyCode = 65;  
34 -const escKeyCode = 27;  
35 -  
36 /*@ngInject*/ 30 /*@ngInject*/
37 export function RuleChainController($stateParams, $scope, $compile, $q, $mdUtil, $timeout, $mdExpansionPanel, $document, $mdDialog, 31 export function RuleChainController($stateParams, $scope, $compile, $q, $mdUtil, $timeout, $mdExpansionPanel, $document, $mdDialog,
38 - $filter, $translate, types, ruleChainService, Modelfactory, flowchartConstants, ruleChain, ruleChainMetaData) { 32 + $filter, $translate, hotkeys, types, ruleChainService, Modelfactory, flowchartConstants,
  33 + ruleChain, ruleChainMetaData, ruleNodeComponents) {
39 34
40 var vm = this; 35 var vm = this;
41 36
@@ -76,42 +71,62 @@ export function RuleChainController($stateParams, $scope, $compile, $q, $mdUtil, @@ -76,42 +71,62 @@ export function RuleChainController($stateParams, $scope, $compile, $q, $mdUtil,
76 71
77 vm.modelservice = Modelfactory(vm.ruleChainModel, vm.selectedObjects); 72 vm.modelservice = Modelfactory(vm.ruleChainModel, vm.selectedObjects);
78 73
79 - vm.ctrlDown = false;  
80 -  
81 vm.saveRuleChain = saveRuleChain; 74 vm.saveRuleChain = saveRuleChain;
82 vm.revertRuleChain = revertRuleChain; 75 vm.revertRuleChain = revertRuleChain;
83 76
84 vm.objectsSelected = objectsSelected; 77 vm.objectsSelected = objectsSelected;
85 vm.deleteSelected = deleteSelected; 78 vm.deleteSelected = deleteSelected;
86 79
87 - vm.keyDown = function (evt) {  
88 - if (evt.keyCode === ctrlKeyCode) {  
89 - vm.ctrlDown = true;  
90 - evt.stopPropagation();  
91 - evt.preventDefault();  
92 - }  
93 - };  
94 -  
95 - vm.keyUp = function (evt) {  
96 -  
97 - if (evt.keyCode === deleteKeyCode) {  
98 - vm.modelservice.deleteSelected();  
99 - }  
100 -  
101 - if (evt.keyCode == aKeyCode && vm.ctrlDown) {  
102 - vm.modelservice.selectAll();  
103 - }  
104 -  
105 - if (evt.keyCode == escKeyCode) {  
106 - vm.modelservice.deselectAll();  
107 - }  
108 -  
109 - if (evt.keyCode === ctrlKeyCode) {  
110 - vm.ctrlDown = false;  
111 - evt.stopPropagation();  
112 - evt.preventDefault();  
113 - }  
114 - }; 80 + initHotKeys();
  81 +
  82 + function initHotKeys() {
  83 + hotkeys.bindTo($scope)
  84 + .add({
  85 + combo: 'ctrl+a',
  86 + description: $translate.instant('rulenode.select-all'),
  87 + allowIn: ['INPUT', 'SELECT', 'TEXTAREA'],
  88 + callback: function (event) {
  89 + event.preventDefault();
  90 + vm.modelservice.selectAll();
  91 + }
  92 + })
  93 + .add({
  94 + combo: 'esc',
  95 + description: $translate.instant('rulenode.deselect-all'),
  96 + allowIn: ['INPUT', 'SELECT', 'TEXTAREA'],
  97 + callback: function (event) {
  98 + event.preventDefault();
  99 + vm.modelservice.deselectAll();
  100 + }
  101 + })
  102 + .add({
  103 + combo: 'ctrl+s',
  104 + description: $translate.instant('action.apply'),
  105 + allowIn: ['INPUT', 'SELECT', 'TEXTAREA'],
  106 + callback: function (event) {
  107 + event.preventDefault();
  108 + vm.saveRuleChain();
  109 + }
  110 + })
  111 + .add({
  112 + combo: 'ctrl+z',
  113 + description: $translate.instant('action.decline-changes'),
  114 + allowIn: ['INPUT', 'SELECT', 'TEXTAREA'],
  115 + callback: function (event) {
  116 + event.preventDefault();
  117 + vm.revertRuleChain();
  118 + }
  119 + })
  120 + .add({
  121 + combo: 'del',
  122 + description: $translate.instant('rulenode.delete-selected-objects'),
  123 + allowIn: ['INPUT', 'SELECT', 'TEXTAREA'],
  124 + callback: function (event) {
  125 + event.preventDefault();
  126 + vm.modelservice.deleteSelected();
  127 + }
  128 + })
  129 + }
115 130
116 vm.onEditRuleNodeClosed = function() { 131 vm.onEditRuleNodeClosed = function() {
117 vm.editingRuleNode = null; 132 vm.editingRuleNode = null;
@@ -289,44 +304,40 @@ export function RuleChainController($stateParams, $scope, $compile, $q, $mdUtil, @@ -289,44 +304,40 @@ export function RuleChainController($stateParams, $scope, $compile, $q, $mdUtil,
289 loadRuleChainLibrary(); 304 loadRuleChainLibrary();
290 305
291 function loadRuleChainLibrary() { 306 function loadRuleChainLibrary() {
292 - ruleChainService.getRuleNodeComponents().then(  
293 - (ruleNodeComponents) => {  
294 - for (var i=0;i<ruleNodeComponents.length;i++) {  
295 - var ruleNodeComponent = ruleNodeComponents[i];  
296 - var componentType = ruleNodeComponent.type;  
297 - var model = vm.ruleNodeTypesModel[componentType].model;  
298 - var node = {  
299 - id: model.nodes.length,  
300 - component: ruleNodeComponent,  
301 - name: '',  
302 - nodeClass: vm.types.ruleNodeType[componentType].nodeClass,  
303 - icon: vm.types.ruleNodeType[componentType].icon,  
304 - x: 30,  
305 - y: 10+50*model.nodes.length,  
306 - connectors: []  
307 - };  
308 - if (ruleNodeComponent.configurationDescriptor.nodeDefinition.inEnabled) {  
309 - node.connectors.push(  
310 - {  
311 - type: flowchartConstants.leftConnectorType,  
312 - id: model.nodes.length * 2  
313 - }  
314 - ); 307 + for (var i=0;i<ruleNodeComponents.length;i++) {
  308 + var ruleNodeComponent = ruleNodeComponents[i];
  309 + var componentType = ruleNodeComponent.type;
  310 + var model = vm.ruleNodeTypesModel[componentType].model;
  311 + var node = {
  312 + id: model.nodes.length,
  313 + component: ruleNodeComponent,
  314 + name: '',
  315 + nodeClass: vm.types.ruleNodeType[componentType].nodeClass,
  316 + icon: vm.types.ruleNodeType[componentType].icon,
  317 + x: 30,
  318 + y: 10+50*model.nodes.length,
  319 + connectors: []
  320 + };
  321 + if (ruleNodeComponent.configurationDescriptor.nodeDefinition.inEnabled) {
  322 + node.connectors.push(
  323 + {
  324 + type: flowchartConstants.leftConnectorType,
  325 + id: model.nodes.length * 2
315 } 326 }
316 - if (ruleNodeComponent.configurationDescriptor.nodeDefinition.outEnabled) {  
317 - node.connectors.push(  
318 - {  
319 - type: flowchartConstants.rightConnectorType,  
320 - id: model.nodes.length * 2 + 1  
321 - }  
322 - ); 327 + );
  328 + }
  329 + if (ruleNodeComponent.configurationDescriptor.nodeDefinition.outEnabled) {
  330 + node.connectors.push(
  331 + {
  332 + type: flowchartConstants.rightConnectorType,
  333 + id: model.nodes.length * 2 + 1
323 } 334 }
324 - model.nodes.push(node);  
325 - }  
326 - vm.ruleChainLibraryLoaded = true;  
327 - prepareRuleChain(); 335 + );
328 } 336 }
329 - ); 337 + model.nodes.push(node);
  338 + }
  339 + vm.ruleChainLibraryLoaded = true;
  340 + prepareRuleChain();
330 } 341 }
331 342
332 function prepareRuleChain() { 343 function prepareRuleChain() {
@@ -68,6 +68,11 @@ export default function RuleChainRoutes($stateProvider, NodeTemplatePathProvider @@ -68,6 +68,11 @@ export default function RuleChainRoutes($stateProvider, NodeTemplatePathProvider
68 /*@ngInject*/ 68 /*@ngInject*/
69 function($stateParams, ruleChainService) { 69 function($stateParams, ruleChainService) {
70 return ruleChainService.getRuleChainMetaData($stateParams.ruleChainId); 70 return ruleChainService.getRuleChainMetaData($stateParams.ruleChainId);
  71 + },
  72 + ruleNodeComponents:
  73 + /*@ngInject*/
  74 + function($stateParams, ruleChainService) {
  75 + return ruleChainService.getRuleNodeComponents();
71 } 76 }
72 }, 77 },
73 data: { 78 data: {
@@ -75,6 +75,7 @@ @@ -75,6 +75,7 @@
75 padding: 5px 10px; 75 padding: 5px 10px;
76 border-radius: 5px; 76 border-radius: 5px;
77 background-color: #F15B26; 77 background-color: #F15B26;
  78 + pointer-events: none;
78 color: #333; 79 color: #333;
79 border: solid 1px #777; 80 border: solid 1px #777;
80 font-size: 12px; 81 font-size: 12px;
@@ -186,12 +187,27 @@ @@ -186,12 +187,27 @@
186 margin: 10px; 187 margin: 10px;
187 border-radius: 5px; 188 border-radius: 5px;
188 background-color: #ccc; 189 background-color: #ccc;
  190 + pointer-events: all;
189 } 191 }
190 192
191 .fc-connector.fc-hover { 193 .fc-connector.fc-hover {
192 background-color: #000; 194 background-color: #000;
193 } 195 }
194 196
  197 +.fc-arrow-marker {
  198 + polygon {
  199 + stroke: gray;
  200 + fill: gray;
  201 + }
  202 +}
  203 +
  204 +.fc-arrow-marker-selected {
  205 + polygon {
  206 + stroke: red;
  207 + fill: red;
  208 + }
  209 +}
  210 +
195 .fc-edge { 211 .fc-edge {
196 outline: none; 212 outline: none;
197 stroke: gray; 213 stroke: gray;
@@ -246,11 +262,23 @@ @@ -246,11 +262,23 @@
246 cursor: pointer; 262 cursor: pointer;
247 } 263 }
248 264
  265 +.fc-noselect {
  266 + -webkit-touch-callout: none; /* iOS Safari */
  267 + -webkit-user-select: none; /* Safari */
  268 + -khtml-user-select: none; /* Konqueror HTML */
  269 + -moz-user-select: none; /* Firefox */
  270 + -ms-user-select: none; /* Internet Explorer/Edge */
  271 + user-select: none; /* Non-prefixed version, currently
  272 + supported by Chrome and Opera */
  273 +}
  274 +
249 .fc-edge-label { 275 .fc-edge-label {
250 position: absolute; 276 position: absolute;
251 - user-select: none;  
252 transition: transform .2s; 277 transition: transform .2s;
253 opacity: 0.8; 278 opacity: 0.8;
  279 + &.ng-leave {
  280 + transition: 0s none;
  281 + }
254 &.fc-hover { 282 &.fc-hover {
255 transform: scale(1.25); 283 transform: scale(1.25);
256 } 284 }
@@ -262,6 +290,13 @@ @@ -262,6 +290,13 @@
262 } 290 }
263 } 291 }
264 } 292 }
  293 + .fc-nodedelete {
  294 + right: -13px;
  295 + top: -30px;
  296 + }
  297 + &:focus {
  298 + outline: 0;
  299 + }
265 } 300 }
266 301
267 .fc-edge-label-text { 302 .fc-edge-label-text {
@@ -273,6 +308,7 @@ @@ -273,6 +308,7 @@
273 font-size: 14px; 308 font-size: 14px;
274 font-weight: 600; 309 font-weight: 600;
275 span { 310 span {
  311 + cursor: default;
276 border: solid 2px #003a79; 312 border: solid 2px #003a79;
277 border-radius: 10px; 313 border-radius: 10px;
278 color: #003a79; 314 color: #003a79;
@@ -16,8 +16,10 @@ @@ -16,8 +16,10 @@
16 16
17 --> 17 -->
18 18
19 -<md-content flex tb-expand-fullscreen  
20 - expand-tooltip-direction="bottom" layout="column" class="tb-rulechain"> 19 +<md-content flex tb-expand-fullscreen tb-confirm-on-exit is-dirty="vm.isDirty"
  20 + expand-tooltip-direction="bottom" layout="column" class="tb-rulechain"
  21 + ng-keydown="vm.keyDown($event)"
  22 + ng-keyup="vm.keyUp($event)">
21 <section class="tb-rulechain-container" flex layout="column"> 23 <section class="tb-rulechain-container" flex layout="column">
22 <div class="tb-rulechain-layout" flex layout="row"> 24 <div class="tb-rulechain-layout" flex layout="row">
23 <div class="tb-rulechain-library"> 25 <div class="tb-rulechain-library">
@@ -50,8 +52,6 @@ @@ -50,8 +52,6 @@
50 </div> 52 </div>
51 <div flex class="tb-rulechain-graph"> 53 <div flex class="tb-rulechain-graph">
52 <fc-canvas id="tb-rulchain-canvas" 54 <fc-canvas id="tb-rulchain-canvas"
53 - ng-keydown="vm.keyDown($event)"  
54 - ng-keyup="vm.keyUp($event)"  
55 model="vm.ruleChainModel" 55 model="vm.ruleChainModel"
56 selected-objects="vm.selectedObjects" 56 selected-objects="vm.selectedObjects"
57 edge-style="curved" 57 edge-style="curved"