Configurable max datapoints limit for Aggregation NONE
This commit is contained in:
		
							parent
							
								
									99dde0cf69
								
							
						
					
					
						commit
						2f4df28036
					
				@ -15,6 +15,8 @@
 | 
			
		||||
 */
 | 
			
		||||
package org.thingsboard.server.controller;
 | 
			
		||||
 | 
			
		||||
import lombok.Getter;
 | 
			
		||||
import org.springframework.beans.factory.annotation.Value;
 | 
			
		||||
import org.springframework.http.HttpStatus;
 | 
			
		||||
import org.springframework.security.access.prepost.PreAuthorize;
 | 
			
		||||
import org.springframework.web.bind.annotation.PathVariable;
 | 
			
		||||
@ -49,6 +51,11 @@ public class DashboardController extends BaseController {
 | 
			
		||||
 | 
			
		||||
    public static final String DASHBOARD_ID = "dashboardId";
 | 
			
		||||
 | 
			
		||||
    @Value("${dashboard.max_datapoints_limit}")
 | 
			
		||||
    @Getter
 | 
			
		||||
    private long maxDatapointsLimit;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
 | 
			
		||||
    @RequestMapping(value = "/dashboard/serverTime", method = RequestMethod.GET)
 | 
			
		||||
    @ResponseBody
 | 
			
		||||
@ -56,6 +63,13 @@ public class DashboardController extends BaseController {
 | 
			
		||||
        return System.currentTimeMillis();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
 | 
			
		||||
    @RequestMapping(value = "/dashboard/maxDatapointsLimit", method = RequestMethod.GET)
 | 
			
		||||
    @ResponseBody
 | 
			
		||||
    public long getMaxDatapointsLimit() throws ThingsboardException {
 | 
			
		||||
        return maxDatapointsLimit;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
 | 
			
		||||
    @RequestMapping(value = "/dashboard/info/{dashboardId}", method = RequestMethod.GET)
 | 
			
		||||
    @ResponseBody
 | 
			
		||||
 | 
			
		||||
@ -77,6 +77,11 @@ security:
 | 
			
		||||
  # Enable/disable access to Tenant Administrators JWT token by System Administrator or Customer Users JWT token by Tenant Administrator
 | 
			
		||||
  user_token_access_enabled: "${SECURITY_USER_TOKEN_ACCESS_ENABLED:true}"
 | 
			
		||||
 | 
			
		||||
# Dashboard parameters
 | 
			
		||||
dashboard:
 | 
			
		||||
  # Maximum allowed datapoints fetched by widgets
 | 
			
		||||
  max_datapoints_limit: "${DASHBOARD_MAX_DATAPOINTS_LIMIT:50000}"
 | 
			
		||||
 | 
			
		||||
# Device communication protocol parameters
 | 
			
		||||
http:
 | 
			
		||||
  request_timeout: "${HTTP_REQUEST_TIMEOUT:60000}"
 | 
			
		||||
 | 
			
		||||
@ -26,15 +26,17 @@ const MIN_INTERVAL = SECOND;
 | 
			
		||||
const MAX_INTERVAL = 365 * 20 * DAY;
 | 
			
		||||
 | 
			
		||||
const MIN_LIMIT = 10;
 | 
			
		||||
const AVG_LIMIT = 200;
 | 
			
		||||
const MAX_LIMIT = 500;
 | 
			
		||||
//const AVG_LIMIT = 200;
 | 
			
		||||
//const MAX_LIMIT = 500;
 | 
			
		||||
 | 
			
		||||
/*@ngInject*/
 | 
			
		||||
function TimeService($translate, types) {
 | 
			
		||||
function TimeService($translate, $http, $q, types) {
 | 
			
		||||
 | 
			
		||||
    var predefIntervals;
 | 
			
		||||
    var maxDatapointsLimit;
 | 
			
		||||
 | 
			
		||||
    var service = {
 | 
			
		||||
        loadMaxDatapointsLimit: loadMaxDatapointsLimit,
 | 
			
		||||
        minIntervalLimit: minIntervalLimit,
 | 
			
		||||
        maxIntervalLimit: maxIntervalLimit,
 | 
			
		||||
        boundMinInterval: boundMinInterval,
 | 
			
		||||
@ -45,20 +47,38 @@ function TimeService($translate, types) {
 | 
			
		||||
        defaultTimewindow: defaultTimewindow,
 | 
			
		||||
        toHistoryTimewindow: toHistoryTimewindow,
 | 
			
		||||
        createSubscriptionTimewindow: createSubscriptionTimewindow,
 | 
			
		||||
        avgAggregationLimit: function () {
 | 
			
		||||
            return AVG_LIMIT;
 | 
			
		||||
        getMaxDatapointsLimit: function () {
 | 
			
		||||
            return maxDatapointsLimit;
 | 
			
		||||
        },
 | 
			
		||||
        getMinDatapointsLimit: function () {
 | 
			
		||||
            return MIN_LIMIT;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return service;
 | 
			
		||||
 | 
			
		||||
    function loadMaxDatapointsLimit() {
 | 
			
		||||
        var deferred = $q.defer();
 | 
			
		||||
        var url = '/api/dashboard/maxDatapointsLimit';
 | 
			
		||||
        $http.get(url, {ignoreLoading: true}).then(function success(response) {
 | 
			
		||||
            maxDatapointsLimit = response.data;
 | 
			
		||||
            if (!maxDatapointsLimit || maxDatapointsLimit <= MIN_LIMIT) {
 | 
			
		||||
                maxDatapointsLimit = MIN_LIMIT + 1;
 | 
			
		||||
            }
 | 
			
		||||
            deferred.resolve();
 | 
			
		||||
        }, function fail() {
 | 
			
		||||
            deferred.reject();
 | 
			
		||||
        });
 | 
			
		||||
        return deferred.promise;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function minIntervalLimit(timewindow) {
 | 
			
		||||
        var min = timewindow / MAX_LIMIT;
 | 
			
		||||
        var min = timewindow / 500;
 | 
			
		||||
        return boundMinInterval(min);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function avgInterval(timewindow) {
 | 
			
		||||
        var avg = timewindow / AVG_LIMIT;
 | 
			
		||||
        var avg = timewindow / 200;
 | 
			
		||||
        return boundMinInterval(avg);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -230,7 +250,7 @@ function TimeService($translate, types) {
 | 
			
		||||
            },
 | 
			
		||||
            aggregation: {
 | 
			
		||||
                type: types.aggregation.avg.value,
 | 
			
		||||
                limit: AVG_LIMIT
 | 
			
		||||
                limit: Math.floor(maxDatapointsLimit / 2)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return timewindow;
 | 
			
		||||
@ -246,22 +266,27 @@ function TimeService($translate, types) {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        var aggType;
 | 
			
		||||
        var limit;
 | 
			
		||||
        if (timewindow.aggregation) {
 | 
			
		||||
            aggType = timewindow.aggregation.type || types.aggregation.avg.value;
 | 
			
		||||
            limit = timewindow.aggregation.limit || maxDatapointsLimit;
 | 
			
		||||
        } else {
 | 
			
		||||
            aggType = types.aggregation.avg.value;
 | 
			
		||||
            limit = maxDatapointsLimit;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        var historyTimewindow = {
 | 
			
		||||
            history: {
 | 
			
		||||
                fixedTimewindow: {
 | 
			
		||||
                    startTimeMs: startTimeMs,
 | 
			
		||||
                    endTimeMs: endTimeMs
 | 
			
		||||
                },
 | 
			
		||||
                interval: boundIntervalToTimewindow(endTimeMs - startTimeMs, interval, aggType)
 | 
			
		||||
                interval: boundIntervalToTimewindow(endTimeMs - startTimeMs, interval, types.aggregation.avg.value)
 | 
			
		||||
            },
 | 
			
		||||
            aggregation: {
 | 
			
		||||
                type: aggType
 | 
			
		||||
                type: aggType,
 | 
			
		||||
                limit: limit
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@ -275,7 +300,7 @@ function TimeService($translate, types) {
 | 
			
		||||
            realtimeWindowMs: null,
 | 
			
		||||
            aggregation: {
 | 
			
		||||
                interval: SECOND,
 | 
			
		||||
                limit: AVG_LIMIT,
 | 
			
		||||
                limit: maxDatapointsLimit,
 | 
			
		||||
                type: types.aggregation.avg.value
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
@ -283,14 +308,14 @@ function TimeService($translate, types) {
 | 
			
		||||
        if (stateData) {
 | 
			
		||||
            subscriptionTimewindow.aggregation = {
 | 
			
		||||
                interval: SECOND,
 | 
			
		||||
                limit: MAX_LIMIT,
 | 
			
		||||
                limit: maxDatapointsLimit,
 | 
			
		||||
                type: types.aggregation.none.value,
 | 
			
		||||
                stateData: true
 | 
			
		||||
            };
 | 
			
		||||
        } else {
 | 
			
		||||
            subscriptionTimewindow.aggregation = {
 | 
			
		||||
                interval: SECOND,
 | 
			
		||||
                limit: AVG_LIMIT,
 | 
			
		||||
                limit: maxDatapointsLimit,
 | 
			
		||||
                type: types.aggregation.avg.value
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
@ -298,7 +323,7 @@ function TimeService($translate, types) {
 | 
			
		||||
        if (angular.isDefined(timewindow.aggregation) && !stateData) {
 | 
			
		||||
            subscriptionTimewindow.aggregation = {
 | 
			
		||||
                type: timewindow.aggregation.type || types.aggregation.avg.value,
 | 
			
		||||
                limit: timewindow.aggregation.limit || AVG_LIMIT
 | 
			
		||||
                limit: timewindow.aggregation.limit || maxDatapointsLimit
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
        if (angular.isDefined(timewindow.realtime)) {
 | 
			
		||||
 | 
			
		||||
@ -22,7 +22,7 @@ export default angular.module('thingsboard.api.user', [thingsboardApiLogin,
 | 
			
		||||
    .name;
 | 
			
		||||
 | 
			
		||||
/*@ngInject*/
 | 
			
		||||
function UserService($http, $q, $rootScope, adminService, dashboardService, loginService, toast, store, jwtHelper, $translate, $state, $location) {
 | 
			
		||||
function UserService($http, $q, $rootScope, adminService, dashboardService, timeService, loginService, toast, store, jwtHelper, $translate, $state, $location) {
 | 
			
		||||
    var currentUser = null,
 | 
			
		||||
        currentUserDetails = null,
 | 
			
		||||
        lastPublicDashboardId = null,
 | 
			
		||||
@ -390,6 +390,7 @@ function UserService($http, $q, $rootScope, adminService, dashboardService, logi
 | 
			
		||||
    function loadSystemParams() {
 | 
			
		||||
        var promises = [];
 | 
			
		||||
        promises.push(loadIsUserTokenAccessEnabled());
 | 
			
		||||
        promises.push(timeService.loadMaxDatapointsLimit());
 | 
			
		||||
        return $q.all(promises);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -31,6 +31,8 @@ export default function TimewindowPanelController(mdPanelRef, $scope, timeServic
 | 
			
		||||
    vm.maxRealtimeAggInterval = maxRealtimeAggInterval;
 | 
			
		||||
    vm.minHistoryAggInterval = minHistoryAggInterval;
 | 
			
		||||
    vm.maxHistoryAggInterval = maxHistoryAggInterval;
 | 
			
		||||
    vm.minDatapointsLimit = minDatapointsLimit;
 | 
			
		||||
    vm.maxDatapointsLimit = maxDatapointsLimit;
 | 
			
		||||
 | 
			
		||||
    if (vm.historyOnly) {
 | 
			
		||||
        vm.timewindow.selectedTab = 1;
 | 
			
		||||
@ -86,6 +88,14 @@ export default function TimewindowPanelController(mdPanelRef, $scope, timeServic
 | 
			
		||||
        return timeService.maxIntervalLimit(currentHistoryTimewindow());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function minDatapointsLimit () {
 | 
			
		||||
        return timeService.getMinDatapointsLimit();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function maxDatapointsLimit () {
 | 
			
		||||
        return timeService.getMaxDatapointsLimit();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function currentHistoryTimewindow() {
 | 
			
		||||
        if (vm.timewindow.history.historyType === 0) {
 | 
			
		||||
            return vm.timewindow.history.timewindowMs;
 | 
			
		||||
 | 
			
		||||
@ -60,19 +60,22 @@
 | 
			
		||||
							</md-option>
 | 
			
		||||
						</md-select>
 | 
			
		||||
					</md-input-container>
 | 
			
		||||
					<md-slider-container ng-show="vm.showLimit()">
 | 
			
		||||
					<md-slider-container ng-if="vm.showLimit()">
 | 
			
		||||
						<span translate>aggregation.limit</span>
 | 
			
		||||
						<md-slider flex min="10" max="500" ng-model="vm.timewindow.aggregation.limit" aria-label="limit" id="limit-slider">
 | 
			
		||||
						<md-slider flex min="{{vm.minDatapointsLimit()}}" max="{{vm.maxDatapointsLimit()}}" step="1"
 | 
			
		||||
                                   ng-model="vm.timewindow.aggregation.limit" aria-label="limit" id="limit-slider">
 | 
			
		||||
						</md-slider>
 | 
			
		||||
						<md-input-container>
 | 
			
		||||
							<input flex type="number" ng-model="vm.timewindow.aggregation.limit" aria-label="limit" aria-controls="limit-slider">
 | 
			
		||||
						<md-input-container style="max-width: 80px;">
 | 
			
		||||
							<input flex type="number" step="1"
 | 
			
		||||
                                   min="{{vm.minDatapointsLimit()}}" max="{{vm.maxDatapointsLimit()}}"
 | 
			
		||||
                                   ng-model="vm.timewindow.aggregation.limit" aria-label="limit" aria-controls="limit-slider">
 | 
			
		||||
						</md-input-container>
 | 
			
		||||
					</md-slider-container>
 | 
			
		||||
					<tb-timeinterval ng-show="vm.showRealtimeAggInterval()" min="vm.minRealtimeAggInterval()" max="vm.maxRealtimeAggInterval()"
 | 
			
		||||
					<tb-timeinterval ng-if="vm.showRealtimeAggInterval()" min="vm.minRealtimeAggInterval()" max="vm.maxRealtimeAggInterval()"
 | 
			
		||||
									 predefined-name="'aggregation.group-interval'"
 | 
			
		||||
									 ng-model="vm.timewindow.realtime.interval">
 | 
			
		||||
					</tb-timeinterval>
 | 
			
		||||
					<tb-timeinterval ng-show="vm.showHistoryAggInterval()" min="vm.minHistoryAggInterval()" max="vm.maxHistoryAggInterval()"
 | 
			
		||||
					<tb-timeinterval ng-if="vm.showHistoryAggInterval()" min="vm.minHistoryAggInterval()" max="vm.maxHistoryAggInterval()"
 | 
			
		||||
									 predefined-name="'aggregation.group-interval'"
 | 
			
		||||
									 ng-model="vm.timewindow.history.interval">
 | 
			
		||||
					</tb-timeinterval>
 | 
			
		||||
 | 
			
		||||
@ -228,7 +228,7 @@ function Timewindow($compile, $templateCache, $filter, $mdPanel, $document, $mdM
 | 
			
		||||
                    if (angular.isDefined(value.aggregation.type) && value.aggregation.type.length > 0) {
 | 
			
		||||
                        model.aggregation.type = value.aggregation.type;
 | 
			
		||||
                    }
 | 
			
		||||
                    model.aggregation.limit = value.aggregation.limit || timeService.avgAggregationLimit();
 | 
			
		||||
                    model.aggregation.limit = value.aggregation.limit || Math.floor(timeService.getMaxDatapointsLimit() / 2);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            scope.updateDisplayValue();
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user