Skip to content

Commit

Permalink
feat(dashboards): adds support for initial sorting and refresh rate (#…
Browse files Browse the repository at this point in the history
…2732)

Co-authored-by: pranav-new-relic <[email protected]>
  • Loading branch information
gmanandhar-nr and pranav-new-relic authored Sep 3, 2024
1 parent 6640ecb commit 21674b6
Show file tree
Hide file tree
Showing 6 changed files with 132 additions and 3 deletions.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ require (
github.com/mitchellh/go-homedir v1.1.0
github.com/newrelic/go-agent/v3 v3.30.0
github.com/newrelic/go-insights v1.0.3
github.com/newrelic/newrelic-client-go/v2 v2.43.2
github.com/newrelic/newrelic-client-go/v2 v2.44.0
github.com/stretchr/testify v1.9.0
golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8
)
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -270,8 +270,8 @@ github.com/newrelic/go-agent/v3 v3.30.0 h1:ZXHCT/Cot4iIPwcegCZURuRQOsfmGA6wilW+S
github.com/newrelic/go-agent/v3 v3.30.0/go.mod h1:9utrgxlSryNqRrTvII2XBL+0lpofXbqXApvVWPpbzUg=
github.com/newrelic/go-insights v1.0.3 h1:zSNp1CEZnXktzSIEsbHJk8v6ZihdPFP2WsO/fzau3OQ=
github.com/newrelic/go-insights v1.0.3/go.mod h1:A20BoT8TNkqPGX2nS/Z2fYmKl3Cqa3iKZd4whzedCY4=
github.com/newrelic/newrelic-client-go/v2 v2.43.2 h1:tWcXYxz1oO63kEWoGtiMXGKJ03VyW+l0UJKwOnMAyyU=
github.com/newrelic/newrelic-client-go/v2 v2.43.2/go.mod h1:pDFY24/6iIMEbPIdowTRrRn9YYwkXc3j+B+XpTb4oF4=
github.com/newrelic/newrelic-client-go/v2 v2.44.0 h1:n4zP64Hfui8pjW/D3tbE1Hi+Acbpz8nBIrI2miEAGiI=
github.com/newrelic/newrelic-client-go/v2 v2.44.0/go.mod h1:pDFY24/6iIMEbPIdowTRrRn9YYwkXc3j+B+XpTb4oF4=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/oklog/run v1.0.0 h1:Ru7dDtJNOyC66gQ5dQmaCa0qIsAUFY3sFpK1Xk8igrw=
github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
Expand Down
27 changes: 27 additions & 0 deletions newrelic/resource_newrelic_one_dashboard.go
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,17 @@ func dashboardWidgetSchemaBase() map[string]*schema.Schema {
Required: true,
Elem: dashboardWidgetNRQLQuerySchemaElem(),
},
"refresh_rate": {
Type: schema.TypeString,
Optional: true,
},
"initial_sorting": {
Type: schema.TypeList,
Optional: true,
MaxItems: 1,
MinItems: 1,
Elem: dashboardWidgetInitialSortingSchemaElem(),
},
"ignore_time_range": {
Type: schema.TypeBool,
Optional: true,
Expand Down Expand Up @@ -444,6 +455,22 @@ func dashboardWidgetNullValuesSchemaElem() *schema.Resource {
},
}
}
func dashboardWidgetInitialSortingSchemaElem() *schema.Resource {
return &schema.Resource{
Schema: map[string]*schema.Schema{
"direction": {
Type: schema.TypeString,
Required: true,
Description: "Defines the sort order. Either ascending or descending.",
},
"name": {
Type: schema.TypeString,
Required: true,
Description: "The column name to be sorted",
},
},
}
}

// dashboardWidgetNRQLQuerySchemaElem defines a NRQL query for use on a dashboard
//
Expand Down
8 changes: 8 additions & 0 deletions newrelic/resource_newrelic_one_dashboard_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -594,6 +594,7 @@ func testAccCheckNewRelicOneDashboardConfig_PageSimple(pageName string) string {
title = "foo"
row = 4
column = 1
refresh_rate = 30000
nrql_query {
query = "FROM Transaction SELECT count(*) FACET name"
}
Expand Down Expand Up @@ -644,6 +645,8 @@ func testAccCheckNewRelicOneDashboardConfig_PageFull(pageName string, accountID
height = 3
width = 12
refresh_rate = 30000
nrql_query {
account_id = ` + accountID + `
query = "FROM Transaction SELECT 51 TIMESERIES"
Expand Down Expand Up @@ -774,6 +777,11 @@ func testAccCheckNewRelicOneDashboardConfig_PageFull(pageName string, accountID
severity = "unavailable"
}
linked_entity_guids = ["MjUyMDUyOHxWSVp8REFTSEJPQVJEfDE2NDYzMDQ"]
refresh_rate = 30000
initial_sorting {
direction = "desc"
name = "appName"
}
}
widget_json {
Expand Down
65 changes: 65 additions & 0 deletions newrelic/structures_newrelic_one_dashboard.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"errors"
"fmt"
"log"
"reflect"
"strconv"
"strings"

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

// Set thresholds
rawConfiguration.Thresholds = expandDashboardTableWidgetConfigurationThresholdInput(d, pageIndex, widgetIndex)
// Set initalSorting
rawConfiguration.InitialSorting = expandDashboardTableWidgetConfigInitialSortingInput(v.(map[string]interface{}))

widget.RawConfiguration, err = json.Marshal(rawConfiguration)
if err != nil {
return nil, err
Expand Down Expand Up @@ -530,6 +534,25 @@ func expandDashboardLineWidgetConfigurationThresholdInput(d *schema.ResourceData
return lineWidgetThresholdsRoot
}

func expandDashboardTableWidgetConfigInitialSortingInput(w map[string]interface{}) *dashboards.DashboardWidgetInitialSorting {
var tableWidgetInitialSorting dashboards.DashboardWidgetInitialSorting

if q, ok := w["initial_sorting"]; ok && len(q.([]interface{})) == 1 && q.([]interface{})[0] != nil {
dashboardInitialSortingMap := q.([]interface{})[0].(map[string]interface{})

if i, ok := dashboardInitialSortingMap["direction"]; ok {
tableWidgetInitialSorting.Direction = i.(string)
}

if i, ok := dashboardInitialSortingMap["name"]; ok {
tableWidgetInitialSorting.Name = i.(string)
}
return &tableWidgetInitialSorting
}

return nil
}

func expandDashboardTableWidgetConfigurationThresholdInput(d *schema.ResourceData, pageIndex int, widgetIndex int) []dashboards.DashboardTableWidgetThresholdInput {
// initialize an object of []DashboardTableWidgetThresholdInput, which would include a list of tableWidgetThresholdsToBeAdded as specified
// in the Terraform configuration, with the attribute "threshold" in table widgets
Expand Down Expand Up @@ -628,6 +651,19 @@ func expandDashboardWidgetInput(w map[string]interface{}, meta interface{}, visu
l.ShowOtherSeries = q.(bool)
cfg.Facet = &l
}
if q, ok := w["refresh_rate"]; ok {
var l dashboards.DashboardWidgetRefreshRate

// Acceptable values for refresh rate could be string such as "auto", or number such as 5000
// If we try to send numerical values as string to NerdGraph eg: "5000", the refresh rate isn't reflected in the UI
// Hence we need to convert numerical values from string type to int type
if v, err := strconv.Atoi(q.(string)); err == nil {
l.Frequency = v
} else {
l.Frequency = q.(string)
}
cfg.RefreshRate = &l
}

cfg = expandDashboardWidgetYAxisAttributesVizClassified(w, cfg, visualisation)
cfg = expandDashboardWidgetNullValuesInput(w, cfg)
Expand Down Expand Up @@ -1191,6 +1227,16 @@ func flattenDashboardWidget(in *entities.DashboardWidget, pageGUID string) (stri
if rawCfg.Colors != nil {
out["colors"] = flattenDashboardWidgetColors(rawCfg.Colors)
}
if rawCfg.RefreshRate != nil {
// Since schema for refresh_rate is defined as string
// If we get integer values in graphQL response, we need to convert to string
if reflect.TypeOf(rawCfg.RefreshRate.Frequency).Kind() == reflect.String {
out["refresh_rate"] = rawCfg.RefreshRate.Frequency
} else {
s := strconv.FormatFloat(rawCfg.RefreshRate.Frequency.(float64), 'f', -1, 64)
out["refresh_rate"] = s
}
}

// Set widget type and arguments
switch in.Visualization.ID {
Expand Down Expand Up @@ -1275,6 +1321,14 @@ func flattenDashboardWidget(in *entities.DashboardWidget, pageGUID string) (stri
widgetType = "widget_table"
out["nrql_query"] = flattenDashboardWidgetNRQLQuery(&rawCfg.NRQLQueries)
out["filter_current_dashboard"] = filterCurrentDashboard

if rawCfg.InitialSorting != nil {
initialSorting := flattenDashboardWidgetInitialSorting(rawCfg.InitialSorting)
if initialSorting != nil {
out["initial_sorting"] = initialSorting
}
}

if rawCfg.Thresholds != nil {
thresholds := flattenDashboardTableWidgetThresholds(rawCfg.Thresholds)
if thresholds != nil {
Expand All @@ -1290,6 +1344,17 @@ func flattenDashboardWidget(in *entities.DashboardWidget, pageGUID string) (stri
return widgetType, out
}

func flattenDashboardWidgetInitialSorting(in *dashboards.DashboardWidgetInitialSorting) []interface{} {
out := make([]interface{}, 1)
k := make(map[string]interface{})

k["direction"] = in.Direction
k["name"] = in.Name

out[0] = k
return out
}

func flattenDashboardWidgetNRQLQuery(in *[]dashboards.DashboardWidgetNRQLQueryInput) []interface{} {
out := make([]interface{}, len(*in))

Expand Down
29 changes: 29 additions & 0 deletions website/docs/r/one_dashboard.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,34 @@ resource "newrelic_one_dashboard" "exampledash" {
page {
name = "New Relic Terraform Example"
widget_table {
title = "List of Transactions"
row = 1
column = 4
width = 6
height = 3
refresh_rate = 60000 // data refreshes every 60 seconds
nrql_query {
query = "FROM Transaction SELECT *"
}
initial_sorting {
direction = "desc"
name = "timestamp"
}
}
widget_billboard {
title = "Requests per minute"
row = 1
column = 1
width = 6
height = 3
refresh_rate = 60000 // 60 seconds
nrql_query {
query = "FROM Transaction SELECT rate(count(*), 1 minute)"
}
Expand Down Expand Up @@ -54,6 +75,8 @@ resource "newrelic_one_dashboard" "exampledash" {
width = 6
height = 3
refresh_rate = 300000 // 5 minutes
nrql_query {
account_id = 12345
query = "FROM Transaction SELECT average(duration) FACET appName"
Expand Down Expand Up @@ -83,6 +106,8 @@ resource "newrelic_one_dashboard" "exampledash" {
width = 6
height = 3
refresh_rate = 30000 // 30 seconds
nrql_query {
account_id = 12345
query = "FROM Transaction select max(duration) as 'max duration' where httpResponseCode = '504' timeseries since 5 minutes ago"
Expand Down Expand Up @@ -270,6 +295,7 @@ All nested `widget` blocks support the following common arguments:
* `null_values` - (Optional) A nested block that describes a Null Values. See [Nested Null Values blocks](#nested-null-values-blocks) below for details.
* `units` - (Optional) A nested block that describes units on your Y axis. See [Nested Units blocks](#nested-units-blocks) below for details.
* `colors` - (Optional) A nested block that describes colors of your charts per series. See [Nested Colors blocks](#nested-colors-blocks) below for details.
* `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.

Each widget type supports an additional set of arguments:

Expand Down Expand Up @@ -328,6 +354,9 @@ Each widget type supports an additional set of arguments:
* `from` - The value 'from' which the threshold would need to be applied.
* `to` - The value until which the threshold would need to be applied.
* `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.
* `initial_sorting` - (Optional) An attribute that describes the sorting mechanism for the table. This attribute requires specifying the following attributes in a nested block -
* `name` - (Required) The name of column to be sorted. Examples of few valid values are `timestamp`, `appId`, `appName`, etc.
* `direction` - (Required) Defines the sort order. Accepted values are `asc` for ascending or `desc` for descending.


### Nested `nrql_query` blocks
Expand Down

0 comments on commit 21674b6

Please sign in to comment.