From 4b54416b4a5d4ce65face052f4b3da515c2e4c15 Mon Sep 17 00:00:00 2001 From: Vitaly Zhuravlev Date: Tue, 5 Nov 2024 12:33:55 +0000 Subject: [PATCH 1/7] Add unit rule smart exceptions --- docs/rules/panel-units-rule.md | 8 +- go.mod | 1 + go.sum | 2 + lint/lint.go | 64 +++++---------- lint/rule_panel_units.go | 69 +++++++++++++++-- lint/rule_panel_units_test.go | 137 +++++++++++++++++++++++++++++++-- 6 files changed, 222 insertions(+), 59 deletions(-) diff --git a/docs/rules/panel-units-rule.md b/docs/rules/panel-units-rule.md index d68807b..cf2f88d 100644 --- a/docs/rules/panel-units-rule.md +++ b/docs/rules/panel-units-rule.md @@ -4,7 +4,11 @@ Checks that every panel has a unit specified, and that the unit is valid per the It currently only checks panels of type ["stat", "singlestat", "graph", "table", "timeseries", "gauge"]. # Best Practice -All panels should have all of their axis labeled with an apprioriate unit. +All panels should have an apprioriate unit set. # Possible exceptions -A panel may be visualizing something which does not have a predefined unit, or which is self explanatory from the vizualization title. In this case you may wish to create a lint exclusion for this rule. \ No newline at end of file +This rule is automatically excluded when: + - Value mappings are set in a panel. + - A Stat panel is configured to show non-numeric values (like label's value), for that 'Fields options' are configured to any value other than 'Numeric fields' (which is default). + +Also, a panel may be visualizing something which does not have a predefined unit, or which is self explanatory from the vizualization title. In this case you may wish to create a lint exclusion for this rule. \ No newline at end of file diff --git a/go.mod b/go.mod index ba69689..2e91c84 100644 --- a/go.mod +++ b/go.mod @@ -64,6 +64,7 @@ require ( github.com/gorilla/mux v1.8.1 // indirect github.com/grafana/dskit v0.0.0-20240905221822-931a021fb06b // indirect github.com/grafana/gomemcache v0.0.0-20240229205252-cd6a66d6fb56 // indirect + github.com/grafana/grafana-foundation-sdk/go v0.0.0-20241101005901-83e3491f2a70 // indirect github.com/grafana/jsonparser v0.0.0-20240425183733-ea80629e1a32 // indirect github.com/grafana/loki/pkg/push v0.0.0-20231124142027-e52380921608 // indirect github.com/grafana/pyroscope-go/godeltaprof v0.1.8 // indirect diff --git a/go.sum b/go.sum index 11254dd..36e9d2b 100644 --- a/go.sum +++ b/go.sum @@ -197,6 +197,8 @@ github.com/grafana/dskit v0.0.0-20240905221822-931a021fb06b h1:x2HCzk29I0o5pRPfq github.com/grafana/dskit v0.0.0-20240905221822-931a021fb06b/go.mod h1:SPLNCARd4xdjCkue0O6hvuoveuS1dGJjDnfxYe405YQ= github.com/grafana/gomemcache v0.0.0-20240229205252-cd6a66d6fb56 h1:X8IKQ0wu40wpvYcKfBcc5T4QnhdQjUhtUtB/1CY89lE= github.com/grafana/gomemcache v0.0.0-20240229205252-cd6a66d6fb56/go.mod h1:PGk3RjYHpxMM8HFPhKKo+vve3DdlPUELZLSDEFehPuU= +github.com/grafana/grafana-foundation-sdk/go v0.0.0-20241101005901-83e3491f2a70 h1:69GI3KsF851YnwYp6zHdsskcGp3ZnGsWc+ve8vMp1mc= +github.com/grafana/grafana-foundation-sdk/go v0.0.0-20241101005901-83e3491f2a70/go.mod h1:WtWosval1KCZP9BGa42b8aVoJmVXSg0EvQXi9LDSVZQ= github.com/grafana/jsonparser v0.0.0-20240425183733-ea80629e1a32 h1:NznuPwItog+rwdVg8hAuGKP29ndRSzJAwhxKldkP8oQ= github.com/grafana/jsonparser v0.0.0-20240425183733-ea80629e1a32/go.mod h1:796sq+UcONnSlzA3RtlBZ+b/hrerkZXiEmO8oMjyRwY= github.com/grafana/loki/pkg/push v0.0.0-20231124142027-e52380921608 h1:ZYk42718kSXOiIKdjZKljWLgBpzL5z1yutKABksQCMg= diff --git a/lint/lint.go b/lint/lint.go index b38df8a..d4012f0 100644 --- a/lint/lint.go +++ b/lint/lint.go @@ -4,6 +4,9 @@ import ( "encoding/json" "fmt" "strings" + + "github.com/grafana/grafana-foundation-sdk/go/dashboard" + "github.com/grafana/grafana-foundation-sdk/go/stat" ) type Severity int @@ -195,55 +198,26 @@ func (a *Annotation) GetDataSource() (Datasource, error) { // Panel is a deliberately incomplete representation of the Dashboard -> Panel type in grafana. // The properties which are extracted from JSON are only those used for linting purposes. type Panel struct { - Id int `json:"id"` - Title string `json:"title"` - Description string `json:"description,omitempty"` - Targets []Target `json:"targets,omitempty"` - Datasource interface{} `json:"datasource,omitempty"` - Type string `json:"type"` - Panels []Panel `json:"panels,omitempty"` - FieldConfig *FieldConfig `json:"fieldConfig,omitempty"` -} - -type FieldConfig struct { - Defaults Defaults `json:"defaults,omitempty"` - Overrides []Override `json:"overrides,omitempty"` -} - -type Override struct { - OverrideProperties []OverrideProperty `json:"properties"` + Id int `json:"id"` + Title string `json:"title"` + Description string `json:"description,omitempty"` + Targets []Target `json:"targets,omitempty"` + Datasource interface{} `json:"datasource,omitempty"` + Type string `json:"type"` + Panels []Panel `json:"panels,omitempty"` + FieldConfig *FieldConfig `json:"fieldConfig,omitempty"` + Options json.RawMessage `json:"options,omitempty"` } -type OverrideProperty struct { - Id string `json:"id"` - Value string `json:"value"` +type statPanel struct { + options stat.Options + Panel } -func (o *OverrideProperty) UnmarshalJSON(buf []byte) error { - // An override value can be of type string or int - // This function detects type mismatch and uses an int type for Value - var raw struct { - Id string `json:"id"` - Value string `json:"value"` - } - - if err := json.Unmarshal(buf, &raw); err != nil { - var raw struct { - Id string `json:"id"` - Value int `json:"value"` - } - if err := json.Unmarshal(buf, &raw); err != nil { - // Override can have varying different types int, string and arrays - // Currently only units are being checked from overrides so returning nil in case of unhandled types - return nil - } - } - - return nil -} - -type Defaults struct { - Unit string `json:"unit,omitempty"` +type FieldConfig struct { + Defaults dashboard.FieldConfig + //Overrides []Override `json:"overrides,omitempty"` + Overrides []dashboard.DashboardFieldConfigSourceOverrides } // GetPanels returns the all panels nested inside the panel (inc the current panel) diff --git a/lint/rule_panel_units.go b/lint/rule_panel_units.go index ace2c3f..1d2b9a2 100644 --- a/lint/rule_panel_units.go +++ b/lint/rule_panel_units.go @@ -1,6 +1,11 @@ package lint -import "fmt" +import ( + "fmt" + + "github.com/grafana/grafana-foundation-sdk/go/dashboard" + "github.com/grafana/grafana-foundation-sdk/go/stat" +) func NewPanelUnitsRule() *PanelRuleFunc { validUnits := []string{ @@ -73,11 +78,37 @@ func NewPanelUnitsRule() *PanelRuleFunc { configuredUnit := getConfiguredUnit(p) if configuredUnit != "" { for _, u := range validUnits { - if u == p.FieldConfig.Defaults.Unit { + if u == *p.FieldConfig.Defaults.Unit { return r } } } + + // ignore if has reduceOptions fields (for stat panels only): + if p.Type == "stat" { + var opts stat.Options + optsByte, err := p.Options.MarshalJSON() + if err != nil { + r.AddError(d, p, err.Error()) + } + err = (*stat.Options).UnmarshalJSONStrict(&opts, optsByte) + if err != nil { + r.AddError(d, p, err.Error()) + } + statPanel := &statPanel{ + Panel: p, + options: opts, + } + + if hasReduceOptionsNonNumericFields(*statPanel) { + return r + } + } + + //ignore if has value mappings: + if len(getValueMappings(p)) > 0 { + return r + } r.AddError(d, p, fmt.Sprintf("has no or invalid units defined: '%s'", configuredUnit)) } return r @@ -90,15 +121,41 @@ func getConfiguredUnit(p Panel) string { // First check if an override with unit exists - if no override then check if standard unit is present and valid if p.FieldConfig != nil && len(p.FieldConfig.Overrides) > 0 { for _, p := range p.FieldConfig.Overrides { - for _, o := range p.OverrideProperties { + for _, o := range p.Properties { if o.Id == "unit" { - configuredUnit = o.Value + configuredUnit = o.Value.(string) } } } } - if configuredUnit == "" && p.FieldConfig != nil && len(p.FieldConfig.Defaults.Unit) > 0 { - configuredUnit = p.FieldConfig.Defaults.Unit + if configuredUnit == "" && p.FieldConfig != nil && p.FieldConfig.Defaults.Unit != nil { + configuredUnit = *p.FieldConfig.Defaults.Unit } return configuredUnit } + +func getValueMappings(p Panel) []dashboard.ValueMapping { + valueMappings := make([]dashboard.ValueMapping, 0) + // First check if an override with unit exists - if no override then check if standard unit is present and valid + if p.FieldConfig != nil && len(p.FieldConfig.Overrides) > 0 { + for _, p := range p.FieldConfig.Overrides { + for _, o := range p.Properties { + if o.Id == "mappings" { + valueMappings = o.Value.([]dashboard.ValueMapping) + } + } + } + } + if len(valueMappings) == 0 && p.FieldConfig != nil && p.FieldConfig.Defaults.Mappings != nil { + valueMappings = *&p.FieldConfig.Defaults.Mappings + } + return valueMappings +} + +func hasReduceOptionsNonNumericFields(p statPanel) bool { + + if p.options.ReduceOptions.Fields != nil && *p.options.ReduceOptions.Fields != "" { + return true + } + return false +} diff --git a/lint/rule_panel_units_test.go b/lint/rule_panel_units_test.go index 1b98fc6..0b1887e 100644 --- a/lint/rule_panel_units_test.go +++ b/lint/rule_panel_units_test.go @@ -2,11 +2,28 @@ package lint import ( "testing" + + "github.com/grafana/grafana-foundation-sdk/go/dashboard" ) +func ptr[T any](t T) *T { return &t } func TestPanelUnits(t *testing.T) { linter := NewPanelUnitsRule() + testValueMap := &dashboard.ValueMap{ + Type: "value", + Options: map[string]dashboard.ValueMappingResult{ + "1": { + Text: ptr("Ok"), + Color: ptr("green"), + }, + "2": { + Text: ptr("Down"), + Color: ptr("red"), + }, + }, + } + for _, tc := range []struct { name string result Result @@ -23,8 +40,8 @@ func TestPanelUnits(t *testing.T) { Datasource: "foo", Title: "bar", FieldConfig: &FieldConfig{ - Defaults: Defaults{ - Unit: "MyInvalidUnit", + Defaults: dashboard.FieldConfig{ + Unit: ptr("MyInvalidUnit"), }, }, }, @@ -62,8 +79,8 @@ func TestPanelUnits(t *testing.T) { Datasource: "foo", Title: "bar", FieldConfig: &FieldConfig{ - Defaults: Defaults{ - Unit: "short", + Defaults: dashboard.FieldConfig{ + Unit: ptr("short"), }, }, }, @@ -76,8 +93,116 @@ func TestPanelUnits(t *testing.T) { Datasource: "foo", Title: "bar", FieldConfig: &FieldConfig{ - Defaults: Defaults{ - Unit: "none", + Defaults: dashboard.FieldConfig{ + Unit: ptr("none"), + }, + }, + }, + }, + { + name: "has nonnumeric reduceOptions fields", + result: ResultSuccess, + panel: Panel{ + Type: "stat", + Datasource: "foo", + Title: "bar", + Options: []byte(` + { + "reduceOptions": { + "values": false, + "calcs": [ + "lastNotNull" + ], + "fields": "/^version$/" + }, + "orientation": "auto", + "textMode": "auto", + "wideLayout": true, + "colorMode": "fixed", + "graphMode": "none", + "justifyMode": "auto", + "showPercentChange": false, + "percentChangeColorMode": "standard" + } + + `), + }, + }, + { + name: "has empty reduceOptions fields(Numeric Fields default value)", + result: Result{ + Severity: Error, + Message: "Dashboard 'test', panel 'bar' has no or invalid units defined: ''", + }, + panel: Panel{ + Type: "stat", + Datasource: "foo", + Title: "bar", + Options: []byte(` + { + "reduceOptions": { + "values": false, + "calcs": [ + "lastNotNull" + ], + "fields": "" + }, + "orientation": "auto", + "textMode": "auto", + "wideLayout": true, + "colorMode": "fixed", + "graphMode": "none", + "justifyMode": "auto", + "showPercentChange": false, + "percentChangeColorMode": "standard" + } + + `), + }, + }, + { + name: "no units but have value mappings", + result: ResultSuccess, + panel: Panel{ + Type: "singlestat", + Datasource: "foo", + Title: "bar", + FieldConfig: &FieldConfig{ + Defaults: dashboard.FieldConfig{ + Mappings: []dashboard.ValueMapOrRangeMapOrRegexMapOrSpecialValueMap{ + dashboard.ValueMapOrRangeMapOrRegexMapOrSpecialValueMap{ + ValueMap: testValueMap, + }, + }, + }, + }, + }, + }, + { + name: "no units but have value mappings in overrides", + result: ResultSuccess, + panel: Panel{ + Type: "singlestat", + Datasource: "foo", + Title: "bar", + FieldConfig: &FieldConfig{ + Overrides: []dashboard.DashboardFieldConfigSourceOverrides{ + dashboard.DashboardFieldConfigSourceOverrides{ + Matcher: dashboard.MatcherConfig{ + Id: "byRegexp", + Options: "/.*/", + }, + Properties: []dashboard.DynamicConfigValue{ + dashboard.DynamicConfigValue{ + Id: "mappings", + Value: []dashboard.ValueMapOrRangeMapOrRegexMapOrSpecialValueMap{ + dashboard.ValueMapOrRangeMapOrRegexMapOrSpecialValueMap{ + ValueMap: testValueMap, + }, + }, + }, + }, + }, }, }, }, From 985c7334d55e2976b687df2a8d2b36c30273a9e2 Mon Sep 17 00:00:00 2001 From: Vitaly Zhuravlev Date: Tue, 5 Nov 2024 13:11:57 +0000 Subject: [PATCH 2/7] Simplify stat options Cannot use UnmarshallJsonStrict() of stat.Options, some fields may be missing. --- lint/lint.go | 30 +++++++++++++++++------------- lint/rule_panel_units.go | 23 ++++++++--------------- lint/rule_panel_units_test.go | 28 ++-------------------------- 3 files changed, 27 insertions(+), 54 deletions(-) diff --git a/lint/lint.go b/lint/lint.go index d4012f0..08cca65 100644 --- a/lint/lint.go +++ b/lint/lint.go @@ -6,7 +6,6 @@ import ( "strings" "github.com/grafana/grafana-foundation-sdk/go/dashboard" - "github.com/grafana/grafana-foundation-sdk/go/stat" ) type Severity int @@ -198,20 +197,25 @@ func (a *Annotation) GetDataSource() (Datasource, error) { // Panel is a deliberately incomplete representation of the Dashboard -> Panel type in grafana. // The properties which are extracted from JSON are only those used for linting purposes. type Panel struct { - Id int `json:"id"` - Title string `json:"title"` - Description string `json:"description,omitempty"` - Targets []Target `json:"targets,omitempty"` - Datasource interface{} `json:"datasource,omitempty"` - Type string `json:"type"` - Panels []Panel `json:"panels,omitempty"` - FieldConfig *FieldConfig `json:"fieldConfig,omitempty"` - Options json.RawMessage `json:"options,omitempty"` + Id int `json:"id"` + Title string `json:"title"` + Description string `json:"description,omitempty"` + Targets []Target `json:"targets,omitempty"` + Datasource interface{} `json:"datasource,omitempty"` + Type string `json:"type"` + Panels []Panel `json:"panels,omitempty"` + FieldConfig *FieldConfig `json:"fieldConfig,omitempty"` + Options []byte `json:"options,omitempty"` } -type statPanel struct { - options stat.Options - Panel +// oversimplified stat panel options +type StatOptions struct { + ReduceOptions ReduceOptions +} + +// oversimplified Reduce options +type ReduceOptions struct { + Fields string `json:"fields,omitempty"` } type FieldConfig struct { diff --git a/lint/rule_panel_units.go b/lint/rule_panel_units.go index 1d2b9a2..162c753 100644 --- a/lint/rule_panel_units.go +++ b/lint/rule_panel_units.go @@ -1,10 +1,10 @@ package lint import ( + "encoding/json" "fmt" "github.com/grafana/grafana-foundation-sdk/go/dashboard" - "github.com/grafana/grafana-foundation-sdk/go/stat" ) func NewPanelUnitsRule() *PanelRuleFunc { @@ -86,21 +86,12 @@ func NewPanelUnitsRule() *PanelRuleFunc { // ignore if has reduceOptions fields (for stat panels only): if p.Type == "stat" { - var opts stat.Options - optsByte, err := p.Options.MarshalJSON() + var opts StatOptions + err := json.Unmarshal(p.Options, &opts) if err != nil { r.AddError(d, p, err.Error()) } - err = (*stat.Options).UnmarshalJSONStrict(&opts, optsByte) - if err != nil { - r.AddError(d, p, err.Error()) - } - statPanel := &statPanel{ - Panel: p, - options: opts, - } - - if hasReduceOptionsNonNumericFields(*statPanel) { + if hasReduceOptionsNonNumericFields(&opts.ReduceOptions) { return r } } @@ -152,10 +143,12 @@ func getValueMappings(p Panel) []dashboard.ValueMapping { return valueMappings } -func hasReduceOptionsNonNumericFields(p statPanel) bool { +// Numeric fields are set as empty string "". Any other value means nonnumeric on grafana stat panel. +func hasReduceOptionsNonNumericFields(reduceOpts *ReduceOptions) bool { - if p.options.ReduceOptions.Fields != nil && *p.options.ReduceOptions.Fields != "" { + if reduceOpts.Fields != "" { return true } + return false } diff --git a/lint/rule_panel_units_test.go b/lint/rule_panel_units_test.go index 0b1887e..d7daaf1 100644 --- a/lint/rule_panel_units_test.go +++ b/lint/rule_panel_units_test.go @@ -109,20 +109,8 @@ func TestPanelUnits(t *testing.T) { Options: []byte(` { "reduceOptions": { - "values": false, - "calcs": [ - "lastNotNull" - ], "fields": "/^version$/" - }, - "orientation": "auto", - "textMode": "auto", - "wideLayout": true, - "colorMode": "fixed", - "graphMode": "none", - "justifyMode": "auto", - "showPercentChange": false, - "percentChangeColorMode": "standard" + } } `), @@ -141,20 +129,8 @@ func TestPanelUnits(t *testing.T) { Options: []byte(` { "reduceOptions": { - "values": false, - "calcs": [ - "lastNotNull" - ], "fields": "" - }, - "orientation": "auto", - "textMode": "auto", - "wideLayout": true, - "colorMode": "fixed", - "graphMode": "none", - "justifyMode": "auto", - "showPercentChange": false, - "percentChangeColorMode": "standard" + } } `), From c3446b37b8a1b2de35bbc4c20fdb534937f90b06 Mon Sep 17 00:00:00 2001 From: Vitaly Zhuravlev Date: Tue, 5 Nov 2024 13:35:02 +0000 Subject: [PATCH 3/7] Fix nil excepion when comparing units. Move units down in the func --- lint/rule_panel_units.go | 17 +++++++++-------- lint/rule_panel_units_test.go | 4 ++-- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/lint/rule_panel_units.go b/lint/rule_panel_units.go index 162c753..15c047c 100644 --- a/lint/rule_panel_units.go +++ b/lint/rule_panel_units.go @@ -75,14 +75,6 @@ func NewPanelUnitsRule() *PanelRuleFunc { r := PanelRuleResults{} switch p.Type { case panelTypeStat, panelTypeSingleStat, panelTypeGraph, panelTypeTimeTable, panelTypeTimeSeries, panelTypeGauge: - configuredUnit := getConfiguredUnit(p) - if configuredUnit != "" { - for _, u := range validUnits { - if u == *p.FieldConfig.Defaults.Unit { - return r - } - } - } // ignore if has reduceOptions fields (for stat panels only): if p.Type == "stat" { @@ -100,6 +92,15 @@ func NewPanelUnitsRule() *PanelRuleFunc { if len(getValueMappings(p)) > 0 { return r } + + configuredUnit := getConfiguredUnit(p) + if configuredUnit != "" { + for _, u := range validUnits { + if u == configuredUnit { + return r + } + } + } r.AddError(d, p, fmt.Sprintf("has no or invalid units defined: '%s'", configuredUnit)) } return r diff --git a/lint/rule_panel_units_test.go b/lint/rule_panel_units_test.go index d7daaf1..21f1d84 100644 --- a/lint/rule_panel_units_test.go +++ b/lint/rule_panel_units_test.go @@ -112,7 +112,7 @@ func TestPanelUnits(t *testing.T) { "fields": "/^version$/" } } - + `), }, }, @@ -132,7 +132,7 @@ func TestPanelUnits(t *testing.T) { "fields": "" } } - + `), }, }, From f9f68b7e69b6ad0a399e81db551542b271dff79a Mon Sep 17 00:00:00 2001 From: Vitaly Zhuravlev Date: Tue, 5 Nov 2024 13:35:10 +0000 Subject: [PATCH 4/7] Update lint.go --- lint/lint.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lint/lint.go b/lint/lint.go index 08cca65..ea29bc0 100644 --- a/lint/lint.go +++ b/lint/lint.go @@ -210,7 +210,7 @@ type Panel struct { // oversimplified stat panel options type StatOptions struct { - ReduceOptions ReduceOptions + ReduceOptions ReduceOptions `json:"reduceOptions,omitempty"` } // oversimplified Reduce options @@ -220,7 +220,6 @@ type ReduceOptions struct { type FieldConfig struct { Defaults dashboard.FieldConfig - //Overrides []Override `json:"overrides,omitempty"` Overrides []dashboard.DashboardFieldConfigSourceOverrides } From fe23dd3cb6878d6a223638f746cfb6f68d255721 Mon Sep 17 00:00:00 2001 From: Vitaly Zhuravlev Date: Tue, 5 Nov 2024 14:16:29 +0000 Subject: [PATCH 5/7] Change to json.RawMessage --- lint/lint.go | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/lint/lint.go b/lint/lint.go index ea29bc0..686be48 100644 --- a/lint/lint.go +++ b/lint/lint.go @@ -197,18 +197,19 @@ func (a *Annotation) GetDataSource() (Datasource, error) { // Panel is a deliberately incomplete representation of the Dashboard -> Panel type in grafana. // The properties which are extracted from JSON are only those used for linting purposes. type Panel struct { - Id int `json:"id"` - Title string `json:"title"` - Description string `json:"description,omitempty"` - Targets []Target `json:"targets,omitempty"` - Datasource interface{} `json:"datasource,omitempty"` - Type string `json:"type"` - Panels []Panel `json:"panels,omitempty"` - FieldConfig *FieldConfig `json:"fieldConfig,omitempty"` - Options []byte `json:"options,omitempty"` + Id int `json:"id"` + Title string `json:"title"` + Description string `json:"description,omitempty"` + Targets []Target `json:"targets,omitempty"` + Datasource interface{} `json:"datasource,omitempty"` + Type string `json:"type"` + Panels []Panel `json:"panels,omitempty"` + FieldConfig *FieldConfig `json:"fieldConfig,omitempty"` + Options json.RawMessage `json:"options,omitempty"` } -// oversimplified stat panel options +// Stat panel options is a deliberately incomplete representation of the stat panel options from grafana. +// The properties which are extracted from JSON are only those used for linting purposes. type StatOptions struct { ReduceOptions ReduceOptions `json:"reduceOptions,omitempty"` } @@ -219,7 +220,7 @@ type ReduceOptions struct { } type FieldConfig struct { - Defaults dashboard.FieldConfig + Defaults dashboard.FieldConfig Overrides []dashboard.DashboardFieldConfigSourceOverrides } From 1e1fabfe6f4893a8b5f31570c93c6e402db4c134 Mon Sep 17 00:00:00 2001 From: Vitaly Zhuravlev Date: Tue, 5 Nov 2024 14:22:27 +0000 Subject: [PATCH 6/7] Lint --- lint/rule_panel_units.go | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/lint/rule_panel_units.go b/lint/rule_panel_units.go index 15c047c..5339374 100644 --- a/lint/rule_panel_units.go +++ b/lint/rule_panel_units.go @@ -147,9 +147,5 @@ func getValueMappings(p Panel) []dashboard.ValueMapping { // Numeric fields are set as empty string "". Any other value means nonnumeric on grafana stat panel. func hasReduceOptionsNonNumericFields(reduceOpts *ReduceOptions) bool { - if reduceOpts.Fields != "" { - return true - } - - return false + return reduceOpts.Fields != "" } From 29f09b5e22899a1ed90e2ef49fe2cabdd1696d83 Mon Sep 17 00:00:00 2001 From: Vitaly Zhuravlev Date: Tue, 5 Nov 2024 14:24:28 +0000 Subject: [PATCH 7/7] Lint --- lint/rule_panel_units.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lint/rule_panel_units.go b/lint/rule_panel_units.go index 5339374..7fea86a 100644 --- a/lint/rule_panel_units.go +++ b/lint/rule_panel_units.go @@ -139,7 +139,7 @@ func getValueMappings(p Panel) []dashboard.ValueMapping { } } if len(valueMappings) == 0 && p.FieldConfig != nil && p.FieldConfig.Defaults.Mappings != nil { - valueMappings = *&p.FieldConfig.Defaults.Mappings + valueMappings = p.FieldConfig.Defaults.Mappings } return valueMappings }