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;
|
package org.thingsboard.server.controller;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
import org.springframework.security.access.prepost.PreAuthorize;
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
import org.springframework.web.bind.annotation.PathVariable;
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
@ -49,6 +51,11 @@ public class DashboardController extends BaseController {
|
|||||||
|
|
||||||
public static final String DASHBOARD_ID = "dashboardId";
|
public static final String DASHBOARD_ID = "dashboardId";
|
||||||
|
|
||||||
|
@Value("${dashboard.max_datapoints_limit}")
|
||||||
|
@Getter
|
||||||
|
private long maxDatapointsLimit;
|
||||||
|
|
||||||
|
|
||||||
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
|
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
|
||||||
@RequestMapping(value = "/dashboard/serverTime", method = RequestMethod.GET)
|
@RequestMapping(value = "/dashboard/serverTime", method = RequestMethod.GET)
|
||||||
@ResponseBody
|
@ResponseBody
|
||||||
@ -56,6 +63,13 @@ public class DashboardController extends BaseController {
|
|||||||
return System.currentTimeMillis();
|
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')")
|
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
|
||||||
@RequestMapping(value = "/dashboard/info/{dashboardId}", method = RequestMethod.GET)
|
@RequestMapping(value = "/dashboard/info/{dashboardId}", method = RequestMethod.GET)
|
||||||
@ResponseBody
|
@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
|
# 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}"
|
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
|
# Device communication protocol parameters
|
||||||
http:
|
http:
|
||||||
request_timeout: "${HTTP_REQUEST_TIMEOUT:60000}"
|
request_timeout: "${HTTP_REQUEST_TIMEOUT:60000}"
|
||||||
|
|||||||
@ -26,15 +26,17 @@ const MIN_INTERVAL = SECOND;
|
|||||||
const MAX_INTERVAL = 365 * 20 * DAY;
|
const MAX_INTERVAL = 365 * 20 * DAY;
|
||||||
|
|
||||||
const MIN_LIMIT = 10;
|
const MIN_LIMIT = 10;
|
||||||
const AVG_LIMIT = 200;
|
//const AVG_LIMIT = 200;
|
||||||
const MAX_LIMIT = 500;
|
//const MAX_LIMIT = 500;
|
||||||
|
|
||||||
/*@ngInject*/
|
/*@ngInject*/
|
||||||
function TimeService($translate, types) {
|
function TimeService($translate, $http, $q, types) {
|
||||||
|
|
||||||
var predefIntervals;
|
var predefIntervals;
|
||||||
|
var maxDatapointsLimit;
|
||||||
|
|
||||||
var service = {
|
var service = {
|
||||||
|
loadMaxDatapointsLimit: loadMaxDatapointsLimit,
|
||||||
minIntervalLimit: minIntervalLimit,
|
minIntervalLimit: minIntervalLimit,
|
||||||
maxIntervalLimit: maxIntervalLimit,
|
maxIntervalLimit: maxIntervalLimit,
|
||||||
boundMinInterval: boundMinInterval,
|
boundMinInterval: boundMinInterval,
|
||||||
@ -45,20 +47,38 @@ function TimeService($translate, types) {
|
|||||||
defaultTimewindow: defaultTimewindow,
|
defaultTimewindow: defaultTimewindow,
|
||||||
toHistoryTimewindow: toHistoryTimewindow,
|
toHistoryTimewindow: toHistoryTimewindow,
|
||||||
createSubscriptionTimewindow: createSubscriptionTimewindow,
|
createSubscriptionTimewindow: createSubscriptionTimewindow,
|
||||||
avgAggregationLimit: function () {
|
getMaxDatapointsLimit: function () {
|
||||||
return AVG_LIMIT;
|
return maxDatapointsLimit;
|
||||||
|
},
|
||||||
|
getMinDatapointsLimit: function () {
|
||||||
|
return MIN_LIMIT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return service;
|
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) {
|
function minIntervalLimit(timewindow) {
|
||||||
var min = timewindow / MAX_LIMIT;
|
var min = timewindow / 500;
|
||||||
return boundMinInterval(min);
|
return boundMinInterval(min);
|
||||||
}
|
}
|
||||||
|
|
||||||
function avgInterval(timewindow) {
|
function avgInterval(timewindow) {
|
||||||
var avg = timewindow / AVG_LIMIT;
|
var avg = timewindow / 200;
|
||||||
return boundMinInterval(avg);
|
return boundMinInterval(avg);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -230,7 +250,7 @@ function TimeService($translate, types) {
|
|||||||
},
|
},
|
||||||
aggregation: {
|
aggregation: {
|
||||||
type: types.aggregation.avg.value,
|
type: types.aggregation.avg.value,
|
||||||
limit: AVG_LIMIT
|
limit: Math.floor(maxDatapointsLimit / 2)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return timewindow;
|
return timewindow;
|
||||||
@ -246,22 +266,27 @@ function TimeService($translate, types) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var aggType;
|
var aggType;
|
||||||
|
var limit;
|
||||||
if (timewindow.aggregation) {
|
if (timewindow.aggregation) {
|
||||||
aggType = timewindow.aggregation.type || types.aggregation.avg.value;
|
aggType = timewindow.aggregation.type || types.aggregation.avg.value;
|
||||||
|
limit = timewindow.aggregation.limit || maxDatapointsLimit;
|
||||||
} else {
|
} else {
|
||||||
aggType = types.aggregation.avg.value;
|
aggType = types.aggregation.avg.value;
|
||||||
|
limit = maxDatapointsLimit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
var historyTimewindow = {
|
var historyTimewindow = {
|
||||||
history: {
|
history: {
|
||||||
fixedTimewindow: {
|
fixedTimewindow: {
|
||||||
startTimeMs: startTimeMs,
|
startTimeMs: startTimeMs,
|
||||||
endTimeMs: endTimeMs
|
endTimeMs: endTimeMs
|
||||||
},
|
},
|
||||||
interval: boundIntervalToTimewindow(endTimeMs - startTimeMs, interval, aggType)
|
interval: boundIntervalToTimewindow(endTimeMs - startTimeMs, interval, types.aggregation.avg.value)
|
||||||
},
|
},
|
||||||
aggregation: {
|
aggregation: {
|
||||||
type: aggType
|
type: aggType,
|
||||||
|
limit: limit
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -275,7 +300,7 @@ function TimeService($translate, types) {
|
|||||||
realtimeWindowMs: null,
|
realtimeWindowMs: null,
|
||||||
aggregation: {
|
aggregation: {
|
||||||
interval: SECOND,
|
interval: SECOND,
|
||||||
limit: AVG_LIMIT,
|
limit: maxDatapointsLimit,
|
||||||
type: types.aggregation.avg.value
|
type: types.aggregation.avg.value
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -283,14 +308,14 @@ function TimeService($translate, types) {
|
|||||||
if (stateData) {
|
if (stateData) {
|
||||||
subscriptionTimewindow.aggregation = {
|
subscriptionTimewindow.aggregation = {
|
||||||
interval: SECOND,
|
interval: SECOND,
|
||||||
limit: MAX_LIMIT,
|
limit: maxDatapointsLimit,
|
||||||
type: types.aggregation.none.value,
|
type: types.aggregation.none.value,
|
||||||
stateData: true
|
stateData: true
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
subscriptionTimewindow.aggregation = {
|
subscriptionTimewindow.aggregation = {
|
||||||
interval: SECOND,
|
interval: SECOND,
|
||||||
limit: AVG_LIMIT,
|
limit: maxDatapointsLimit,
|
||||||
type: types.aggregation.avg.value
|
type: types.aggregation.avg.value
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -298,7 +323,7 @@ function TimeService($translate, types) {
|
|||||||
if (angular.isDefined(timewindow.aggregation) && !stateData) {
|
if (angular.isDefined(timewindow.aggregation) && !stateData) {
|
||||||
subscriptionTimewindow.aggregation = {
|
subscriptionTimewindow.aggregation = {
|
||||||
type: timewindow.aggregation.type || types.aggregation.avg.value,
|
type: timewindow.aggregation.type || types.aggregation.avg.value,
|
||||||
limit: timewindow.aggregation.limit || AVG_LIMIT
|
limit: timewindow.aggregation.limit || maxDatapointsLimit
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
if (angular.isDefined(timewindow.realtime)) {
|
if (angular.isDefined(timewindow.realtime)) {
|
||||||
|
|||||||
@ -22,7 +22,7 @@ export default angular.module('thingsboard.api.user', [thingsboardApiLogin,
|
|||||||
.name;
|
.name;
|
||||||
|
|
||||||
/*@ngInject*/
|
/*@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,
|
var currentUser = null,
|
||||||
currentUserDetails = null,
|
currentUserDetails = null,
|
||||||
lastPublicDashboardId = null,
|
lastPublicDashboardId = null,
|
||||||
@ -390,6 +390,7 @@ function UserService($http, $q, $rootScope, adminService, dashboardService, logi
|
|||||||
function loadSystemParams() {
|
function loadSystemParams() {
|
||||||
var promises = [];
|
var promises = [];
|
||||||
promises.push(loadIsUserTokenAccessEnabled());
|
promises.push(loadIsUserTokenAccessEnabled());
|
||||||
|
promises.push(timeService.loadMaxDatapointsLimit());
|
||||||
return $q.all(promises);
|
return $q.all(promises);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -31,6 +31,8 @@ export default function TimewindowPanelController(mdPanelRef, $scope, timeServic
|
|||||||
vm.maxRealtimeAggInterval = maxRealtimeAggInterval;
|
vm.maxRealtimeAggInterval = maxRealtimeAggInterval;
|
||||||
vm.minHistoryAggInterval = minHistoryAggInterval;
|
vm.minHistoryAggInterval = minHistoryAggInterval;
|
||||||
vm.maxHistoryAggInterval = maxHistoryAggInterval;
|
vm.maxHistoryAggInterval = maxHistoryAggInterval;
|
||||||
|
vm.minDatapointsLimit = minDatapointsLimit;
|
||||||
|
vm.maxDatapointsLimit = maxDatapointsLimit;
|
||||||
|
|
||||||
if (vm.historyOnly) {
|
if (vm.historyOnly) {
|
||||||
vm.timewindow.selectedTab = 1;
|
vm.timewindow.selectedTab = 1;
|
||||||
@ -86,6 +88,14 @@ export default function TimewindowPanelController(mdPanelRef, $scope, timeServic
|
|||||||
return timeService.maxIntervalLimit(currentHistoryTimewindow());
|
return timeService.maxIntervalLimit(currentHistoryTimewindow());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function minDatapointsLimit () {
|
||||||
|
return timeService.getMinDatapointsLimit();
|
||||||
|
}
|
||||||
|
|
||||||
|
function maxDatapointsLimit () {
|
||||||
|
return timeService.getMaxDatapointsLimit();
|
||||||
|
}
|
||||||
|
|
||||||
function currentHistoryTimewindow() {
|
function currentHistoryTimewindow() {
|
||||||
if (vm.timewindow.history.historyType === 0) {
|
if (vm.timewindow.history.historyType === 0) {
|
||||||
return vm.timewindow.history.timewindowMs;
|
return vm.timewindow.history.timewindowMs;
|
||||||
|
|||||||
@ -60,19 +60,22 @@
|
|||||||
</md-option>
|
</md-option>
|
||||||
</md-select>
|
</md-select>
|
||||||
</md-input-container>
|
</md-input-container>
|
||||||
<md-slider-container ng-show="vm.showLimit()">
|
<md-slider-container ng-if="vm.showLimit()">
|
||||||
<span translate>aggregation.limit</span>
|
<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-slider>
|
||||||
<md-input-container>
|
<md-input-container style="max-width: 80px;">
|
||||||
<input flex type="number" ng-model="vm.timewindow.aggregation.limit" aria-label="limit" aria-controls="limit-slider">
|
<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-input-container>
|
||||||
</md-slider-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'"
|
predefined-name="'aggregation.group-interval'"
|
||||||
ng-model="vm.timewindow.realtime.interval">
|
ng-model="vm.timewindow.realtime.interval">
|
||||||
</tb-timeinterval>
|
</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'"
|
predefined-name="'aggregation.group-interval'"
|
||||||
ng-model="vm.timewindow.history.interval">
|
ng-model="vm.timewindow.history.interval">
|
||||||
</tb-timeinterval>
|
</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) {
|
if (angular.isDefined(value.aggregation.type) && value.aggregation.type.length > 0) {
|
||||||
model.aggregation.type = value.aggregation.type;
|
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();
|
scope.updateDisplayValue();
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user