Public Dashboard: Support relative time range in panels when time picker is disabled (#96076)

Public Dashboard: Support relative time range in panels
This commit is contained in:
Agnès Toulet 2024-11-12 09:21:13 +01:00 committed by GitHub
parent 4c0dde6f2f
commit d2aca99d38
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 69 additions and 8 deletions

View File

@ -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 // 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 // group queries by panel
queriesByPanel := groupQueriesByPanelId(dashboard.Data) queriesByPanel := groupQueriesByPanelId(dashboard.Data)
queries, ok := queriesByPanel[panelId] queries, ok := queriesByPanel[panelID]
if !ok { if !ok {
return dtos.MetricRequest{}, models.ErrPanelNotFound.Errorf("buildMetricRequest: public dashboard panel not found") 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 // determine safe resolution to query data at
safeInterval, safeResolution := pd.getSafeIntervalAndMaxDataPoints(reqDTO, ts) safeInterval, safeResolution := pd.getSafeIntervalAndMaxDataPoints(reqDTO, ts)
@ -372,8 +372,8 @@ func sanitizeData(data *simplejson.Json) {
var NewTimeRange = gtime.NewTimeRange var NewTimeRange = gtime.NewTimeRange
// BuildTimeSettings build time settings object using selected values if enabled and are valid or dashboard default values // 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 { func buildTimeSettings(d *dashboards.Dashboard, reqDTO models.PublicDashboardQueryDTO, pd *models.PublicDashboard, panelID int64) models.TimeSettings {
from, to, timezone := getTimeRangeValuesOrDefault(reqDTO, d, pd.TimeSelectionEnabled) from, to, timezone := getTimeRangeValuesOrDefault(reqDTO, d, pd.TimeSelectionEnabled, panelID)
timeRange := NewTimeRange(from, to) 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 // 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() from := d.Data.GetPath("time", "from").MustString()
to := d.Data.GetPath("time", "to").MustString() to := d.Data.GetPath("time", "to").MustString()
dashboardTimezone := d.Data.GetPath("timezone").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 // we use the values from the request if the time selection is enabled and the values are valid
if timeSelectionEnabled { if timeSelectionEnabled {
if reqDTO.TimeRange.From != "" && reqDTO.TimeRange.To != "" { if reqDTO.TimeRange.From != "" && reqDTO.TimeRange.To != "" {
@ -421,3 +426,15 @@ func getTimeRangeValuesOrDefault(reqDTO models.PublicDashboardQueryDTO, d *dashb
return from, to, timezone 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 ""
}

View File

@ -1609,9 +1609,20 @@ func TestBuildTimeSettings(t *testing.T) {
}, },
"timezone": "America/Argentina/Mendoza", "timezone": "America/Argentina/Mendoza",
}) })
defaultFromMs, defaultToMs := internal.GetTimeRangeFromDashboard(t, defaultDashboardData) 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") fakeTimezone, _ := time.LoadLocation("Europe/Madrid")
fakeNow := time.Date(2018, 12, 9, 20, 30, 0, 0, fakeTimezone) fakeNow := time.Date(2018, 12, 9, 20, 30, 0, 0, fakeTimezone)
@ -1638,6 +1649,7 @@ func TestBuildTimeSettings(t *testing.T) {
dashboard *dashboards.Dashboard dashboard *dashboards.Dashboard
pubdash *PublicDashboard pubdash *PublicDashboard
reqDTO PublicDashboardQueryDTO reqDTO PublicDashboardQueryDTO
panelID int64
want TimeSettings want TimeSettings
}{ }{
{ {
@ -1745,11 +1757,43 @@ func TestBuildTimeSettings(t *testing.T) {
To: defaultToMs, 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 { for _, test := range testCases {
t.Run(test.name, func(t *testing.T) { 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))
}) })
} }
} }