Commit b855d82f7a2abc54d6701f69f8c097bfd24029de

Authored by Andrew Shvayka
2 parents 522d3927 dcefde00

Merge branch 'master' of github.com:thingsboard/thingsboard

@@ -169,15 +169,7 @@ export default class Subscription { @@ -169,15 +169,7 @@ export default class Subscription {
169 }); 169 });
170 this.registrations.push(registration); 170 this.registrations.push(registration);
171 } else { 171 } else {
172 - registration = this.ctx.$scope.$watch(function () {  
173 - return subscription.timeWindowConfig;  
174 - }, function (newTimewindow, prevTimewindow) {  
175 - if (!angular.equals(newTimewindow, prevTimewindow)) {  
176 - subscription.unsubscribe();  
177 - subscription.subscribe();  
178 - }  
179 - });  
180 - this.registrations.push(registration); 172 + this.startWatchingTimewindow();
181 } 173 }
182 } 174 }
183 175
@@ -188,6 +180,29 @@ export default class Subscription { @@ -188,6 +180,29 @@ export default class Subscription {
188 this.registrations.push(registration); 180 this.registrations.push(registration);
189 } 181 }
190 182
  183 + startWatchingTimewindow() {
  184 + var subscription = this;
  185 + this.timeWindowWatchRegistration = this.ctx.$scope.$watch(function () {
  186 + return subscription.timeWindowConfig;
  187 + }, function (newTimewindow, prevTimewindow) {
  188 + if (!angular.equals(newTimewindow, prevTimewindow)) {
  189 + subscription.unsubscribe();
  190 + subscription.subscribe();
  191 + }
  192 + }, true);
  193 + this.registrations.push(this.timeWindowWatchRegistration);
  194 + }
  195 +
  196 + stopWatchingTimewindow() {
  197 + if (this.timeWindowWatchRegistration) {
  198 + this.timeWindowWatchRegistration();
  199 + var index = this.registrations.indexOf(this.timeWindowWatchRegistration);
  200 + if (index > -1) {
  201 + this.registrations.splice(index, 1);
  202 + }
  203 + }
  204 + }
  205 +
191 initRpc() { 206 initRpc() {
192 207
193 if (this.targetDeviceAliasIds && this.targetDeviceAliasIds.length > 0) { 208 if (this.targetDeviceAliasIds && this.targetDeviceAliasIds.length > 0) {
@@ -335,9 +350,9 @@ export default class Subscription { @@ -335,9 +350,9 @@ export default class Subscription {
335 var subscription = this; 350 var subscription = this;
336 this.cafs['dataUpdated'] = this.ctx.tbRaf(function() { 351 this.cafs['dataUpdated'] = this.ctx.tbRaf(function() {
337 try { 352 try {
338 - subscription.callbacks.onDataUpdated(this, apply); 353 + subscription.callbacks.onDataUpdated(subscription, apply);
339 } catch (e) { 354 } catch (e) {
340 - subscription.callbacks.onDataUpdateError(this, e); 355 + subscription.callbacks.onDataUpdateError(subscription, e);
341 } 356 }
342 }); 357 });
343 if (apply) { 358 if (apply) {
@@ -354,9 +369,13 @@ export default class Subscription { @@ -354,9 +369,13 @@ export default class Subscription {
354 this.ctx.dashboardTimewindowApi.onResetTimewindow(); 369 this.ctx.dashboardTimewindowApi.onResetTimewindow();
355 } else { 370 } else {
356 if (this.originalTimewindow) { 371 if (this.originalTimewindow) {
  372 + this.stopWatchingTimewindow();
357 this.timeWindowConfig = angular.copy(this.originalTimewindow); 373 this.timeWindowConfig = angular.copy(this.originalTimewindow);
358 this.originalTimewindow = null; 374 this.originalTimewindow = null;
359 this.callbacks.timeWindowUpdated(this, this.timeWindowConfig); 375 this.callbacks.timeWindowUpdated(this, this.timeWindowConfig);
  376 + this.unsubscribe();
  377 + this.subscribe();
  378 + this.startWatchingTimewindow();
360 } 379 }
361 } 380 }
362 } 381 }
@@ -365,11 +384,15 @@ export default class Subscription { @@ -365,11 +384,15 @@ export default class Subscription {
365 if (this.useDashboardTimewindow) { 384 if (this.useDashboardTimewindow) {
366 this.ctx.dashboardTimewindowApi.onUpdateTimewindow(startTimeMs, endTimeMs); 385 this.ctx.dashboardTimewindowApi.onUpdateTimewindow(startTimeMs, endTimeMs);
367 } else { 386 } else {
  387 + this.stopWatchingTimewindow();
368 if (!this.originalTimewindow) { 388 if (!this.originalTimewindow) {
369 this.originalTimewindow = angular.copy(this.timeWindowConfig); 389 this.originalTimewindow = angular.copy(this.timeWindowConfig);
370 } 390 }
371 this.timeWindowConfig = this.ctx.timeService.toHistoryTimewindow(this.timeWindowConfig, startTimeMs, endTimeMs); 391 this.timeWindowConfig = this.ctx.timeService.toHistoryTimewindow(this.timeWindowConfig, startTimeMs, endTimeMs);
372 this.callbacks.timeWindowUpdated(this, this.timeWindowConfig); 392 this.callbacks.timeWindowUpdated(this, this.timeWindowConfig);
  393 + this.unsubscribe();
  394 + this.subscribe();
  395 + this.startWatchingTimewindow();
373 } 396 }
374 } 397 }
375 398
@@ -342,6 +342,7 @@ function Utils($mdColorPalette, $rootScope, $window, $q, deviceService, types) { @@ -342,6 +342,7 @@ function Utils($mdColorPalette, $rootScope, $window, $q, deviceService, types) {
342 datasource = { 342 datasource = {
343 type: subscriptionInfo.type, 343 type: subscriptionInfo.type,
344 deviceName: device.name, 344 deviceName: device.name,
  345 + name: device.name,
345 deviceId: device.id.id, 346 deviceId: device.id.id,
346 dataKeys: [] 347 dataKeys: []
347 } 348 }
@@ -72,7 +72,7 @@ export default function AttributeTableDirective($compile, $templateCache, $rootS @@ -72,7 +72,7 @@ export default function AttributeTableDirective($compile, $templateCache, $rootS
72 scope.$watch("deviceId", function(newVal, prevVal) { 72 scope.$watch("deviceId", function(newVal, prevVal) {
73 if (newVal && !angular.equals(newVal, prevVal)) { 73 if (newVal && !angular.equals(newVal, prevVal)) {
74 scope.resetFilter(); 74 scope.resetFilter();
75 - scope.getDeviceAttributes(); 75 + scope.getDeviceAttributes(false, true);
76 } 76 }
77 }); 77 });
78 78
@@ -81,7 +81,7 @@ export default function AttributeTableDirective($compile, $templateCache, $rootS @@ -81,7 +81,7 @@ export default function AttributeTableDirective($compile, $templateCache, $rootS
81 scope.mode = 'default'; 81 scope.mode = 'default';
82 scope.query.search = null; 82 scope.query.search = null;
83 scope.selectedAttributes = []; 83 scope.selectedAttributes = [];
84 - scope.getDeviceAttributes(); 84 + scope.getDeviceAttributes(false, true);
85 } 85 }
86 }); 86 });
87 87
@@ -117,15 +117,25 @@ export default function AttributeTableDirective($compile, $templateCache, $rootS @@ -117,15 +117,25 @@ export default function AttributeTableDirective($compile, $templateCache, $rootS
117 } 117 }
118 } 118 }
119 119
120 - scope.getDeviceAttributes = function(forceUpdate) { 120 + scope.onReorder = function() {
  121 + scope.getDeviceAttributes(false, false);
  122 + }
  123 +
  124 + scope.onPaginate = function() {
  125 + scope.getDeviceAttributes(false, false);
  126 + }
  127 +
  128 + scope.getDeviceAttributes = function(forceUpdate, reset) {
121 if (scope.attributesDeferred) { 129 if (scope.attributesDeferred) {
122 scope.attributesDeferred.resolve(); 130 scope.attributesDeferred.resolve();
123 } 131 }
124 if (scope.deviceId && scope.attributeScope) { 132 if (scope.deviceId && scope.attributeScope) {
125 - scope.attributes = {  
126 - count: 0,  
127 - data: []  
128 - }; 133 + if (reset) {
  134 + scope.attributes = {
  135 + count: 0,
  136 + data: []
  137 + };
  138 + }
129 scope.checkSubscription(); 139 scope.checkSubscription();
130 scope.attributesDeferred = deviceService.getDeviceAttributes(scope.deviceId, scope.attributeScope.value, 140 scope.attributesDeferred = deviceService.getDeviceAttributes(scope.deviceId, scope.attributeScope.value,
131 scope.query, function(attributes, update, apply) { 141 scope.query, function(attributes, update, apply) {
@@ -126,7 +126,7 @@ @@ -126,7 +126,7 @@
126 </md-toolbar> 126 </md-toolbar>
127 <md-table-container ng-show="mode!='widget'"> 127 <md-table-container ng-show="mode!='widget'">
128 <table md-table md-row-select multiple="" ng-model="selectedAttributes" md-progress="attributesDeferred.promise"> 128 <table md-table md-row-select multiple="" ng-model="selectedAttributes" md-progress="attributesDeferred.promise">
129 - <thead md-head md-order="query.order" md-on-reorder="getDeviceAttributes"> 129 + <thead md-head md-order="query.order" md-on-reorder="onReorder">
130 <tr md-row> 130 <tr md-row>
131 <th md-column md-order-by="lastUpdateTs"><span>Last update time</span></th> 131 <th md-column md-order-by="lastUpdateTs"><span>Last update time</span></th>
132 <th md-column md-order-by="key"><span>Key</span></th> 132 <th md-column md-order-by="key"><span>Key</span></th>
@@ -147,7 +147,7 @@ @@ -147,7 +147,7 @@
147 </md-table-container> 147 </md-table-container>
148 <md-table-pagination ng-show="mode!='widget'" md-limit="query.limit" md-limit-options="[5, 10, 15]" 148 <md-table-pagination ng-show="mode!='widget'" md-limit="query.limit" md-limit-options="[5, 10, 15]"
149 md-page="query.page" md-total="{{attributes.count}}" 149 md-page="query.page" md-total="{{attributes.count}}"
150 - md-on-paginate="getDeviceAttributes" md-page-select> 150 + md-on-paginate="onPaginate" md-page-select>
151 </md-table-pagination> 151 </md-table-pagination>
152 <ul flex rn-carousel ng-if="mode==='widget'" class="widgets-carousel" 152 <ul flex rn-carousel ng-if="mode==='widget'" class="widgets-carousel"
153 rn-carousel-index="widgetsCarousel.index" 153 rn-carousel-index="widgetsCarousel.index"
@@ -374,6 +374,10 @@ export default class TbFlot { @@ -374,6 +374,10 @@ export default class TbFlot {
374 } 374 }
375 375
376 update() { 376 update() {
  377 + if (this.updateTimeoutHandle) {
  378 + this.ctx.$scope.$timeout.cancel(this.updateTimeoutHandle);
  379 + this.updateTimeoutHandle = null;
  380 + }
377 if (this.subscription) { 381 if (this.subscription) {
378 if (!this.isMouseInteraction && this.ctx.plot) { 382 if (!this.isMouseInteraction && this.ctx.plot) {
379 if (this.chartType === 'line' || this.chartType === 'bar') { 383 if (this.chartType === 'line' || this.chartType === 'bar') {
@@ -396,6 +400,11 @@ export default class TbFlot { @@ -396,6 +400,11 @@ export default class TbFlot {
396 this.ctx.plot.draw(); 400 this.ctx.plot.draw();
397 } 401 }
398 } 402 }
  403 + } else if (this.isMouseInteraction && this.ctx.plot){
  404 + var tbFlot = this;
  405 + this.updateTimeoutHandle = this.ctx.$scope.$timeout(function() {
  406 + tbFlot.update();
  407 + }, 30, false);
399 } 408 }
400 } 409 }
401 } 410 }
@@ -217,7 +217,9 @@ export default class TbGoogleMap { @@ -217,7 +217,9 @@ export default class TbGoogleMap {
217 this.updateMarkerImage(marker, settings, settings.markerImage, settings.markerImageSize || 34); 217 this.updateMarkerImage(marker, settings, settings.markerImage, settings.markerImageSize || 34);
218 } 218 }
219 219
220 - this.createTooltip(marker, settings.tooltipPattern, settings.tooltipReplaceInfo); 220 + if (settings.displayTooltip) {
  221 + this.createTooltip(marker, settings.tooltipPattern, settings.tooltipReplaceInfo);
  222 + }
221 223
222 if (onClickListener) { 224 if (onClickListener) {
223 marker.addListener('click', onClickListener); 225 marker.addListener('click', onClickListener);
@@ -19,7 +19,7 @@ import tinycolor from 'tinycolor2'; @@ -19,7 +19,7 @@ import tinycolor from 'tinycolor2';
19 import TbGoogleMap from './google-map'; 19 import TbGoogleMap from './google-map';
20 import TbOpenStreetMap from './openstreet-map'; 20 import TbOpenStreetMap from './openstreet-map';
21 21
22 -function procesTooltipPattern(tbMap, pattern, datasources) { 22 +function procesTooltipPattern(tbMap, pattern, datasources, dsIndex) {
23 var match = tbMap.varsRegex.exec(pattern); 23 var match = tbMap.varsRegex.exec(pattern);
24 var replaceInfo = {}; 24 var replaceInfo = {};
25 replaceInfo.variables = []; 25 replaceInfo.variables = [];
@@ -48,11 +48,13 @@ function procesTooltipPattern(tbMap, pattern, datasources) { @@ -48,11 +48,13 @@ function procesTooltipPattern(tbMap, pattern, datasources) {
48 var offset = 0; 48 var offset = 0;
49 for (var i=0;i<datasources.length;i++) { 49 for (var i=0;i<datasources.length;i++) {
50 var datasource = datasources[i]; 50 var datasource = datasources[i];
51 - for (var k = 0; k < datasource.dataKeys.length; k++) {  
52 - var dataKey = datasource.dataKeys[k];  
53 - if (dataKey.label === label) {  
54 - variableInfo.dataKeyIndex = offset + k;  
55 - break; 51 + if (angular.isUndefined(dsIndex) || dsIndex == i) {
  52 + for (var k = 0; k < datasource.dataKeys.length; k++) {
  53 + var dataKey = datasource.dataKeys[k];
  54 + if (dataKey.label === label) {
  55 + variableInfo.dataKeyIndex = offset + k;
  56 + break;
  57 + }
56 } 58 }
57 } 59 }
58 offset += datasource.dataKeys.length; 60 offset += datasource.dataKeys.length;
@@ -168,6 +170,7 @@ export default class TbMapWidget { @@ -168,6 +170,7 @@ export default class TbMapWidget {
168 latKeyName: localLatKeyName, 170 latKeyName: localLatKeyName,
169 lngKeyName: localLngKeyName, 171 lngKeyName: localLngKeyName,
170 showLabel: subscriptionLocationSettings.showLabel !== false, 172 showLabel: subscriptionLocationSettings.showLabel !== false,
  173 + displayTooltip: subscriptionLocationSettings.displayTooltip !== false,
171 label: datasource.name, 174 label: datasource.name,
172 labelColor: this.ctx.widgetConfig.color || '#000000', 175 labelColor: this.ctx.widgetConfig.color || '#000000',
173 color: "#FE7569", 176 color: "#FE7569",
@@ -179,10 +182,10 @@ export default class TbMapWidget { @@ -179,10 +182,10 @@ export default class TbMapWidget {
179 useMarkerImageFunction: false, 182 useMarkerImageFunction: false,
180 markerImageFunction: null, 183 markerImageFunction: null,
181 markerImages: [], 184 markerImages: [],
182 - tooltipPattern: "<b>Latitude:</b> ${#"+latKeyIndex+":7}<br/><b>Longitude:</b> ${#"+lngKeyIndex+":7}" 185 + tooltipPattern: subscriptionLocationSettings.tooltipPattern || "<b>Latitude:</b> ${latitude:7}<br/><b>Longitude:</b> ${longitude:7}"
183 }; 186 };
184 187
185 - locationsSettings.tooltipReplaceInfo = procesTooltipPattern(this, locationsSettings.tooltipPattern, this.subscription.datasources); 188 + locationsSettings.tooltipReplaceInfo = procesTooltipPattern(this, locationsSettings.tooltipPattern, this.subscription.datasources, i);
186 189
187 locationsSettings.useColorFunction = subscriptionLocationSettings.useColorFunction === true; 190 locationsSettings.useColorFunction = subscriptionLocationSettings.useColorFunction === true;
188 if (angular.isDefined(subscriptionLocationSettings.colorFunction) && subscriptionLocationSettings.colorFunction.length > 0) { 191 if (angular.isDefined(subscriptionLocationSettings.colorFunction) && subscriptionLocationSettings.colorFunction.length > 0) {
@@ -211,6 +214,7 @@ export default class TbMapWidget { @@ -211,6 +214,7 @@ export default class TbMapWidget {
211 latKeyName: "lat", 214 latKeyName: "lat",
212 lngKeyName: "lng", 215 lngKeyName: "lng",
213 showLabel: true, 216 showLabel: true,
  217 + displayTooltip: true,
214 label: "", 218 label: "",
215 labelColor: this.ctx.widgetConfig.color || '#000000', 219 labelColor: this.ctx.widgetConfig.color || '#000000',
216 color: "#FE7569", 220 color: "#FE7569",
@@ -109,7 +109,9 @@ export default class TbOpenStreetMap { @@ -109,7 +109,9 @@ export default class TbOpenStreetMap {
109 this.updateMarkerImage(marker, settings, settings.markerImage, settings.markerImageSize || 34); 109 this.updateMarkerImage(marker, settings, settings.markerImage, settings.markerImageSize || 34);
110 } 110 }
111 111
112 - this.createTooltip(marker, settings.tooltipPattern, settings.tooltipReplaceInfo); 112 + if (settings.displayTooltip) {
  113 + this.createTooltip(marker, settings.tooltipPattern, settings.tooltipReplaceInfo);
  114 + }
113 115
114 if (onClickListener) { 116 if (onClickListener) {
115 marker.on('click', onClickListener); 117 marker.on('click', onClickListener);