From d2aca99d38a76bf7ad264d305c3de965f923dc35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Agn=C3=A8s=20Toulet?= <35176601+AgnesToulet@users.noreply.github.com> Date: Tue, 12 Nov 2024 09:21:13 +0100 Subject: [PATCH] Public Dashboard: Support relative time range in panels when time picker is disabled (#96076) Public Dashboard: Support relative time range in panels --- .../publicdashboards/service/query.go | 29 ++++++++--- .../publicdashboards/service/query_test.go | 48 ++++++++++++++++++- 2 files changed, 69 insertions(+), 8 deletions(-) diff --git a/pkg/services/publicdashboards/service/query.go b/pkg/services/publicdashboards/service/query.go index 29df0b7546d..3d8731e895d 100644 --- a/pkg/services/publicdashboards/service/query.go +++ b/pkg/services/publicdashboards/service/query.go @@ -155,15 +155,15 @@ 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(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] + queries, ok := queriesByPanel[panelID] if !ok { return dtos.MetricRequest{}, models.ErrPanelNotFound.Errorf("buildMetricRequest: public dashboard panel not found") } - ts := buildTimeSettings(dashboard, reqDTO, publicDashboard) + ts := buildTimeSettings(dashboard, reqDTO, publicDashboard, panelID) // determine safe resolution to query data at safeInterval, safeResolution := pd.getSafeIntervalAndMaxDataPoints(reqDTO, ts) @@ -372,8 +372,8 @@ func sanitizeData(data *simplejson.Json) { var NewTimeRange = gtime.NewTimeRange // 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) +func buildTimeSettings(d *dashboards.Dashboard, reqDTO models.PublicDashboardQueryDTO, pd *models.PublicDashboard, panelID int64) models.TimeSettings { + from, to, timezone := getTimeRangeValuesOrDefault(reqDTO, d, pd.TimeSelectionEnabled, panelID) timeRange := NewTimeRange(from, to) @@ -394,11 +394,16 @@ func buildTimeSettings(d *dashboards.Dashboard, reqDTO models.PublicDashboardQue } // 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) { +func getTimeRangeValuesOrDefault(reqDTO models.PublicDashboardQueryDTO, d *dashboards.Dashboard, timeSelectionEnabled bool, panelID int64) (string, string, *time.Location) { from := d.Data.GetPath("time", "from").MustString() to := d.Data.GetPath("time", "to").MustString() dashboardTimezone := d.Data.GetPath("timezone").MustString() + panelRelativeTime := getPanelRelativeTimeRange(d.Data, panelID) + if panelRelativeTime != "" { + from = panelRelativeTime + } + // 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 != "" { @@ -421,3 +426,15 @@ func getTimeRangeValuesOrDefault(reqDTO models.PublicDashboardQueryDTO, d *dashb return from, to, timezone } + +func getPanelRelativeTimeRange(dashboard *simplejson.Json, panelID int64) string { + for _, panelObj := range dashboard.Get("panels").MustArray() { + panel := simplejson.NewFromAny(panelObj) + + if panel.Get("id").MustInt64() == panelID { + return panel.Get("timeFrom").MustString() + } + } + + return "" +} diff --git a/pkg/services/publicdashboards/service/query_test.go b/pkg/services/publicdashboards/service/query_test.go index 7a356effc7b..ff33e49d609 100644 --- a/pkg/services/publicdashboards/service/query_test.go +++ b/pkg/services/publicdashboards/service/query_test.go @@ -1609,9 +1609,20 @@ func TestBuildTimeSettings(t *testing.T) { }, "timezone": "America/Argentina/Mendoza", }) - defaultFromMs, defaultToMs := internal.GetTimeRangeFromDashboard(t, defaultDashboardData) + dashboardDataWithPanelRelativeTime, err := simplejson.NewJson([]byte(` + { + "panels": [ + {"id": 1, "timeFrom": "now-1d/d"} + ], + "time": { + "from": "now-6h", "to": "now" + }, + "timezone": "Europe/Madrid" + }`)) + require.NoError(t, err) + fakeTimezone, _ := time.LoadLocation("Europe/Madrid") fakeNow := time.Date(2018, 12, 9, 20, 30, 0, 0, fakeTimezone) @@ -1638,6 +1649,7 @@ func TestBuildTimeSettings(t *testing.T) { dashboard *dashboards.Dashboard pubdash *PublicDashboard reqDTO PublicDashboardQueryDTO + panelID int64 want TimeSettings }{ { @@ -1745,11 +1757,43 @@ func TestBuildTimeSettings(t *testing.T) { To: defaultToMs, }, }, + { + name: "should use panel relative time when time selection is disabled", + dashboard: &dashboards.Dashboard{Data: dashboardDataWithPanelRelativeTime}, + pubdash: &PublicDashboard{TimeSelectionEnabled: false}, + reqDTO: PublicDashboardQueryDTO{ + TimeRange: TimeRangeDTO{ + From: selectionFromMs, + To: selectionToMs, + }, + }, + panelID: 1, + want: TimeSettings{ + From: strconv.FormatInt(startOfYesterdayMadrid.UnixMilli(), 10), + To: strconv.FormatInt(fakeNow.UnixMilli(), 10), + }, + }, + { + name: "should use selected values if time selection is enabled for panels with relative time set", + dashboard: &dashboards.Dashboard{Data: dashboardDataWithPanelRelativeTime}, + pubdash: &PublicDashboard{TimeSelectionEnabled: true}, + reqDTO: PublicDashboardQueryDTO{ + TimeRange: TimeRangeDTO{ + From: selectionFromMs, + To: selectionToMs, + }, + }, + panelID: 1, + want: TimeSettings{ + From: selectionFromMs, + To: selectionToMs, + }, + }, } for _, test := range testCases { t.Run(test.name, func(t *testing.T) { - assert.Equal(t, test.want, buildTimeSettings(test.dashboard, test.reqDTO, test.pubdash)) + assert.Equal(t, test.want, buildTimeSettings(test.dashboard, test.reqDTO, test.pubdash, test.panelID)) }) } }