mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Dashboard: Adds support for a global minimum dashboard refresh interval (#19416)
This feature would provide a way for administrators to limit the minimum dashboard refresh interval globally. Filters out the refresh intervals available in the time picker that are lower than the set minimum refresh interval in the configuration .ini file Adds the minimum refresh interval as available in the time picker. If the user tries to enter a refresh interval that is lower than the minimum in the URL, defaults to the minimum interval. When trying to update the JSON via the API, rejects the update if the dashboard's refresh interval is lower than the minimum. When trying to update a dashboard via provisioning having a lower refresh interval than the minimum, defaults to the minimum interval and logs a warning. Fixes #3356 Co-authored-by: Marcus Efraimsson <marcus.efraimsson@gmail.com>
This commit is contained in:
parent
1db8849e51
commit
72628c8ea0
@ -230,6 +230,10 @@ snapshot_remove_expired = true
|
|||||||
# Number dashboard versions to keep (per dashboard). Default: 20, Minimum: 1
|
# Number dashboard versions to keep (per dashboard). Default: 20, Minimum: 1
|
||||||
versions_to_keep = 20
|
versions_to_keep = 20
|
||||||
|
|
||||||
|
# Minimum dashboard refresh interval. When set, this will restrict users to set the refresh interval of a dashboard lower than given interval. Per default this is not set/unrestricted.
|
||||||
|
# The interval string is a possibly signed sequence of decimal numbers, followed by a unit suffix (ms, s, m, h, d), e.g. 30s or 1m.
|
||||||
|
min_refresh_interval =
|
||||||
|
|
||||||
#################################### Users ###############################
|
#################################### Users ###############################
|
||||||
[users]
|
[users]
|
||||||
# disable user signup / registration
|
# disable user signup / registration
|
||||||
|
@ -229,6 +229,10 @@
|
|||||||
# Number dashboard versions to keep (per dashboard). Default: 20, Minimum: 1
|
# Number dashboard versions to keep (per dashboard). Default: 20, Minimum: 1
|
||||||
;versions_to_keep = 20
|
;versions_to_keep = 20
|
||||||
|
|
||||||
|
# Minimum dashboard refresh interval. When set, this will restrict users to set the refresh interval of a dashboard lower than given interval. Per default this is not set/unrestricted.
|
||||||
|
# The interval string is a possibly signed sequence of decimal numbers, followed by a unit suffix (ms, s, m, h, d), e.g. 30s or 1m.
|
||||||
|
;min_refresh_interval =
|
||||||
|
|
||||||
#################################### Users ###############################
|
#################################### Users ###############################
|
||||||
[users]
|
[users]
|
||||||
# disable user signup / registration
|
# disable user signup / registration
|
||||||
|
@ -502,6 +502,13 @@ Set to false to disable all checks to https://grafana.com for new versions of in
|
|||||||
|
|
||||||
Number dashboard versions to keep (per dashboard). Default: `20`, Minimum: `1`.
|
Number dashboard versions to keep (per dashboard). Default: `20`, Minimum: `1`.
|
||||||
|
|
||||||
|
### min_refresh_interval
|
||||||
|
|
||||||
|
> Only available in Grafana v6.7+.
|
||||||
|
|
||||||
|
When set, this will restrict users to set the refresh interval of a dashboard lower than given interval. Per default this is not set/unrestricted.
|
||||||
|
The interval string is a possibly signed sequence of decimal numbers, followed by a unit suffix (ms, s, m, h, d), e.g. `30s` or `1m`.
|
||||||
|
|
||||||
## [dashboards.json]
|
## [dashboards.json]
|
||||||
|
|
||||||
> This have been replaced with dashboards [provisioning]({{< relref "../administration/provisioning" >}}) in 5.0+
|
> This have been replaced with dashboards [provisioning]({{< relref "../administration/provisioning" >}}) in 5.0+
|
||||||
|
@ -30,6 +30,7 @@ interface LicenseInfo {
|
|||||||
export class GrafanaBootConfig {
|
export class GrafanaBootConfig {
|
||||||
datasources: { [str: string]: DataSourceInstanceSettings } = {};
|
datasources: { [str: string]: DataSourceInstanceSettings } = {};
|
||||||
panels: { [key: string]: PanelPluginMeta } = {};
|
panels: { [key: string]: PanelPluginMeta } = {};
|
||||||
|
minRefreshInterval = '';
|
||||||
appSubUrl = '';
|
appSubUrl = '';
|
||||||
windowTitlePrefix = '';
|
windowTitlePrefix = '';
|
||||||
buildInfo: BuildInfo = {} as BuildInfo;
|
buildInfo: BuildInfo = {} as BuildInfo;
|
||||||
|
@ -8,7 +8,7 @@ import memoizeOne from 'memoize-one';
|
|||||||
import { GrafanaTheme } from '@grafana/data';
|
import { GrafanaTheme } from '@grafana/data';
|
||||||
import { withTheme } from '../../themes';
|
import { withTheme } from '../../themes';
|
||||||
|
|
||||||
const defaultIntervals = ['5s', '10s', '30s', '1m', '5m', '15m', '30m', '1h', '2h', '1d'];
|
export const defaultIntervals = ['5s', '10s', '30s', '1m', '5m', '15m', '30m', '1h', '2h', '1d'];
|
||||||
|
|
||||||
const getStyles = memoizeOne((theme: GrafanaTheme) => {
|
const getStyles = memoizeOne((theme: GrafanaTheme) => {
|
||||||
return {
|
return {
|
||||||
@ -45,9 +45,7 @@ export class RefreshPickerBase extends PureComponent<Props> {
|
|||||||
|
|
||||||
intervalsToOptions = (intervals: string[] | undefined): Array<SelectableValue<string>> => {
|
intervalsToOptions = (intervals: string[] | undefined): Array<SelectableValue<string>> => {
|
||||||
const intervalsOrDefault = intervals || defaultIntervals;
|
const intervalsOrDefault = intervals || defaultIntervals;
|
||||||
const options = intervalsOrDefault
|
const options = intervalsOrDefault.map(interval => ({ label: interval, value: interval }));
|
||||||
.filter(str => str !== '')
|
|
||||||
.map(interval => ({ label: interval, value: interval }));
|
|
||||||
|
|
||||||
if (this.props.hasLiveOption) {
|
if (this.props.hasLiveOption) {
|
||||||
options.unshift(RefreshPicker.liveOption);
|
options.unshift(RefreshPicker.liveOption);
|
||||||
|
@ -278,6 +278,7 @@ func dashboardSaveErrorToApiResponse(err error) Response {
|
|||||||
err == m.ErrFolderNotFound ||
|
err == m.ErrFolderNotFound ||
|
||||||
err == m.ErrDashboardFolderCannotHaveParent ||
|
err == m.ErrDashboardFolderCannotHaveParent ||
|
||||||
err == m.ErrDashboardFolderNameExists ||
|
err == m.ErrDashboardFolderNameExists ||
|
||||||
|
err == m.ErrDashboardRefreshIntervalTooShort ||
|
||||||
err == m.ErrDashboardCannotSaveProvisionedDashboard {
|
err == m.ErrDashboardCannotSaveProvisionedDashboard {
|
||||||
return Error(400, err.Error(), nil)
|
return Error(400, err.Error(), nil)
|
||||||
}
|
}
|
||||||
|
@ -170,6 +170,7 @@ func (hs *HTTPServer) getFrontendSettingsMap(c *m.ReqContext) (map[string]interf
|
|||||||
jsonObj := map[string]interface{}{
|
jsonObj := map[string]interface{}{
|
||||||
"defaultDatasource": defaultDatasource,
|
"defaultDatasource": defaultDatasource,
|
||||||
"datasources": datasources,
|
"datasources": datasources,
|
||||||
|
"minRefreshInterval": setting.MinRefreshInterval,
|
||||||
"panels": panels,
|
"panels": panels,
|
||||||
"appSubUrl": setting.AppSubUrl,
|
"appSubUrl": setting.AppSubUrl,
|
||||||
"allowOrgCreate": (setting.AllowUserOrgCreate && c.IsSignedIn) || c.IsGrafanaAdmin,
|
"allowOrgCreate": (setting.AllowUserOrgCreate && c.IsSignedIn) || c.IsGrafanaAdmin,
|
||||||
|
@ -31,6 +31,7 @@ var (
|
|||||||
ErrDashboardInvalidUid = errors.New("uid contains illegal characters")
|
ErrDashboardInvalidUid = errors.New("uid contains illegal characters")
|
||||||
ErrDashboardUidToLong = errors.New("uid to long. max 40 characters")
|
ErrDashboardUidToLong = errors.New("uid to long. max 40 characters")
|
||||||
ErrDashboardCannotSaveProvisionedDashboard = errors.New("Cannot save provisioned dashboard")
|
ErrDashboardCannotSaveProvisionedDashboard = errors.New("Cannot save provisioned dashboard")
|
||||||
|
ErrDashboardRefreshIntervalTooShort = errors.New("Dashboard refresh interval is too low")
|
||||||
ErrDashboardCannotDeleteProvisionedDashboard = errors.New("provisioned dashboard cannot be deleted")
|
ErrDashboardCannotDeleteProvisionedDashboard = errors.New("provisioned dashboard cannot be deleted")
|
||||||
ErrDashboardIdentifierNotSet = errors.New("Unique identfier needed to be able to get a dashboard")
|
ErrDashboardIdentifierNotSet = errors.New("Unique identfier needed to be able to get a dashboard")
|
||||||
RootFolderName = "General"
|
RootFolderName = "General"
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
package dashboards
|
package dashboards
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/grafana/grafana/pkg/components/gtime"
|
||||||
|
"github.com/grafana/grafana/pkg/setting"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -103,6 +105,10 @@ func (dr *dashboardServiceImpl) buildSaveDashboardCommand(dto *SaveDashboardDTO,
|
|||||||
return nil, models.ErrDashboardUidToLong
|
return nil, models.ErrDashboardUidToLong
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := validateDashboardRefreshInterval(dash); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
if validateAlerts {
|
if validateAlerts {
|
||||||
validateAlertsCmd := models.ValidateDashboardAlertsCommand{
|
validateAlertsCmd := models.ValidateDashboardAlertsCommand{
|
||||||
OrgId: dto.OrgId,
|
OrgId: dto.OrgId,
|
||||||
@ -172,6 +178,33 @@ func (dr *dashboardServiceImpl) buildSaveDashboardCommand(dto *SaveDashboardDTO,
|
|||||||
return cmd, nil
|
return cmd, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func validateDashboardRefreshInterval(dash *models.Dashboard) error {
|
||||||
|
if setting.MinRefreshInterval == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
refresh := dash.Data.Get("refresh").MustString("")
|
||||||
|
if refresh == "" {
|
||||||
|
// since no refresh is set it is a valid refresh rate
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
minRefreshInterval, err := gtime.ParseInterval(setting.MinRefreshInterval)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
d, err := gtime.ParseInterval(refresh)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if d < minRefreshInterval {
|
||||||
|
return models.ErrDashboardRefreshIntervalTooShort
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (dr *dashboardServiceImpl) updateAlerting(cmd *models.SaveDashboardCommand, dto *SaveDashboardDTO) error {
|
func (dr *dashboardServiceImpl) updateAlerting(cmd *models.SaveDashboardCommand, dto *SaveDashboardDTO) error {
|
||||||
alertCmd := models.UpdateDashboardAlertsCommand{
|
alertCmd := models.UpdateDashboardAlertsCommand{
|
||||||
OrgId: dto.OrgId,
|
OrgId: dto.OrgId,
|
||||||
@ -183,6 +216,11 @@ func (dr *dashboardServiceImpl) updateAlerting(cmd *models.SaveDashboardCommand,
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (dr *dashboardServiceImpl) SaveProvisionedDashboard(dto *SaveDashboardDTO, provisioning *models.DashboardProvisioning) (*models.Dashboard, error) {
|
func (dr *dashboardServiceImpl) SaveProvisionedDashboard(dto *SaveDashboardDTO, provisioning *models.DashboardProvisioning) (*models.Dashboard, error) {
|
||||||
|
if err := validateDashboardRefreshInterval(dto.Dashboard); err != nil {
|
||||||
|
dr.log.Warn("Changing refresh interval for provisioned dashboard to minimum refresh interval", "dashboardUid", dto.Dashboard.Uid, "dashboardTitle", dto.Dashboard.Title, "minRefreshInterval", setting.MinRefreshInterval)
|
||||||
|
dto.Dashboard.Data.Set("refresh", setting.MinRefreshInterval)
|
||||||
|
}
|
||||||
|
|
||||||
dto.User = &models.SignedInUser{
|
dto.User = &models.SignedInUser{
|
||||||
UserId: 0,
|
UserId: 0,
|
||||||
OrgRole: models.ROLE_ADMIN,
|
OrgRole: models.ROLE_ADMIN,
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
package dashboards
|
package dashboards
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/grafana/grafana/pkg/infra/log"
|
||||||
|
"github.com/grafana/grafana/pkg/setting"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/bus"
|
"github.com/grafana/grafana/pkg/bus"
|
||||||
@ -14,7 +16,9 @@ func TestDashboardService(t *testing.T) {
|
|||||||
Convey("Dashboard service tests", t, func() {
|
Convey("Dashboard service tests", t, func() {
|
||||||
bus.ClearBusHandlers()
|
bus.ClearBusHandlers()
|
||||||
|
|
||||||
service := &dashboardServiceImpl{}
|
service := &dashboardServiceImpl{
|
||||||
|
log: log.New("test.logger"),
|
||||||
|
}
|
||||||
|
|
||||||
origNewDashboardGuardian := guardian.New
|
origNewDashboardGuardian := guardian.New
|
||||||
guardian.MockDashboardGuardian(&guardian.FakeDashboardGuardian{CanSaveValue: true})
|
guardian.MockDashboardGuardian(&guardian.FakeDashboardGuardian{CanSaveValue: true})
|
||||||
@ -184,6 +188,43 @@ func TestDashboardService(t *testing.T) {
|
|||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
So(provisioningValidated, ShouldBeFalse)
|
So(provisioningValidated, ShouldBeFalse)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
Convey("Should override invalid refresh interval if dashboard is provisioned", func() {
|
||||||
|
oldRefreshInterval := setting.MinRefreshInterval
|
||||||
|
setting.MinRefreshInterval = "5m"
|
||||||
|
defer func() { setting.MinRefreshInterval = oldRefreshInterval }()
|
||||||
|
|
||||||
|
bus.AddHandler("test", func(cmd *models.GetProvisionedDashboardDataByIdQuery) error {
|
||||||
|
cmd.Result = &models.DashboardProvisioning{}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
bus.AddHandler("test", func(cmd *models.ValidateDashboardAlertsCommand) error {
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
bus.AddHandler("test", func(cmd *models.ValidateDashboardBeforeSaveCommand) error {
|
||||||
|
cmd.Result = &models.ValidateDashboardBeforeSaveResult{}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
bus.AddHandler("test", func(cmd *models.SaveProvisionedDashboardCommand) error {
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
bus.AddHandler("test", func(cmd *models.UpdateDashboardAlertsCommand) error {
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
dto.Dashboard = models.NewDashboard("Dash")
|
||||||
|
dto.Dashboard.SetId(3)
|
||||||
|
dto.User = &models.SignedInUser{UserId: 1}
|
||||||
|
dto.Dashboard.Data.Set("refresh", "1s")
|
||||||
|
_, err := service.SaveProvisionedDashboard(dto, nil)
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
So(dto.Dashboard.Data.Get("refresh").MustString(), ShouldEqual, "5m")
|
||||||
|
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
Convey("Import dashboard validation", func() {
|
Convey("Import dashboard validation", func() {
|
||||||
|
@ -623,6 +623,7 @@ func getExistingDashboardByTitleAndFolder(sess *DBSession, cmd *models.ValidateD
|
|||||||
|
|
||||||
func ValidateDashboardBeforeSave(cmd *models.ValidateDashboardBeforeSaveCommand) (err error) {
|
func ValidateDashboardBeforeSave(cmd *models.ValidateDashboardBeforeSaveCommand) (err error) {
|
||||||
cmd.Result = &models.ValidateDashboardBeforeSaveResult{}
|
cmd.Result = &models.ValidateDashboardBeforeSaveResult{}
|
||||||
|
|
||||||
return inTransaction(func(sess *DBSession) error {
|
return inTransaction(func(sess *DBSession) error {
|
||||||
if err = getExistingDashboardByIdOrUidForUpdate(sess, cmd); err != nil {
|
if err = getExistingDashboardByIdOrUidForUpdate(sess, cmd); err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -119,6 +119,7 @@ var (
|
|||||||
|
|
||||||
// Dashboard history
|
// Dashboard history
|
||||||
DashboardVersionsToKeep int
|
DashboardVersionsToKeep int
|
||||||
|
MinRefreshInterval string
|
||||||
|
|
||||||
// User settings
|
// User settings
|
||||||
AllowUserSignUp bool
|
AllowUserSignUp bool
|
||||||
@ -763,6 +764,10 @@ func (cfg *Cfg) Load(args *CommandLineArgs) error {
|
|||||||
// read dashboard settings
|
// read dashboard settings
|
||||||
dashboards := iniFile.Section("dashboards")
|
dashboards := iniFile.Section("dashboards")
|
||||||
DashboardVersionsToKeep = dashboards.Key("versions_to_keep").MustInt(20)
|
DashboardVersionsToKeep = dashboards.Key("versions_to_keep").MustInt(20)
|
||||||
|
MinRefreshInterval, err = valueAsString(dashboards, "min_refresh_interval", "")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// read data source proxy white list
|
// read data source proxy white list
|
||||||
DataProxyWhiteList = make(map[string]bool)
|
DataProxyWhiteList = make(map[string]bool)
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import config from 'app/core/config';
|
import config from '../../core/config';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import coreModule from 'app/core/core_module';
|
import coreModule from 'app/core/core_module';
|
||||||
|
import kbn from '../utils/kbn';
|
||||||
|
|
||||||
export class User {
|
export class User {
|
||||||
id: number;
|
id: number;
|
||||||
@ -32,6 +33,7 @@ export class ContextSrv {
|
|||||||
isEditor: any;
|
isEditor: any;
|
||||||
sidemenuSmallBreakpoint = false;
|
sidemenuSmallBreakpoint = false;
|
||||||
hasEditPermissionInFolders: boolean;
|
hasEditPermissionInFolders: boolean;
|
||||||
|
minRefreshInterval: string;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
if (!config.bootData) {
|
if (!config.bootData) {
|
||||||
@ -43,6 +45,7 @@ export class ContextSrv {
|
|||||||
this.isGrafanaAdmin = this.user.isGrafanaAdmin;
|
this.isGrafanaAdmin = this.user.isGrafanaAdmin;
|
||||||
this.isEditor = this.hasRole('Editor') || this.hasRole('Admin');
|
this.isEditor = this.hasRole('Editor') || this.hasRole('Admin');
|
||||||
this.hasEditPermissionInFolders = this.user.hasEditPermissionInFolders;
|
this.hasEditPermissionInFolders = this.user.hasEditPermissionInFolders;
|
||||||
|
this.minRefreshInterval = config.minRefreshInterval;
|
||||||
}
|
}
|
||||||
|
|
||||||
hasRole(role: string) {
|
hasRole(role: string) {
|
||||||
@ -53,6 +56,21 @@ export class ContextSrv {
|
|||||||
return !!(document.visibilityState === undefined || document.visibilityState === 'visible');
|
return !!(document.visibilityState === undefined || document.visibilityState === 'visible');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// checks whether the passed interval is longer than the configured minimum refresh rate
|
||||||
|
isAllowedInterval(interval: string) {
|
||||||
|
if (!config.minRefreshInterval) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return kbn.interval_to_ms(interval) >= kbn.interval_to_ms(config.minRefreshInterval);
|
||||||
|
}
|
||||||
|
|
||||||
|
getValidInterval(interval: string) {
|
||||||
|
if (!this.isAllowedInterval(interval)) {
|
||||||
|
return config.minRefreshInterval;
|
||||||
|
}
|
||||||
|
return interval;
|
||||||
|
}
|
||||||
|
|
||||||
hasAccessToExplore() {
|
hasAccessToExplore() {
|
||||||
return (this.isEditor || config.viewersCanEdit) && config.exploreEnabled;
|
return (this.isEditor || config.viewersCanEdit) && config.exploreEnabled;
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@ import { TimePickerWithHistory } from 'app/core/components/TimePicker/TimePicker
|
|||||||
|
|
||||||
// Utils & Services
|
// Utils & Services
|
||||||
import { getTimeSrv } from 'app/features/dashboard/services/TimeSrv';
|
import { getTimeSrv } from 'app/features/dashboard/services/TimeSrv';
|
||||||
|
import { defaultIntervals } from '@grafana/ui/src/components/RefreshPicker/RefreshPicker';
|
||||||
import { appEvents } from 'app/core/core';
|
import { appEvents } from 'app/core/core';
|
||||||
|
|
||||||
const getStyles = stylesFactory((theme: GrafanaTheme) => {
|
const getStyles = stylesFactory((theme: GrafanaTheme) => {
|
||||||
@ -92,7 +93,9 @@ class UnthemedDashNavTimeControls extends Component<Props> {
|
|||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { dashboard, theme } = this.props;
|
const { dashboard, theme } = this.props;
|
||||||
const intervals = dashboard.timepicker.refresh_intervals;
|
const { refresh_intervals } = dashboard.timepicker;
|
||||||
|
const intervals = getTimeSrv().getValidIntervals(refresh_intervals || defaultIntervals);
|
||||||
|
|
||||||
const timePickerValue = getTimeSrv().timeRange();
|
const timePickerValue = getTimeSrv().timeRange();
|
||||||
const timeZone = dashboard.getTimezone();
|
const timeZone = dashboard.getTimezone();
|
||||||
const styles = getStyles(theme);
|
const styles = getStyles(theme);
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
import coreModule from 'app/core/core_module';
|
import coreModule from 'app/core/core_module';
|
||||||
import { DashboardModel } from 'app/features/dashboard/state';
|
import { DashboardModel } from 'app/features/dashboard/state';
|
||||||
|
import { config } from 'app/core/config';
|
||||||
|
import kbn from 'app/core/utils/kbn';
|
||||||
|
|
||||||
export class TimePickerCtrl {
|
export class TimePickerCtrl {
|
||||||
panel: any;
|
panel: any;
|
||||||
@ -19,6 +21,15 @@ export class TimePickerCtrl {
|
|||||||
'2h',
|
'2h',
|
||||||
'1d',
|
'1d',
|
||||||
];
|
];
|
||||||
|
if (config.minRefreshInterval) {
|
||||||
|
this.panel.refresh_intervals = this.filterRefreshRates(this.panel.refresh_intervals);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
filterRefreshRates(refreshRates: string[]) {
|
||||||
|
return refreshRates.filter(rate => {
|
||||||
|
return kbn.interval_to_ms(rate) > kbn.interval_to_ms(config.minRefreshInterval);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,6 +22,8 @@ import { getZoomedTimeRange, getShiftedTimeRange } from 'app/core/utils/timePick
|
|||||||
import { appEvents } from '../../../core/core';
|
import { appEvents } from '../../../core/core';
|
||||||
import { CoreEvents } from '../../../types';
|
import { CoreEvents } from '../../../types';
|
||||||
|
|
||||||
|
import { config } from 'app/core/config';
|
||||||
|
|
||||||
export class TimeSrv {
|
export class TimeSrv {
|
||||||
time: any;
|
time: any;
|
||||||
refreshTimer: any;
|
refreshTimer: any;
|
||||||
@ -72,6 +74,19 @@ export class TimeSrv {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getValidIntervals(intervals: string[]): string[] {
|
||||||
|
if (!this.contextSrv.minRefreshInterval) {
|
||||||
|
return intervals;
|
||||||
|
}
|
||||||
|
|
||||||
|
const validIntervals = intervals.filter(str => str !== '').filter(this.contextSrv.isAllowedInterval);
|
||||||
|
|
||||||
|
if (validIntervals.indexOf(this.contextSrv.minRefreshInterval) === -1) {
|
||||||
|
validIntervals.unshift(this.contextSrv.minRefreshInterval);
|
||||||
|
}
|
||||||
|
return validIntervals;
|
||||||
|
}
|
||||||
|
|
||||||
private parseTime() {
|
private parseTime() {
|
||||||
// when absolute time is saved in json it is turned to a string
|
// when absolute time is saved in json it is turned to a string
|
||||||
if (_.isString(this.time.from) && this.time.from.indexOf('Z') >= 0) {
|
if (_.isString(this.time.from) && this.time.from.indexOf('Z') >= 0) {
|
||||||
@ -138,7 +153,11 @@ export class TimeSrv {
|
|||||||
}
|
}
|
||||||
// but if refresh explicitly set then use that
|
// but if refresh explicitly set then use that
|
||||||
if (params.refresh) {
|
if (params.refresh) {
|
||||||
this.refresh = params.refresh || this.refresh;
|
if (!this.contextSrv.isAllowedInterval(params.refresh)) {
|
||||||
|
this.refresh = config.minRefreshInterval;
|
||||||
|
} else {
|
||||||
|
this.refresh = params.refresh || this.refresh;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -170,7 +189,8 @@ export class TimeSrv {
|
|||||||
this.cancelNextRefresh();
|
this.cancelNextRefresh();
|
||||||
|
|
||||||
if (interval) {
|
if (interval) {
|
||||||
const intervalMs = kbn.interval_to_ms(interval);
|
const validInterval = this.contextSrv.getValidInterval(interval);
|
||||||
|
const intervalMs = kbn.interval_to_ms(validInterval);
|
||||||
|
|
||||||
this.refreshTimer = this.timer.register(
|
this.refreshTimer = this.timer.register(
|
||||||
this.$timeout(() => {
|
this.$timeout(() => {
|
||||||
@ -184,7 +204,7 @@ export class TimeSrv {
|
|||||||
this.$timeout(() => {
|
this.$timeout(() => {
|
||||||
const params = this.$location.search();
|
const params = this.$location.search();
|
||||||
if (interval) {
|
if (interval) {
|
||||||
params.refresh = interval;
|
params.refresh = this.contextSrv.getValidInterval(interval);
|
||||||
this.$location.search(params);
|
this.$location.search(params);
|
||||||
} else if (params.refresh) {
|
} else if (params.refresh) {
|
||||||
delete params.refresh;
|
delete params.refresh;
|
||||||
|
@ -177,6 +177,10 @@ export class TimeSrvStub {
|
|||||||
export class ContextSrvStub {
|
export class ContextSrvStub {
|
||||||
isGrafanaVisibile = jest.fn();
|
isGrafanaVisibile = jest.fn();
|
||||||
|
|
||||||
|
getValidInterval() {
|
||||||
|
return '10s';
|
||||||
|
}
|
||||||
|
|
||||||
hasRole() {
|
hasRole() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user