Skip to content

Commit 21674b6

Browse files
feat(dashboards): adds support for initial sorting and refresh rate (#2732)
Co-authored-by: pranav-new-relic <[email protected]>
1 parent 6640ecb commit 21674b6

6 files changed

+132
-3
lines changed

go.mod

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ require (
77
github.com/mitchellh/go-homedir v1.1.0
88
github.com/newrelic/go-agent/v3 v3.30.0
99
github.com/newrelic/go-insights v1.0.3
10-
github.com/newrelic/newrelic-client-go/v2 v2.43.2
10+
github.com/newrelic/newrelic-client-go/v2 v2.44.0
1111
github.com/stretchr/testify v1.9.0
1212
golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8
1313
)

go.sum

+2-2
Original file line numberDiff line numberDiff line change
@@ -270,8 +270,8 @@ github.com/newrelic/go-agent/v3 v3.30.0 h1:ZXHCT/Cot4iIPwcegCZURuRQOsfmGA6wilW+S
270270
github.com/newrelic/go-agent/v3 v3.30.0/go.mod h1:9utrgxlSryNqRrTvII2XBL+0lpofXbqXApvVWPpbzUg=
271271
github.com/newrelic/go-insights v1.0.3 h1:zSNp1CEZnXktzSIEsbHJk8v6ZihdPFP2WsO/fzau3OQ=
272272
github.com/newrelic/go-insights v1.0.3/go.mod h1:A20BoT8TNkqPGX2nS/Z2fYmKl3Cqa3iKZd4whzedCY4=
273-
github.com/newrelic/newrelic-client-go/v2 v2.43.2 h1:tWcXYxz1oO63kEWoGtiMXGKJ03VyW+l0UJKwOnMAyyU=
274-
github.com/newrelic/newrelic-client-go/v2 v2.43.2/go.mod h1:pDFY24/6iIMEbPIdowTRrRn9YYwkXc3j+B+XpTb4oF4=
273+
github.com/newrelic/newrelic-client-go/v2 v2.44.0 h1:n4zP64Hfui8pjW/D3tbE1Hi+Acbpz8nBIrI2miEAGiI=
274+
github.com/newrelic/newrelic-client-go/v2 v2.44.0/go.mod h1:pDFY24/6iIMEbPIdowTRrRn9YYwkXc3j+B+XpTb4oF4=
275275
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
276276
github.com/oklog/run v1.0.0 h1:Ru7dDtJNOyC66gQ5dQmaCa0qIsAUFY3sFpK1Xk8igrw=
277277
github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=

newrelic/resource_newrelic_one_dashboard.go

+27
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,17 @@ func dashboardWidgetSchemaBase() map[string]*schema.Schema {
319319
Required: true,
320320
Elem: dashboardWidgetNRQLQuerySchemaElem(),
321321
},
322+
"refresh_rate": {
323+
Type: schema.TypeString,
324+
Optional: true,
325+
},
326+
"initial_sorting": {
327+
Type: schema.TypeList,
328+
Optional: true,
329+
MaxItems: 1,
330+
MinItems: 1,
331+
Elem: dashboardWidgetInitialSortingSchemaElem(),
332+
},
322333
"ignore_time_range": {
323334
Type: schema.TypeBool,
324335
Optional: true,
@@ -444,6 +455,22 @@ func dashboardWidgetNullValuesSchemaElem() *schema.Resource {
444455
},
445456
}
446457
}
458+
func dashboardWidgetInitialSortingSchemaElem() *schema.Resource {
459+
return &schema.Resource{
460+
Schema: map[string]*schema.Schema{
461+
"direction": {
462+
Type: schema.TypeString,
463+
Required: true,
464+
Description: "Defines the sort order. Either ascending or descending.",
465+
},
466+
"name": {
467+
Type: schema.TypeString,
468+
Required: true,
469+
Description: "The column name to be sorted",
470+
},
471+
},
472+
}
473+
}
447474

448475
// dashboardWidgetNRQLQuerySchemaElem defines a NRQL query for use on a dashboard
449476
//

newrelic/resource_newrelic_one_dashboard_test.go

+8
Original file line numberDiff line numberDiff line change
@@ -594,6 +594,7 @@ func testAccCheckNewRelicOneDashboardConfig_PageSimple(pageName string) string {
594594
title = "foo"
595595
row = 4
596596
column = 1
597+
refresh_rate = 30000
597598
nrql_query {
598599
query = "FROM Transaction SELECT count(*) FACET name"
599600
}
@@ -644,6 +645,8 @@ func testAccCheckNewRelicOneDashboardConfig_PageFull(pageName string, accountID
644645
height = 3
645646
width = 12
646647
648+
refresh_rate = 30000
649+
647650
nrql_query {
648651
account_id = ` + accountID + `
649652
query = "FROM Transaction SELECT 51 TIMESERIES"
@@ -774,6 +777,11 @@ func testAccCheckNewRelicOneDashboardConfig_PageFull(pageName string, accountID
774777
severity = "unavailable"
775778
}
776779
linked_entity_guids = ["MjUyMDUyOHxWSVp8REFTSEJPQVJEfDE2NDYzMDQ"]
780+
refresh_rate = 30000
781+
initial_sorting {
782+
direction = "desc"
783+
name = "appName"
784+
}
777785
}
778786
779787
widget_json {

newrelic/structures_newrelic_one_dashboard.go

+65
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"errors"
77
"fmt"
88
"log"
9+
"reflect"
910
"strconv"
1011
"strings"
1112

@@ -356,6 +357,9 @@ func expandDashboardPageInput(d *schema.ResourceData, pages []interface{}, meta
356357

357358
// Set thresholds
358359
rawConfiguration.Thresholds = expandDashboardTableWidgetConfigurationThresholdInput(d, pageIndex, widgetIndex)
360+
// Set initalSorting
361+
rawConfiguration.InitialSorting = expandDashboardTableWidgetConfigInitialSortingInput(v.(map[string]interface{}))
362+
359363
widget.RawConfiguration, err = json.Marshal(rawConfiguration)
360364
if err != nil {
361365
return nil, err
@@ -530,6 +534,25 @@ func expandDashboardLineWidgetConfigurationThresholdInput(d *schema.ResourceData
530534
return lineWidgetThresholdsRoot
531535
}
532536

537+
func expandDashboardTableWidgetConfigInitialSortingInput(w map[string]interface{}) *dashboards.DashboardWidgetInitialSorting {
538+
var tableWidgetInitialSorting dashboards.DashboardWidgetInitialSorting
539+
540+
if q, ok := w["initial_sorting"]; ok && len(q.([]interface{})) == 1 && q.([]interface{})[0] != nil {
541+
dashboardInitialSortingMap := q.([]interface{})[0].(map[string]interface{})
542+
543+
if i, ok := dashboardInitialSortingMap["direction"]; ok {
544+
tableWidgetInitialSorting.Direction = i.(string)
545+
}
546+
547+
if i, ok := dashboardInitialSortingMap["name"]; ok {
548+
tableWidgetInitialSorting.Name = i.(string)
549+
}
550+
return &tableWidgetInitialSorting
551+
}
552+
553+
return nil
554+
}
555+
533556
func expandDashboardTableWidgetConfigurationThresholdInput(d *schema.ResourceData, pageIndex int, widgetIndex int) []dashboards.DashboardTableWidgetThresholdInput {
534557
// initialize an object of []DashboardTableWidgetThresholdInput, which would include a list of tableWidgetThresholdsToBeAdded as specified
535558
// in the Terraform configuration, with the attribute "threshold" in table widgets
@@ -628,6 +651,19 @@ func expandDashboardWidgetInput(w map[string]interface{}, meta interface{}, visu
628651
l.ShowOtherSeries = q.(bool)
629652
cfg.Facet = &l
630653
}
654+
if q, ok := w["refresh_rate"]; ok {
655+
var l dashboards.DashboardWidgetRefreshRate
656+
657+
// Acceptable values for refresh rate could be string such as "auto", or number such as 5000
658+
// If we try to send numerical values as string to NerdGraph eg: "5000", the refresh rate isn't reflected in the UI
659+
// Hence we need to convert numerical values from string type to int type
660+
if v, err := strconv.Atoi(q.(string)); err == nil {
661+
l.Frequency = v
662+
} else {
663+
l.Frequency = q.(string)
664+
}
665+
cfg.RefreshRate = &l
666+
}
631667

632668
cfg = expandDashboardWidgetYAxisAttributesVizClassified(w, cfg, visualisation)
633669
cfg = expandDashboardWidgetNullValuesInput(w, cfg)
@@ -1191,6 +1227,16 @@ func flattenDashboardWidget(in *entities.DashboardWidget, pageGUID string) (stri
11911227
if rawCfg.Colors != nil {
11921228
out["colors"] = flattenDashboardWidgetColors(rawCfg.Colors)
11931229
}
1230+
if rawCfg.RefreshRate != nil {
1231+
// Since schema for refresh_rate is defined as string
1232+
// If we get integer values in graphQL response, we need to convert to string
1233+
if reflect.TypeOf(rawCfg.RefreshRate.Frequency).Kind() == reflect.String {
1234+
out["refresh_rate"] = rawCfg.RefreshRate.Frequency
1235+
} else {
1236+
s := strconv.FormatFloat(rawCfg.RefreshRate.Frequency.(float64), 'f', -1, 64)
1237+
out["refresh_rate"] = s
1238+
}
1239+
}
11941240

11951241
// Set widget type and arguments
11961242
switch in.Visualization.ID {
@@ -1275,6 +1321,14 @@ func flattenDashboardWidget(in *entities.DashboardWidget, pageGUID string) (stri
12751321
widgetType = "widget_table"
12761322
out["nrql_query"] = flattenDashboardWidgetNRQLQuery(&rawCfg.NRQLQueries)
12771323
out["filter_current_dashboard"] = filterCurrentDashboard
1324+
1325+
if rawCfg.InitialSorting != nil {
1326+
initialSorting := flattenDashboardWidgetInitialSorting(rawCfg.InitialSorting)
1327+
if initialSorting != nil {
1328+
out["initial_sorting"] = initialSorting
1329+
}
1330+
}
1331+
12781332
if rawCfg.Thresholds != nil {
12791333
thresholds := flattenDashboardTableWidgetThresholds(rawCfg.Thresholds)
12801334
if thresholds != nil {
@@ -1290,6 +1344,17 @@ func flattenDashboardWidget(in *entities.DashboardWidget, pageGUID string) (stri
12901344
return widgetType, out
12911345
}
12921346

1347+
func flattenDashboardWidgetInitialSorting(in *dashboards.DashboardWidgetInitialSorting) []interface{} {
1348+
out := make([]interface{}, 1)
1349+
k := make(map[string]interface{})
1350+
1351+
k["direction"] = in.Direction
1352+
k["name"] = in.Name
1353+
1354+
out[0] = k
1355+
return out
1356+
}
1357+
12931358
func flattenDashboardWidgetNRQLQuery(in *[]dashboards.DashboardWidgetNRQLQueryInput) []interface{} {
12941359
out := make([]interface{}, len(*in))
12951360

website/docs/r/one_dashboard.html.markdown

+29
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,34 @@ resource "newrelic_one_dashboard" "exampledash" {
1919
page {
2020
name = "New Relic Terraform Example"
2121
22+
widget_table {
23+
title = "List of Transactions"
24+
row = 1
25+
column = 4
26+
width = 6
27+
height = 3
28+
29+
refresh_rate = 60000 // data refreshes every 60 seconds
30+
31+
nrql_query {
32+
query = "FROM Transaction SELECT *"
33+
}
34+
35+
initial_sorting {
36+
direction = "desc"
37+
name = "timestamp"
38+
}
39+
}
40+
2241
widget_billboard {
2342
title = "Requests per minute"
2443
row = 1
2544
column = 1
2645
width = 6
2746
height = 3
2847
48+
refresh_rate = 60000 // 60 seconds
49+
2950
nrql_query {
3051
query = "FROM Transaction SELECT rate(count(*), 1 minute)"
3152
}
@@ -54,6 +75,8 @@ resource "newrelic_one_dashboard" "exampledash" {
5475
width = 6
5576
height = 3
5677
78+
refresh_rate = 300000 // 5 minutes
79+
5780
nrql_query {
5881
account_id = 12345
5982
query = "FROM Transaction SELECT average(duration) FACET appName"
@@ -83,6 +106,8 @@ resource "newrelic_one_dashboard" "exampledash" {
83106
width = 6
84107
height = 3
85108
109+
refresh_rate = 30000 // 30 seconds
110+
86111
nrql_query {
87112
account_id = 12345
88113
query = "FROM Transaction select max(duration) as 'max duration' where httpResponseCode = '504' timeseries since 5 minutes ago"
@@ -270,6 +295,7 @@ All nested `widget` blocks support the following common arguments:
270295
* `null_values` - (Optional) A nested block that describes a Null Values. See [Nested Null Values blocks](#nested-null-values-blocks) below for details.
271296
* `units` - (Optional) A nested block that describes units on your Y axis. See [Nested Units blocks](#nested-units-blocks) below for details.
272297
* `colors` - (Optional) A nested block that describes colors of your charts per series. See [Nested Colors blocks](#nested-colors-blocks) below for details.
298+
* `refresh_rate` - (Optional) This attribute determines the frequency for data refresh specified in milliseconds. Accepted values are `auto` for default value, `0` for no refresh, `5000` for 5 seconds, `30000` for 30 seconds, `60000` for 60 seconds, `300000` for 5 minutes, `1800000` for 30 minutes, `3600000` for 60 minute, `10800000` for 3 hours, `43200000` for 12 hours and `86400000` for 24 hours.
273299

274300
Each widget type supports an additional set of arguments:
275301

@@ -328,6 +354,9 @@ Each widget type supports an additional set of arguments:
328354
* `from` - The value 'from' which the threshold would need to be applied.
329355
* `to` - The value until which the threshold would need to be applied.
330356
* `severity` - The severity of the threshold, which would affect the visual appearance of the threshold (such as its color) accordingly. The value of this attribute would need to be one of the following - `warning`, `severe`, `critical`, `success`, `unavailable` which correspond to the severity labels _Warning_, _Approaching critical_, _Critical_, _Good_, _Neutral_ in the dropdown that helps specify the severity of thresholds in table widgets in the UI, respectively.
357+
* `initial_sorting` - (Optional) An attribute that describes the sorting mechanism for the table. This attribute requires specifying the following attributes in a nested block -
358+
* `name` - (Required) The name of column to be sorted. Examples of few valid values are `timestamp`, `appId`, `appName`, etc.
359+
* `direction` - (Required) Defines the sort order. Accepted values are `asc` for ascending or `desc` for descending.
331360

332361

333362
### Nested `nrql_query` blocks

0 commit comments

Comments
 (0)