thingsboard-memoizeit
Changes
application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleNodeActorMessageProcessor.java 8(+6 -2)
ui/src/app/event/event.scss 25(+21 -4)
ui/src/app/locale/locale.constant.js 2(+2 -0)
ui/src/app/rulechain/rulechain.controller.js 57(+53 -4)
ui/src/app/rulechain/rulechain.scss 13(+12 -1)
ui/src/app/rulechain/rulechain.tpl.html 21(+12 -9)
Details
diff --git a/application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleNodeActorMessageProcessor.java b/application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleNodeActorMessageProcessor.java
index a08dc34..93cb5fb 100644
--- a/application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleNodeActorMessageProcessor.java
+++ b/application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleNodeActorMessageProcessor.java
@@ -69,14 +69,18 @@ public class RuleNodeActorMessageProcessor extends ComponentMsgProcessor<RuleNod
&& ruleNode.getConfiguration().equals(newRuleNode.getConfiguration()));
this.ruleNode = newRuleNode;
if (restartRequired) {
- tbNode.destroy();
+ if (tbNode != null) {
+ tbNode.destroy();
+ }
start(context);
}
}
@Override
public void stop(ActorContext context) throws Exception {
- tbNode.destroy();
+ if (tbNode != null) {
+ tbNode.destroy();
+ }
context.stop(self);
}
ui/src/app/event/event.scss 25(+21 -4)
diff --git a/ui/src/app/event/event.scss b/ui/src/app/event/event.scss
index b3be35c..b0fc46f 100644
--- a/ui/src/app/event/event.scss
+++ b/ui/src/app/event/event.scss
@@ -24,6 +24,17 @@ md-list.tb-event-table {
height: 48px;
padding: 0px;
overflow: hidden;
+ .tb-cell {
+ text-overflow: ellipsis;
+ &.tb-scroll {
+ white-space: nowrap;
+ overflow-y: hidden;
+ overflow-x: auto;
+ }
+ &.tb-nowrap {
+ white-space: nowrap;
+ }
+ }
}
.tb-row:hover {
@@ -39,13 +50,19 @@ md-list.tb-event-table {
color: rgba(0,0,0,.54);
font-size: 12px;
font-weight: 700;
- white-space: nowrap;
background: none;
+ white-space: nowrap;
}
}
.tb-cell {
- padding: 0 24px;
+ &:first-child {
+ padding-left: 14px;
+ }
+ &:last-child {
+ padding-right: 14px;
+ }
+ padding: 0 6px;
margin: auto 0;
color: rgba(0,0,0,.87);
font-size: 13px;
@@ -53,8 +70,8 @@ md-list.tb-event-table {
text-align: left;
overflow: hidden;
.md-button {
- padding: 0;
- margin: 0;
+ padding: 0;
+ margin: 0;
}
}
diff --git a/ui/src/app/event/event-header-debug-rulenode.tpl.html b/ui/src/app/event/event-header-debug-rulenode.tpl.html
index b412a0c..34f4513 100644
--- a/ui/src/app/event/event-header-debug-rulenode.tpl.html
+++ b/ui/src/app/event/event-header-debug-rulenode.tpl.html
@@ -15,13 +15,13 @@
limitations under the License.
-->
-<div hide-xs hide-sm translate class="tb-cell" flex="30">event.event-time</div>
+<div hide-xs hide-sm translate class="tb-cell" flex="25">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="10">event.type</div>
+<div translate class="tb-cell" flex="15">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>
+<div translate class="tb-cell" flex="15">event.data-type</div>
+<div translate class="tb-cell" flex="10">event.data</div>
+<div translate class="tb-cell" flex="10">event.metadata</div>
+<div translate class="tb-cell" flex="10">event.error</div>
diff --git a/ui/src/app/event/event-row.directive.js b/ui/src/app/event/event-row.directive.js
index 4643761..b808fb8 100644
--- a/ui/src/app/event/event-row.directive.js
+++ b/ui/src/app/event/event-row.directive.js
@@ -86,6 +86,14 @@ export default function EventRowDirective($compile, $templateCache, $mdDialog, $
});
}
+ scope.checkTooltip = function($event) {
+ var el = $event.target;
+ var $el = angular.element(el);
+ if(el.offsetWidth < el.scrollWidth && !$el.attr('title')){
+ $el.attr('title', $el.text());
+ }
+ }
+
$compile(element.contents())(scope);
}
diff --git a/ui/src/app/event/event-row-debug-rulenode.tpl.html b/ui/src/app/event/event-row-debug-rulenode.tpl.html
index 5b96baf..bb832b1 100644
--- a/ui/src/app/event/event-row-debug-rulenode.tpl.html
+++ b/ui/src/app/event/event-row-debug-rulenode.tpl.html
@@ -15,14 +15,14 @@
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 hide-xs hide-sm class="tb-cell" flex="25">{{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">
+<div class="tb-cell" flex="10">{{event.body.type}}</div>
+<div class="tb-cell" flex="15">{{event.body.entityName}}</div>
+<div class="tb-cell tb-nowrap" flex="20" ng-mouseenter="checkTooltip($event)">{{event.body.msgId}}</div>
+<div class="tb-cell" flex="20" ng-mouseenter="checkTooltip($event)">{{event.body.msgType}}</div>
+<div class="tb-cell" flex="15">{{event.body.dataType}}</div>
+<div class="tb-cell" flex="10">
<md-button ng-if="event.body.data" class="md-icon-button md-primary"
ng-click="showContent($event, event.body.data, 'event.data', event.body.dataType)"
aria-label="{{ 'action.view' | translate }}">
@@ -35,7 +35,7 @@
</md-icon>
</md-button>
</div>
-<div class="tb-cell" flex="20">
+<div class="tb-cell" flex="10">
<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 }}">
@@ -48,7 +48,7 @@
</md-icon>
</md-button>
</div>
-<div class="tb-cell" flex="20">
+<div class="tb-cell" flex="10">
<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 }}">
ui/src/app/locale/locale.constant.js 2(+2 -0)
diff --git a/ui/src/app/locale/locale.constant.js b/ui/src/app/locale/locale.constant.js
index f616fec..9c0cd12 100644
--- a/ui/src/app/locale/locale.constant.js
+++ b/ui/src/app/locale/locale.constant.js
@@ -43,6 +43,7 @@ export default angular.module('thingsboard.locale', [])
"update": "Update",
"remove": "Remove",
"search": "Search",
+ "clear-search": "Clear search",
"assign": "Assign",
"unassign": "Unassign",
"share": "Share",
@@ -1188,6 +1189,7 @@ export default angular.module('thingsboard.locale', [])
"details": "Details",
"events": "Events",
"search": "Search nodes",
+ "open-node-library": "Open node library",
"add": "Add rule node",
"name": "Name",
"name-required": "Name is required.",
ui/src/app/rulechain/rulechain.controller.js 57(+53 -4)
diff --git a/ui/src/app/rulechain/rulechain.controller.js b/ui/src/app/rulechain/rulechain.controller.js
index 7de72c3..14cf798 100644
--- a/ui/src/app/rulechain/rulechain.controller.js
+++ b/ui/src/app/rulechain/rulechain.controller.js
@@ -37,6 +37,8 @@ export function RuleChainController($stateParams, $scope, $compile, $q, $mdUtil,
vm.$mdExpansionPanel = $mdExpansionPanel;
vm.types = types;
+ vm.isFullscreen = false;
+
vm.editingRuleNode = null;
vm.isEditingRuleNode = false;
@@ -57,6 +59,7 @@ export function RuleChainController($stateParams, $scope, $compile, $q, $mdUtil,
};
vm.ruleNodeTypesModel = {};
+ vm.ruleNodeTypesCanvasControl = {};
vm.ruleChainLibraryLoaded = false;
for (var type in types.ruleNodeType) {
if (!types.ruleNodeType[type].special) {
@@ -67,9 +70,12 @@ export function RuleChainController($stateParams, $scope, $compile, $q, $mdUtil,
},
selectedObjects: []
};
+ vm.ruleNodeTypesCanvasControl[type] = {};
}
}
+
+
vm.selectedObjects = [];
vm.modelservice = Modelfactory(vm.ruleChainModel, vm.selectedObjects);
@@ -147,6 +153,7 @@ export function RuleChainController($stateParams, $scope, $compile, $q, $mdUtil,
theForm.$setPristine();
vm.ruleChainModel.nodes[vm.editingRuleNodeIndex] = vm.editingRuleNode;
vm.editingRuleNode = angular.copy(vm.editingRuleNode);
+ updateRuleNodesHighlight();
}
};
@@ -313,12 +320,28 @@ export function RuleChainController($stateParams, $scope, $compile, $q, $mdUtil,
}
};
- loadRuleChainLibrary();
+ loadRuleChainLibrary(ruleNodeComponents, true);
+
+ $scope.$watch('vm.ruleNodeSearch',
+ function (newVal, oldVal) {
+ if (!angular.equals(newVal, oldVal)) {
+ var res = $filter('filter')(ruleNodeComponents, {name: vm.ruleNodeSearch});
+ loadRuleChainLibrary(res);
+ }
+ }
+ );
- function loadRuleChainLibrary() {
+ $scope.$on('searchTextUpdated', function () {
+ updateRuleNodesHighlight();
+ });
+
+ function loadRuleChainLibrary(ruleNodeComponents, loadRuleChain) {
+ for (var componentType in vm.ruleNodeTypesModel) {
+ vm.ruleNodeTypesModel[componentType].model.nodes.length = 0;
+ }
for (var i=0;i<ruleNodeComponents.length;i++) {
var ruleNodeComponent = ruleNodeComponents[i];
- var componentType = ruleNodeComponent.type;
+ componentType = ruleNodeComponent.type;
var model = vm.ruleNodeTypesModel[componentType].model;
var node = {
id: 'node-lib-' + componentType + '-' + model.nodes.length,
@@ -349,7 +372,16 @@ export function RuleChainController($stateParams, $scope, $compile, $q, $mdUtil,
model.nodes.push(node);
}
vm.ruleChainLibraryLoaded = true;
- prepareRuleChain();
+ if (loadRuleChain) {
+ prepareRuleChain();
+ }
+ $mdUtil.nextTick(() => {
+ for (componentType in vm.ruleNodeTypesCanvasControl) {
+ if (vm.ruleNodeTypesCanvasControl[componentType].adjustCanvasSize) {
+ vm.ruleNodeTypesCanvasControl[componentType].adjustCanvasSize(true);
+ }
+ }
+ });
}
function prepareRuleChain() {
@@ -519,6 +551,8 @@ export function RuleChainController($stateParams, $scope, $compile, $q, $mdUtil,
vm.isDirty = false;
+ updateRuleNodesHighlight();
+
$mdUtil.nextTick(() => {
vm.ruleChainWatch = $scope.$watch('vm.ruleChainModel',
function (newVal, oldVal) {
@@ -530,6 +564,20 @@ export function RuleChainController($stateParams, $scope, $compile, $q, $mdUtil,
});
}
+ function updateRuleNodesHighlight() {
+ for (var i=0;i<vm.ruleChainModel.nodes.length;i++) {
+ vm.ruleChainModel.nodes[i].highlighted = false;
+ }
+ if ($scope.searchConfig.searchText) {
+ var res = $filter('filter')(vm.ruleChainModel.nodes, {name: $scope.searchConfig.searchText});
+ if (res) {
+ for (i=0;i<res.length;i++) {
+ res[i].highlighted = true;
+ }
+ }
+ }
+ }
+
function saveRuleChain() {
var ruleChainMetaData = {
ruleChainId: vm.ruleChain.id,
@@ -642,6 +690,7 @@ export function RuleChainController($stateParams, $scope, $compile, $q, $mdUtil,
);
}
vm.ruleChainModel.nodes.push(ruleNode);
+ updateRuleNodesHighlight();
}, function () {
});
}
diff --git a/ui/src/app/rulechain/rulechain.routes.js b/ui/src/app/rulechain/rulechain.routes.js
index f9578ef..48559d9 100644
--- a/ui/src/app/rulechain/rulechain.routes.js
+++ b/ui/src/app/rulechain/rulechain.routes.js
@@ -76,7 +76,7 @@ export default function RuleChainRoutes($stateProvider, NodeTemplatePathProvider
}
},
data: {
- searchEnabled: false,
+ searchEnabled: true,
pageTitle: 'rulechain.rulechain'
},
ncyBreadcrumb: {
ui/src/app/rulechain/rulechain.scss 13(+12 -1)
diff --git a/ui/src/app/rulechain/rulechain.scss b/ui/src/app/rulechain/rulechain.scss
index 38f785a..850de3c 100644
--- a/ui/src/app/rulechain/rulechain.scss
+++ b/ui/src/app/rulechain/rulechain.scss
@@ -125,6 +125,13 @@
color: #333;
border: solid 1px #777;
font-size: 12px;
+ &.tb-rule-node-highlighted {
+ box-shadow: 0 0 10px 6px #51cbee;
+ .tb-node-title {
+ text-decoration: underline;
+ font-weight: bold;
+ }
+ }
&.tb-input-type {
background-color: #a3eaa9;
user-select: none;
@@ -156,7 +163,7 @@
}
.tb-node-title {
- font-weight: 600;
+ font-weight: 500;
}
.tb-node-type, .tb-node-title {
overflow: hidden;
@@ -184,6 +191,10 @@
bottom: 0;
background-color: #000;
opacity: 0;
+/* &.tb-rule-node-highlighted {
+ background-color: green;
+ opacity: 0.15;
+ }*/
}
&.fc-hover {
.fc-node-overlay {
ui/src/app/rulechain/rulechain.tpl.html 21(+12 -9)
diff --git a/ui/src/app/rulechain/rulechain.tpl.html b/ui/src/app/rulechain/rulechain.tpl.html
index ddc1a90..a843b03 100644
--- a/ui/src/app/rulechain/rulechain.tpl.html
+++ b/ui/src/app/rulechain/rulechain.tpl.html
@@ -19,17 +19,17 @@
<md-content flex tb-expand-fullscreen tb-confirm-on-exit is-dirty="vm.isDirty"
expand-tooltip-direction="bottom" layout="column" class="tb-rulechain"
ng-keydown="vm.keyDown($event)"
- ng-keyup="vm.keyUp($event)">
+ ng-keyup="vm.keyUp($event)" on-fullscreen-changed="vm.isFullscreen = expanded">
<section class="tb-rulechain-container" flex layout="column">
<div class="tb-rulechain-layout" flex layout="row">
<section layout="row" layout-wrap
class="tb-header-buttons md-fab tb-library-open">
<md-button ng-show="!vm.isLibraryOpen"
class="tb-btn-header tb-btn-open-library md-primary md-fab md-fab-top-left"
- aria-label="{{ 'action.apply' | translate }}"
+ aria-label="{{ 'rulenode.open-node-library' | translate }}"
ng-click="vm.isLibraryOpen = true">
- <md-tooltip md-direction="top">
- {{ 'action.apply-changes' | translate }}
+ <md-tooltip md-direction="{{vm.isFullscreen ? 'bottom' : 'top'}}">
+ {{ 'rulenode.open-node-library' | translate }}
</md-tooltip>
<ng-md-icon icon="menu"></ng-md-icon>
</md-button>
@@ -43,7 +43,7 @@
<div class="md-toolbar-tools">
<md-button class="md-icon-button tb-small" aria-label="{{ 'action.search' | translate }}">
<md-icon aria-label="{{ 'action.search' | translate }}" class="material-icons">search</md-icon>
- <md-tooltip md-direction="top">
+ <md-tooltip md-direction="{{vm.isFullscreen ? 'bottom' : 'top'}}">
{{'rulenode.search' | translate}}
</md-tooltip>
</md-button>
@@ -53,15 +53,17 @@
<input ng-model="vm.ruleNodeSearch" placeholder="{{'rulenode.search' | translate}}"/>
</md-input-container>
</div>
- <md-button class="md-icon-button tb-small" aria-label="Close" ng-click="vm.ruleNodeSearch = ''">
+ <md-button class="md-icon-button tb-small" aria-label="Close"
+ ng-show="vm.ruleNodeSearch"
+ ng-click="vm.ruleNodeSearch = ''">
<md-icon aria-label="Close" class="material-icons">close</md-icon>
- <md-tooltip md-direction="top">
- {{ 'action.close' | translate }}
+ <md-tooltip md-direction="{{vm.isFullscreen ? 'bottom' : 'top'}}">
+ {{ 'action.clear-search' | translate }}
</md-tooltip>
</md-button>
<md-button class="md-icon-button tb-small" aria-label="Close" ng-click="vm.isLibraryOpen = false">
<md-icon aria-label="Close" class="material-icons">chevron_left</md-icon>
- <md-tooltip md-direction="top">
+ <md-tooltip md-direction="{{vm.isFullscreen ? 'bottom' : 'top'}}">
{{ 'action.close' | translate }}
</md-tooltip>
</md-button>
@@ -90,6 +92,7 @@
callbacks="vm.nodeLibCallbacks"
node-width="170"
node-height="50"
+ control="vm.ruleNodeTypesCanvasControl[typeId]"
drop-target-id="'tb-rulchain-canvas'"></fc-canvas>
</md-expansion-panel-content>
</md-expansion-panel-expanded>
diff --git a/ui/src/app/rulechain/rulenode.tpl.html b/ui/src/app/rulechain/rulenode.tpl.html
index 55ee3d3..83ce988 100644
--- a/ui/src/app/rulechain/rulenode.tpl.html
+++ b/ui/src/app/rulechain/rulenode.tpl.html
@@ -22,8 +22,8 @@
ng-mousedown="callbacks.mouseDown($event, node)"
ng-mouseenter="callbacks.mouseEnter($event, node)"
ng-mouseleave="callbacks.mouseLeave($event, node)">
- <div class="{{flowchartConstants.nodeOverlayClass}}"></div>
- <div class="tb-rule-node {{node.nodeClass}}">
+ <div class="{{flowchartConstants.nodeOverlayClass}}" ng-class="{'tb-rule-node-highlighted' : node.highlighted}"></div>
+ <div class="tb-rule-node {{node.nodeClass}}" ng-class="{'tb-rule-node-highlighted' : node.highlighted}">
<md-icon aria-label="node-type-icon" flex="15"
class="material-icons">{{node.icon}}</md-icon>
<div layout="column" flex="85" layout-align="center">