mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
PublicDashboards: Support timezone on query API (#68560)
This commit is contained in:
parent
7ea9be6832
commit
fc374f93a3
@ -2,12 +2,9 @@ package models
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/grafana/grafana/pkg/kinds/dashboard"
|
||||
"github.com/grafana/grafana/pkg/services/dashboards"
|
||||
"github.com/grafana/grafana/pkg/tsdb/legacydata"
|
||||
)
|
||||
|
||||
// PublicDashboardErr represents a dashboard error.
|
||||
@ -127,25 +124,6 @@ func (ts *TimeSettings) ToDB() ([]byte, error) {
|
||||
return json.Marshal(ts)
|
||||
}
|
||||
|
||||
// BuildTimeSettings build time settings object using selected values if enabled and are valid or dashboard default values
|
||||
func (pd PublicDashboard) BuildTimeSettings(dashboard *dashboards.Dashboard, reqDTO PublicDashboardQueryDTO) TimeSettings {
|
||||
from := dashboard.Data.GetPath("time", "from").MustString()
|
||||
to := dashboard.Data.GetPath("time", "to").MustString()
|
||||
|
||||
if pd.TimeSelectionEnabled {
|
||||
from = reqDTO.TimeRange.From
|
||||
to = reqDTO.TimeRange.To
|
||||
}
|
||||
|
||||
timeRange := legacydata.NewDataTimeRange(from, to)
|
||||
|
||||
// Were using epoch ms because this is used to build a MetricRequest, which is used by query caching, which expected the time range in epoch milliseconds.
|
||||
return TimeSettings{
|
||||
From: strconv.FormatInt(timeRange.GetFromAsMsEpoch(), 10),
|
||||
To: strconv.FormatInt(timeRange.GetToAsMsEpoch(), 10),
|
||||
}
|
||||
}
|
||||
|
||||
// DTO for transforming user input in the api
|
||||
type SavePublicDashboardDTO struct {
|
||||
DashboardUid string
|
||||
@ -153,11 +131,17 @@ type SavePublicDashboardDTO struct {
|
||||
PublicDashboard *PublicDashboardDTO
|
||||
}
|
||||
|
||||
type TimeRangeDTO struct {
|
||||
From string
|
||||
To string
|
||||
Timezone string
|
||||
}
|
||||
|
||||
type PublicDashboardQueryDTO struct {
|
||||
IntervalMs int64
|
||||
MaxDataPoints int64
|
||||
QueryCachingTTL int64
|
||||
TimeRange TimeSettings
|
||||
TimeRange TimeRangeDTO
|
||||
}
|
||||
|
||||
type AnnotationsQueryDTO struct {
|
||||
|
@ -1,74 +1,11 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||
"github.com/grafana/grafana/pkg/services/dashboards"
|
||||
"github.com/grafana/grafana/pkg/services/publicdashboards/internal"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestPublicDashboardTableName(t *testing.T) {
|
||||
assert.Equal(t, "dashboard_public", PublicDashboard{}.TableName())
|
||||
}
|
||||
|
||||
func TestBuildTimeSettings(t *testing.T) {
|
||||
var dashboardData = simplejson.NewFromAny(map[string]interface{}{"time": map[string]interface{}{"from": "2022-09-01T00:00:00.000Z", "to": "2022-09-01T12:00:00.000Z"}})
|
||||
defaultFromMs, defaultToMs := internal.GetTimeRangeFromDashboard(t, dashboardData)
|
||||
|
||||
selectionFromMs := strconv.FormatInt(time.Now().UnixMilli(), 10)
|
||||
selectionToMs := strconv.FormatInt(time.Now().Add(time.Hour).UnixMilli(), 10)
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
dashboard *dashboards.Dashboard
|
||||
pubdash *PublicDashboard
|
||||
timeResult TimeSettings
|
||||
reqDTO PublicDashboardQueryDTO
|
||||
}{
|
||||
{
|
||||
name: "should use dashboard time if pubdash time empty",
|
||||
dashboard: &dashboards.Dashboard{Data: dashboardData},
|
||||
pubdash: &PublicDashboard{TimeSelectionEnabled: false},
|
||||
timeResult: TimeSettings{
|
||||
From: defaultFromMs,
|
||||
To: defaultToMs,
|
||||
},
|
||||
reqDTO: PublicDashboardQueryDTO{},
|
||||
},
|
||||
{
|
||||
name: "should use dashboard time when time selection is disabled",
|
||||
dashboard: &dashboards.Dashboard{Data: dashboardData},
|
||||
pubdash: &PublicDashboard{TimeSelectionEnabled: false, TimeSettings: &TimeSettings{From: "now-12", To: "now"}},
|
||||
timeResult: TimeSettings{
|
||||
From: defaultFromMs,
|
||||
To: defaultToMs,
|
||||
},
|
||||
reqDTO: PublicDashboardQueryDTO{},
|
||||
},
|
||||
{
|
||||
name: "should use selected values if time selection is enabled",
|
||||
dashboard: &dashboards.Dashboard{Data: dashboardData},
|
||||
pubdash: &PublicDashboard{TimeSelectionEnabled: true, TimeSettings: &TimeSettings{From: "now-12", To: "now"}},
|
||||
reqDTO: PublicDashboardQueryDTO{
|
||||
TimeRange: TimeSettings{
|
||||
From: selectionFromMs,
|
||||
To: selectionToMs,
|
||||
},
|
||||
},
|
||||
timeResult: TimeSettings{
|
||||
From: selectionFromMs,
|
||||
To: selectionToMs,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
assert.Equal(t, test.timeResult, test.pubdash.BuildTimeSettings(test.dashboard, test.reqDTO))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,8 @@ package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||
"github.com/grafana/grafana/pkg/api/dtos"
|
||||
@ -14,6 +16,7 @@ import (
|
||||
"github.com/grafana/grafana/pkg/services/publicdashboards/validation"
|
||||
"github.com/grafana/grafana/pkg/services/user"
|
||||
"github.com/grafana/grafana/pkg/tsdb/grafanads"
|
||||
"github.com/grafana/grafana/pkg/tsdb/legacydata"
|
||||
)
|
||||
|
||||
// FindAnnotations returns annotations for a public dashboard
|
||||
@ -106,7 +109,6 @@ func (pd *PublicDashboardServiceImpl) GetMetricRequest(ctx context.Context, dash
|
||||
}
|
||||
|
||||
metricReqDTO, err := pd.buildMetricRequest(
|
||||
ctx,
|
||||
dashboard,
|
||||
publicDashboard,
|
||||
panelId,
|
||||
@ -151,7 +153,7 @@ func (pd *PublicDashboardServiceImpl) GetQueryDataResponse(ctx context.Context,
|
||||
}
|
||||
|
||||
// buildMetricRequest merges public dashboard parameters with dashboard and returns a metrics request to be sent to query backend
|
||||
func (pd *PublicDashboardServiceImpl) buildMetricRequest(ctx context.Context, dashboard *dashboards.Dashboard, publicDashboard *models.PublicDashboard, panelId int64, reqDTO models.PublicDashboardQueryDTO) (dtos.MetricRequest, error) {
|
||||
func (pd *PublicDashboardServiceImpl) buildMetricRequest(dashboard *dashboards.Dashboard, publicDashboard *models.PublicDashboard, panelId int64, reqDTO models.PublicDashboardQueryDTO) (dtos.MetricRequest, error) {
|
||||
// group queries by panel
|
||||
queriesByPanel := groupQueriesByPanelId(dashboard.Data)
|
||||
queries, ok := queriesByPanel[panelId]
|
||||
@ -159,7 +161,7 @@ func (pd *PublicDashboardServiceImpl) buildMetricRequest(ctx context.Context, da
|
||||
return dtos.MetricRequest{}, models.ErrPanelNotFound.Errorf("buildMetricRequest: public dashboard panel not found")
|
||||
}
|
||||
|
||||
ts := publicDashboard.BuildTimeSettings(dashboard, reqDTO)
|
||||
ts := buildTimeSettings(dashboard, reqDTO, publicDashboard)
|
||||
|
||||
// determine safe resolution to query data at
|
||||
safeInterval, safeResolution := pd.getSafeIntervalAndMaxDataPoints(reqDTO, ts)
|
||||
@ -319,3 +321,57 @@ func sanitizeMetadataFromQueryData(res *backend.QueryDataResponse) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// NewDataTimeRange declared to be able to stub this function in tests
|
||||
var NewDataTimeRange = legacydata.NewDataTimeRange
|
||||
|
||||
// BuildTimeSettings build time settings object using selected values if enabled and are valid or dashboard default values
|
||||
func buildTimeSettings(d *dashboards.Dashboard, reqDTO models.PublicDashboardQueryDTO, pd *models.PublicDashboard) models.TimeSettings {
|
||||
from, to, timezone := getTimeRangeValuesOrDefault(reqDTO, d, pd.TimeSelectionEnabled)
|
||||
|
||||
timeRange := NewDataTimeRange(from, to)
|
||||
|
||||
timeFrom, _ := timeRange.ParseFrom(
|
||||
legacydata.WithLocation(timezone),
|
||||
)
|
||||
timeTo, _ := timeRange.ParseTo(
|
||||
legacydata.WithLocation(timezone),
|
||||
)
|
||||
timeToAsEpoch := timeTo.UnixMilli()
|
||||
timeFromAsEpoch := timeFrom.UnixMilli()
|
||||
|
||||
// Were using epoch ms because this is used to build a MetricRequest, which is used by query caching, which want the time range in epoch milliseconds.
|
||||
return models.TimeSettings{
|
||||
From: strconv.FormatInt(timeFromAsEpoch, 10),
|
||||
To: strconv.FormatInt(timeToAsEpoch, 10),
|
||||
}
|
||||
}
|
||||
|
||||
// returns from, to and timezone from the request if the timeSelection is enabled or the dashboard default values
|
||||
func getTimeRangeValuesOrDefault(reqDTO models.PublicDashboardQueryDTO, d *dashboards.Dashboard, timeSelectionEnabled bool) (string, string, *time.Location) {
|
||||
from := d.Data.GetPath("time", "from").MustString()
|
||||
to := d.Data.GetPath("time", "to").MustString()
|
||||
dashboardTimezone := d.Data.GetPath("timezone").MustString()
|
||||
|
||||
// we use the values from the request if the time selection is enabled and the values are valid
|
||||
if timeSelectionEnabled {
|
||||
if reqDTO.TimeRange.From != "" && reqDTO.TimeRange.To != "" {
|
||||
from = reqDTO.TimeRange.From
|
||||
to = reqDTO.TimeRange.To
|
||||
}
|
||||
|
||||
if reqDTO.TimeRange.Timezone != "" {
|
||||
if userTimezone, err := time.LoadLocation(reqDTO.TimeRange.Timezone); err == nil {
|
||||
return from, to, userTimezone
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if the dashboardTimezone is blank or there is an error default is UTC
|
||||
timezone, err := time.LoadLocation(dashboardTimezone)
|
||||
if err != nil {
|
||||
return from, to, time.UTC
|
||||
}
|
||||
|
||||
return from, to, timezone
|
||||
}
|
||||
|
@ -3,7 +3,9 @@ package service
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"strconv"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||
"github.com/grafana/grafana-plugin-sdk-go/data"
|
||||
@ -26,6 +28,7 @@ import (
|
||||
"github.com/grafana/grafana/pkg/services/tag/tagimpl"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
"github.com/grafana/grafana/pkg/tsdb/intervalv2"
|
||||
"github.com/grafana/grafana/pkg/tsdb/legacydata"
|
||||
"github.com/grafana/grafana/pkg/util"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
@ -1229,7 +1232,6 @@ func TestBuildMetricRequest(t *testing.T) {
|
||||
|
||||
t.Run("extracts queries from provided dashboard", func(t *testing.T) {
|
||||
reqDTO, err := service.buildMetricRequest(
|
||||
context.Background(),
|
||||
publicDashboard,
|
||||
publicDashboardPD,
|
||||
1,
|
||||
@ -1280,7 +1282,6 @@ func TestBuildMetricRequest(t *testing.T) {
|
||||
|
||||
t.Run("returns an error when panel missing", func(t *testing.T) {
|
||||
_, err := service.buildMetricRequest(
|
||||
context.Background(),
|
||||
publicDashboard,
|
||||
publicDashboardPD,
|
||||
49,
|
||||
@ -1319,7 +1320,6 @@ func TestBuildMetricRequest(t *testing.T) {
|
||||
publicDashboard := insertTestDashboard(t, dashboardStore, "testDashWithHiddenQuery", 1, 0, true, []map[string]interface{}{}, customPanels)
|
||||
|
||||
reqDTO, err := service.buildMetricRequest(
|
||||
context.Background(),
|
||||
publicDashboard,
|
||||
publicDashboardPD,
|
||||
1,
|
||||
@ -1611,6 +1611,158 @@ func TestSanitizeMetadataFromQueryData(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestBuildTimeSettings(t *testing.T) {
|
||||
var defaultDashboardData = simplejson.NewFromAny(map[string]interface{}{
|
||||
"time": map[string]interface{}{
|
||||
"from": "2022-09-01T00:00:00.000Z", "to": "2022-09-01T12:00:00.000Z",
|
||||
},
|
||||
"timezone": "America/Argentina/Mendoza",
|
||||
})
|
||||
|
||||
defaultFromMs, defaultToMs := internal.GetTimeRangeFromDashboard(t, defaultDashboardData)
|
||||
|
||||
fakeTimezone, _ := time.LoadLocation("Europe/Madrid")
|
||||
fakeNow := time.Date(2018, 12, 9, 20, 30, 0, 0, fakeTimezone)
|
||||
|
||||
// stub time range construction to have a fixed time.Now and be able to tests relative time ranges
|
||||
NewDataTimeRange = func(from, to string) legacydata.DataTimeRange {
|
||||
return legacydata.DataTimeRange{
|
||||
From: from,
|
||||
To: to,
|
||||
Now: fakeNow,
|
||||
}
|
||||
}
|
||||
|
||||
startOfYesterdayMadrid, endOfYesterdayMadrid := getStartAndEndOfTheDayBefore(fakeNow, "Europe/Madrid")
|
||||
|
||||
// the day before fakeNow in Australia/Sydney timezone is not the same day before as in Europe/Madrid
|
||||
startOfYesterdaySydney, endOfYesterdaySydney := getStartAndEndOfTheDayBefore(fakeNow, "Australia/Sydney")
|
||||
startOfYesterdayUTC, endOfYesterdayUTC := getStartAndEndOfTheDayBefore(fakeNow, "UTC")
|
||||
|
||||
selectionFromMs := strconv.FormatInt(time.Now().UnixMilli(), 10)
|
||||
selectionToMs := strconv.FormatInt(time.Now().Add(time.Hour).UnixMilli(), 10)
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
dashboard *dashboards.Dashboard
|
||||
pubdash *PublicDashboard
|
||||
reqDTO PublicDashboardQueryDTO
|
||||
want TimeSettings
|
||||
}{
|
||||
{
|
||||
name: "should return default time range with timezone with relative time range",
|
||||
dashboard: &dashboards.Dashboard{Data: buildJsonDataWithTimeRange("now-1d/d", "now-1d/d", "Australia/Sydney")},
|
||||
pubdash: &PublicDashboard{TimeSelectionEnabled: false},
|
||||
reqDTO: PublicDashboardQueryDTO{},
|
||||
want: TimeSettings{
|
||||
From: strconv.FormatInt(startOfYesterdaySydney.UnixMilli(), 10),
|
||||
To: strconv.FormatInt(endOfYesterdaySydney.UnixMilli(), 10),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "should return default time range with UTC timezone with relative time range with unknown timezone",
|
||||
dashboard: &dashboards.Dashboard{Data: buildJsonDataWithTimeRange("now-1d/d", "now-1d/d", "browser")},
|
||||
pubdash: &PublicDashboard{TimeSelectionEnabled: false},
|
||||
reqDTO: PublicDashboardQueryDTO{},
|
||||
want: TimeSettings{
|
||||
From: strconv.FormatInt(startOfYesterdayUTC.UnixMilli(), 10),
|
||||
To: strconv.FormatInt(endOfYesterdayUTC.UnixMilli(), 10),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "should return default time range with timezone with relative time range if time selection is not enabled",
|
||||
dashboard: &dashboards.Dashboard{Data: buildJsonDataWithTimeRange("now-1d/d", "now-1d/d", "Australia/Sydney")},
|
||||
pubdash: &PublicDashboard{TimeSelectionEnabled: false},
|
||||
reqDTO: PublicDashboardQueryDTO{
|
||||
TimeRange: TimeRangeDTO{
|
||||
Timezone: "Europe/Madrid",
|
||||
}},
|
||||
want: TimeSettings{
|
||||
From: strconv.FormatInt(startOfYesterdaySydney.UnixMilli(), 10),
|
||||
To: strconv.FormatInt(endOfYesterdaySydney.UnixMilli(), 10),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "should return user time range with dashboard timezone with relative time range",
|
||||
dashboard: &dashboards.Dashboard{Data: buildJsonDataWithTimeRange("now-1d/d", "now-1d/d", "Europe/Madrid")},
|
||||
pubdash: &PublicDashboard{TimeSelectionEnabled: false},
|
||||
reqDTO: PublicDashboardQueryDTO{},
|
||||
want: TimeSettings{
|
||||
From: strconv.FormatInt(startOfYesterdayMadrid.UnixMilli(), 10),
|
||||
To: strconv.FormatInt(endOfYesterdayMadrid.UnixMilli(), 10),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "should return user time range with dashboard timezone with relative time range for the last hour",
|
||||
dashboard: &dashboards.Dashboard{Data: buildJsonDataWithTimeRange("now-1h", "now", "Europe/Madrid")},
|
||||
pubdash: &PublicDashboard{TimeSelectionEnabled: false},
|
||||
reqDTO: PublicDashboardQueryDTO{},
|
||||
want: TimeSettings{
|
||||
From: strconv.FormatInt(fakeNow.Add(-time.Hour).UnixMilli(), 10),
|
||||
To: strconv.FormatInt(fakeNow.UnixMilli(), 10),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "should use dashboard time if pubdash time empty",
|
||||
dashboard: &dashboards.Dashboard{Data: defaultDashboardData},
|
||||
pubdash: &PublicDashboard{TimeSelectionEnabled: false},
|
||||
reqDTO: PublicDashboardQueryDTO{},
|
||||
want: TimeSettings{
|
||||
From: defaultFromMs,
|
||||
To: defaultToMs,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "should use dashboard time when time selection is disabled",
|
||||
dashboard: &dashboards.Dashboard{Data: defaultDashboardData},
|
||||
pubdash: &PublicDashboard{TimeSelectionEnabled: false},
|
||||
reqDTO: PublicDashboardQueryDTO{
|
||||
TimeRange: TimeRangeDTO{
|
||||
From: selectionFromMs,
|
||||
To: selectionToMs,
|
||||
},
|
||||
},
|
||||
want: TimeSettings{
|
||||
From: defaultFromMs,
|
||||
To: defaultToMs,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "should use selected values if time selection is enabled",
|
||||
dashboard: &dashboards.Dashboard{Data: defaultDashboardData},
|
||||
pubdash: &PublicDashboard{TimeSelectionEnabled: true},
|
||||
reqDTO: PublicDashboardQueryDTO{
|
||||
TimeRange: TimeRangeDTO{
|
||||
From: selectionFromMs,
|
||||
To: selectionToMs,
|
||||
},
|
||||
},
|
||||
want: TimeSettings{
|
||||
From: selectionFromMs,
|
||||
To: selectionToMs,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "should use default values if time selection is enabled but the time range is empty",
|
||||
dashboard: &dashboards.Dashboard{Data: defaultDashboardData},
|
||||
pubdash: &PublicDashboard{TimeSelectionEnabled: true},
|
||||
reqDTO: PublicDashboardQueryDTO{
|
||||
TimeRange: TimeRangeDTO{},
|
||||
},
|
||||
want: TimeSettings{
|
||||
From: defaultFromMs,
|
||||
To: defaultToMs,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
assert.Equal(t, test.want, buildTimeSettings(test.dashboard, test.reqDTO, test.pubdash))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func groupQueriesByDataSource(t *testing.T, queries []*simplejson.Json) (result [][]*simplejson.Json) {
|
||||
t.Helper()
|
||||
byDataSource := make(map[string][]*simplejson.Json)
|
||||
@ -1626,3 +1778,21 @@ func groupQueriesByDataSource(t *testing.T, queries []*simplejson.Json) (result
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func getStartAndEndOfTheDayBefore(fakeNow time.Time, timezoneName string) (time.Time, time.Time) {
|
||||
timezone, _ := time.LoadLocation(timezoneName)
|
||||
fakeNowWithTimezone := fakeNow.In(timezone)
|
||||
yy, mm, dd := fakeNowWithTimezone.Add(-24 * time.Hour).Date()
|
||||
startOfYesterdaySydney := time.Date(yy, mm, dd, 0, 0, 0, 0, timezone)
|
||||
endOfYesterdaySydney := time.Date(yy, mm, dd, 23, 59, 59, 999999999, timezone)
|
||||
return startOfYesterdaySydney, endOfYesterdaySydney
|
||||
}
|
||||
|
||||
func buildJsonDataWithTimeRange(from, to, timezone string) *simplejson.Json {
|
||||
return simplejson.NewFromAny(map[string]interface{}{
|
||||
"time": map[string]interface{}{
|
||||
"from": from, "to": to,
|
||||
},
|
||||
"timezone": timezone,
|
||||
})
|
||||
}
|
||||
|
@ -40,7 +40,7 @@ func TestValidateQueryPublicDashboardRequest(t *testing.T) {
|
||||
req: PublicDashboardQueryDTO{
|
||||
IntervalMs: 1000,
|
||||
MaxDataPoints: 1000,
|
||||
TimeRange: TimeSettings{
|
||||
TimeRange: TimeRangeDTO{
|
||||
From: "now-1h",
|
||||
To: "now",
|
||||
},
|
||||
@ -88,7 +88,7 @@ func TestValidateQueryPublicDashboardRequest(t *testing.T) {
|
||||
name: "Returns validation error when time range from is invalid",
|
||||
args: args{
|
||||
req: PublicDashboardQueryDTO{
|
||||
TimeRange: TimeSettings{
|
||||
TimeRange: TimeRangeDTO{
|
||||
From: "invalid",
|
||||
To: "1622560000000",
|
||||
},
|
||||
@ -103,7 +103,7 @@ func TestValidateQueryPublicDashboardRequest(t *testing.T) {
|
||||
name: "Returns validation error when time range to is invalid",
|
||||
args: args{
|
||||
req: PublicDashboardQueryDTO{
|
||||
TimeRange: TimeSettings{
|
||||
TimeRange: TimeRangeDTO{
|
||||
From: "1622560000000",
|
||||
To: "invalid",
|
||||
},
|
||||
@ -118,7 +118,7 @@ func TestValidateQueryPublicDashboardRequest(t *testing.T) {
|
||||
name: "Returns validation error when time range from or to is blank",
|
||||
args: args{
|
||||
req: PublicDashboardQueryDTO{
|
||||
TimeRange: TimeSettings{
|
||||
TimeRange: TimeRangeDTO{
|
||||
From: "",
|
||||
To: "",
|
||||
},
|
||||
|
@ -113,7 +113,11 @@ export class PublicDashboardDataSource extends DataSourceApi<DataQuery, DataSour
|
||||
intervalMs,
|
||||
maxDataPoints,
|
||||
queryCachingTTL,
|
||||
timeRange: { from: fromRange.valueOf().toString(), to: toRange.valueOf().toString() },
|
||||
timeRange: {
|
||||
from: fromRange.valueOf().toString(),
|
||||
to: toRange.valueOf().toString(),
|
||||
timezone: this.getBrowserTimezone(),
|
||||
},
|
||||
};
|
||||
|
||||
return getBackendSrv()
|
||||
@ -155,4 +159,9 @@ export class PublicDashboardDataSource extends DataSourceApi<DataQuery, DataSour
|
||||
testDatasource(): Promise<TestDataSourceResponse> {
|
||||
return Promise.resolve({ message: '', status: '' });
|
||||
}
|
||||
|
||||
// Try to get the browser timezone otherwise return blank
|
||||
getBrowserTimezone(): string {
|
||||
return window.Intl?.DateTimeFormat().resolvedOptions()?.timeZone || '';
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user