mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Prometheus datasource: Show info annotations in the UI (#97978)
* Show info annotations from Prometheus datasources in the UI * Add test data for backend
This commit is contained in:
parent
228ac25ff4
commit
e3e51f6e3b
@ -34,6 +34,7 @@ func ReadPrometheusStyleResult(jIter *jsoniter.Iterator, opt Options) backend.Da
|
||||
errorType := ""
|
||||
promErrString := ""
|
||||
warnings := []data.Notice{}
|
||||
infos := []data.Notice{}
|
||||
|
||||
l1Fields:
|
||||
for l1Field, err := iter.ReadObject(); ; l1Field, err = iter.ReadObject() {
|
||||
@ -67,6 +68,11 @@ l1Fields:
|
||||
return rspErr(err)
|
||||
}
|
||||
|
||||
case "infos":
|
||||
if infos, err = readInfos(iter); err != nil {
|
||||
return rspErr(err)
|
||||
}
|
||||
|
||||
case "":
|
||||
if err != nil {
|
||||
return rspErr(err)
|
||||
@ -89,6 +95,10 @@ l1Fields:
|
||||
}
|
||||
}
|
||||
|
||||
if len(infos) > 0 {
|
||||
warnings = append(warnings, infos...)
|
||||
}
|
||||
|
||||
if len(warnings) > 0 {
|
||||
if len(rsp.Frames) == 0 {
|
||||
rsp.Frames = append(rsp.Frames, data.NewFrame("Warnings"))
|
||||
@ -105,7 +115,7 @@ l1Fields:
|
||||
return rsp
|
||||
}
|
||||
|
||||
func readWarnings(iter *sdkjsoniter.Iterator) ([]data.Notice, error) {
|
||||
func readAnnotations(iter *sdkjsoniter.Iterator, sevLevel data.NoticeSeverity) ([]data.Notice, error) {
|
||||
warnings := []data.Notice{}
|
||||
next, err := iter.WhatIsNext()
|
||||
if err != nil {
|
||||
@ -130,7 +140,7 @@ func readWarnings(iter *sdkjsoniter.Iterator) ([]data.Notice, error) {
|
||||
return nil, err
|
||||
}
|
||||
notice := data.Notice{
|
||||
Severity: data.NoticeSeverityWarning,
|
||||
Severity: sevLevel,
|
||||
Text: s,
|
||||
}
|
||||
warnings = append(warnings, notice)
|
||||
@ -140,6 +150,14 @@ func readWarnings(iter *sdkjsoniter.Iterator) ([]data.Notice, error) {
|
||||
return warnings, nil
|
||||
}
|
||||
|
||||
func readWarnings(iter *sdkjsoniter.Iterator) ([]data.Notice, error) {
|
||||
return readAnnotations(iter, data.NoticeSeverityWarning)
|
||||
}
|
||||
|
||||
func readInfos(iter *sdkjsoniter.Iterator) ([]data.Notice, error) {
|
||||
return readAnnotations(iter, data.NoticeSeverityInfo)
|
||||
}
|
||||
|
||||
func readPrometheusData(iter *sdkjsoniter.Iterator, opt Options) backend.DataResponse {
|
||||
var rsp backend.DataResponse
|
||||
t, err := iter.WhatIsNext()
|
||||
|
@ -7,6 +7,7 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/grafana/grafana-plugin-sdk-go/data"
|
||||
sdkjsoniter "github.com/grafana/grafana-plugin-sdk-go/data/utils/jsoniter"
|
||||
"github.com/grafana/grafana-plugin-sdk-go/experimental"
|
||||
jsoniter "github.com/json-iterator/go"
|
||||
@ -29,6 +30,8 @@ var files = []string{
|
||||
"prom-series",
|
||||
"prom-warnings",
|
||||
"prom-warnings-no-data",
|
||||
"prom-infos",
|
||||
"prom-infos-no-data",
|
||||
"prom-error",
|
||||
"prom-exemplars-a",
|
||||
"prom-exemplars-b",
|
||||
@ -62,8 +65,13 @@ func runScenario(name string, opts Options) func(t *testing.T) {
|
||||
if strings.Contains(name, "warnings") {
|
||||
hasWarning := false
|
||||
for _, frame := range rsp.Frames {
|
||||
if len(frame.Meta.Notices) > 0 {
|
||||
hasWarning = true
|
||||
for _, notice := range frame.Meta.Notices {
|
||||
if notice.Severity == data.NoticeSeverityWarning {
|
||||
hasWarning = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if hasWarning {
|
||||
break
|
||||
}
|
||||
}
|
||||
@ -71,6 +79,23 @@ func runScenario(name string, opts Options) func(t *testing.T) {
|
||||
require.True(t, hasWarning)
|
||||
}
|
||||
|
||||
if strings.Contains(name, "infos") {
|
||||
hasInfo := false
|
||||
for _, frame := range rsp.Frames {
|
||||
for _, notice := range frame.Meta.Notices {
|
||||
if notice.Severity == data.NoticeSeverityInfo {
|
||||
hasInfo = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if hasInfo {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
require.True(t, hasInfo)
|
||||
}
|
||||
|
||||
require.NoError(t, rsp.Error)
|
||||
|
||||
fname := name + "-frame"
|
||||
|
443
pkg/promlib/converter/testdata/prom-infos-frame.jsonc
vendored
Normal file
443
pkg/promlib/converter/testdata/prom-infos-frame.jsonc
vendored
Normal file
@ -0,0 +1,443 @@
|
||||
// 🌟 This was machine generated. Do not edit. 🌟
|
||||
//
|
||||
// Frame[0] {
|
||||
// "type": "timeseries-multi",
|
||||
// "typeVersion": [
|
||||
// 0,
|
||||
// 0
|
||||
// ],
|
||||
// "custom": {
|
||||
// "resultType": "vector"
|
||||
// },
|
||||
// "notices": [
|
||||
// {
|
||||
// "text": "info 1"
|
||||
// },
|
||||
// {
|
||||
// "text": "info 2"
|
||||
// }
|
||||
// ]
|
||||
// }
|
||||
// Name:
|
||||
// Dimensions: 2 Fields by 1 Rows
|
||||
// +-----------------------------------+--------------------------------------------------------------+
|
||||
// | Name: Time | Name: Value |
|
||||
// | Labels: | Labels: __name__=up, instance=localhost:9090, job=prometheus |
|
||||
// | Type: []time.Time | Type: []float64 |
|
||||
// +-----------------------------------+--------------------------------------------------------------+
|
||||
// | 2015-07-01 20:10:51.781 +0000 UTC | 1 |
|
||||
// +-----------------------------------+--------------------------------------------------------------+
|
||||
//
|
||||
//
|
||||
//
|
||||
// Frame[1] {
|
||||
// "type": "timeseries-multi",
|
||||
// "typeVersion": [
|
||||
// 0,
|
||||
// 0
|
||||
// ],
|
||||
// "custom": {
|
||||
// "resultType": "vector"
|
||||
// },
|
||||
// "notices": [
|
||||
// {
|
||||
// "text": "info 1"
|
||||
// },
|
||||
// {
|
||||
// "text": "info 2"
|
||||
// }
|
||||
// ]
|
||||
// }
|
||||
// Name:
|
||||
// Dimensions: 2 Fields by 1 Rows
|
||||
// +-----------------------------------+--------------------------------------------------------+
|
||||
// | Name: Time | Name: Value |
|
||||
// | Labels: | Labels: __name__=up, instance=localhost:9100, job=node |
|
||||
// | Type: []time.Time | Type: []float64 |
|
||||
// +-----------------------------------+--------------------------------------------------------+
|
||||
// | 2015-07-01 20:10:51.781 +0000 UTC | 0 |
|
||||
// +-----------------------------------+--------------------------------------------------------+
|
||||
//
|
||||
//
|
||||
//
|
||||
// Frame[2] {
|
||||
// "type": "timeseries-multi",
|
||||
// "typeVersion": [
|
||||
// 0,
|
||||
// 0
|
||||
// ],
|
||||
// "custom": {
|
||||
// "resultType": "vector"
|
||||
// },
|
||||
// "notices": [
|
||||
// {
|
||||
// "text": "info 1"
|
||||
// },
|
||||
// {
|
||||
// "text": "info 2"
|
||||
// }
|
||||
// ]
|
||||
// }
|
||||
// Name:
|
||||
// Dimensions: 2 Fields by 1 Rows
|
||||
// +-------------------------------+------------------------------------+
|
||||
// | Name: Time | Name: Value |
|
||||
// | Labels: | Labels: level=error, location=moon |
|
||||
// | Type: []time.Time | Type: []float64 |
|
||||
// +-------------------------------+------------------------------------+
|
||||
// | 2022-02-16 16:41:39 +0000 UTC | +Inf |
|
||||
// +-------------------------------+------------------------------------+
|
||||
//
|
||||
//
|
||||
//
|
||||
// Frame[3] {
|
||||
// "type": "timeseries-multi",
|
||||
// "typeVersion": [
|
||||
// 0,
|
||||
// 0
|
||||
// ],
|
||||
// "custom": {
|
||||
// "resultType": "vector"
|
||||
// },
|
||||
// "notices": [
|
||||
// {
|
||||
// "text": "info 1"
|
||||
// },
|
||||
// {
|
||||
// "text": "info 2"
|
||||
// }
|
||||
// ]
|
||||
// }
|
||||
// Name:
|
||||
// Dimensions: 2 Fields by 1 Rows
|
||||
// +-------------------------------+-----------------------------------+
|
||||
// | Name: Time | Name: Value |
|
||||
// | Labels: | Labels: level=info, location=moon |
|
||||
// | Type: []time.Time | Type: []float64 |
|
||||
// +-------------------------------+-----------------------------------+
|
||||
// | 2022-02-16 16:41:39 +0000 UTC | -Inf |
|
||||
// +-------------------------------+-----------------------------------+
|
||||
//
|
||||
//
|
||||
//
|
||||
// Frame[4] {
|
||||
// "type": "timeseries-multi",
|
||||
// "typeVersion": [
|
||||
// 0,
|
||||
// 0
|
||||
// ],
|
||||
// "custom": {
|
||||
// "resultType": "vector"
|
||||
// },
|
||||
// "notices": [
|
||||
// {
|
||||
// "text": "info 1"
|
||||
// },
|
||||
// {
|
||||
// "text": "info 2"
|
||||
// }
|
||||
// ]
|
||||
// }
|
||||
// Name:
|
||||
// Dimensions: 2 Fields by 1 Rows
|
||||
// +-------------------------------+------------------------------------+
|
||||
// | Name: Time | Name: Value |
|
||||
// | Labels: | Labels: level=debug, location=moon |
|
||||
// | Type: []time.Time | Type: []float64 |
|
||||
// +-------------------------------+------------------------------------+
|
||||
// | 2022-02-16 16:41:39 +0000 UTC | NaN |
|
||||
// +-------------------------------+------------------------------------+
|
||||
//
|
||||
//
|
||||
// 🌟 This was machine generated. Do not edit. 🌟
|
||||
{
|
||||
"status": 200,
|
||||
"frames": [
|
||||
{
|
||||
"schema": {
|
||||
"meta": {
|
||||
"type": "timeseries-multi",
|
||||
"typeVersion": [
|
||||
0,
|
||||
0
|
||||
],
|
||||
"custom": {
|
||||
"resultType": "vector"
|
||||
},
|
||||
"notices": [
|
||||
{
|
||||
"text": "info 1"
|
||||
},
|
||||
{
|
||||
"text": "info 2"
|
||||
}
|
||||
]
|
||||
},
|
||||
"fields": [
|
||||
{
|
||||
"name": "Time",
|
||||
"type": "time",
|
||||
"typeInfo": {
|
||||
"frame": "time.Time"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Value",
|
||||
"type": "number",
|
||||
"typeInfo": {
|
||||
"frame": "float64"
|
||||
},
|
||||
"labels": {
|
||||
"__name__": "up",
|
||||
"instance": "localhost:9090",
|
||||
"job": "prometheus"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"data": {
|
||||
"values": [
|
||||
[
|
||||
1435781451781
|
||||
],
|
||||
[
|
||||
1
|
||||
]
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"schema": {
|
||||
"meta": {
|
||||
"type": "timeseries-multi",
|
||||
"typeVersion": [
|
||||
0,
|
||||
0
|
||||
],
|
||||
"custom": {
|
||||
"resultType": "vector"
|
||||
},
|
||||
"notices": [
|
||||
{
|
||||
"text": "info 1"
|
||||
},
|
||||
{
|
||||
"text": "info 2"
|
||||
}
|
||||
]
|
||||
},
|
||||
"fields": [
|
||||
{
|
||||
"name": "Time",
|
||||
"type": "time",
|
||||
"typeInfo": {
|
||||
"frame": "time.Time"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Value",
|
||||
"type": "number",
|
||||
"typeInfo": {
|
||||
"frame": "float64"
|
||||
},
|
||||
"labels": {
|
||||
"__name__": "up",
|
||||
"instance": "localhost:9100",
|
||||
"job": "node"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"data": {
|
||||
"values": [
|
||||
[
|
||||
1435781451781
|
||||
],
|
||||
[
|
||||
0
|
||||
]
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"schema": {
|
||||
"meta": {
|
||||
"type": "timeseries-multi",
|
||||
"typeVersion": [
|
||||
0,
|
||||
0
|
||||
],
|
||||
"custom": {
|
||||
"resultType": "vector"
|
||||
},
|
||||
"notices": [
|
||||
{
|
||||
"text": "info 1"
|
||||
},
|
||||
{
|
||||
"text": "info 2"
|
||||
}
|
||||
]
|
||||
},
|
||||
"fields": [
|
||||
{
|
||||
"name": "Time",
|
||||
"type": "time",
|
||||
"typeInfo": {
|
||||
"frame": "time.Time"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Value",
|
||||
"type": "number",
|
||||
"typeInfo": {
|
||||
"frame": "float64"
|
||||
},
|
||||
"labels": {
|
||||
"level": "error",
|
||||
"location": "moon"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"data": {
|
||||
"values": [
|
||||
[
|
||||
1645029699000
|
||||
],
|
||||
[
|
||||
null
|
||||
]
|
||||
],
|
||||
"entities": [
|
||||
null,
|
||||
{
|
||||
"Inf": [
|
||||
0
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"schema": {
|
||||
"meta": {
|
||||
"type": "timeseries-multi",
|
||||
"typeVersion": [
|
||||
0,
|
||||
0
|
||||
],
|
||||
"custom": {
|
||||
"resultType": "vector"
|
||||
},
|
||||
"notices": [
|
||||
{
|
||||
"text": "info 1"
|
||||
},
|
||||
{
|
||||
"text": "info 2"
|
||||
}
|
||||
]
|
||||
},
|
||||
"fields": [
|
||||
{
|
||||
"name": "Time",
|
||||
"type": "time",
|
||||
"typeInfo": {
|
||||
"frame": "time.Time"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Value",
|
||||
"type": "number",
|
||||
"typeInfo": {
|
||||
"frame": "float64"
|
||||
},
|
||||
"labels": {
|
||||
"level": "info",
|
||||
"location": "moon"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"data": {
|
||||
"values": [
|
||||
[
|
||||
1645029699000
|
||||
],
|
||||
[
|
||||
null
|
||||
]
|
||||
],
|
||||
"entities": [
|
||||
null,
|
||||
{
|
||||
"NegInf": [
|
||||
0
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"schema": {
|
||||
"meta": {
|
||||
"type": "timeseries-multi",
|
||||
"typeVersion": [
|
||||
0,
|
||||
0
|
||||
],
|
||||
"custom": {
|
||||
"resultType": "vector"
|
||||
},
|
||||
"notices": [
|
||||
{
|
||||
"text": "info 1"
|
||||
},
|
||||
{
|
||||
"text": "info 2"
|
||||
}
|
||||
]
|
||||
},
|
||||
"fields": [
|
||||
{
|
||||
"name": "Time",
|
||||
"type": "time",
|
||||
"typeInfo": {
|
||||
"frame": "time.Time"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Value",
|
||||
"type": "number",
|
||||
"typeInfo": {
|
||||
"frame": "float64"
|
||||
},
|
||||
"labels": {
|
||||
"level": "debug",
|
||||
"location": "moon"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"data": {
|
||||
"values": [
|
||||
[
|
||||
1645029699000
|
||||
],
|
||||
[
|
||||
null
|
||||
]
|
||||
],
|
||||
"entities": [
|
||||
null,
|
||||
{
|
||||
"NaN": [
|
||||
0
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
51
pkg/promlib/converter/testdata/prom-infos-no-data-frame.jsonc
vendored
Normal file
51
pkg/promlib/converter/testdata/prom-infos-no-data-frame.jsonc
vendored
Normal file
@ -0,0 +1,51 @@
|
||||
// 🌟 This was machine generated. Do not edit. 🌟
|
||||
//
|
||||
// Frame[0] {
|
||||
// "typeVersion": [
|
||||
// 0,
|
||||
// 0
|
||||
// ],
|
||||
// "notices": [
|
||||
// {
|
||||
// "text": "info 1"
|
||||
// },
|
||||
// {
|
||||
// "text": "info 2"
|
||||
// }
|
||||
// ]
|
||||
// }
|
||||
// Name: Warnings
|
||||
// Dimensions: 0 Fields by 0 Rows
|
||||
// +
|
||||
// +
|
||||
//
|
||||
//
|
||||
// 🌟 This was machine generated. Do not edit. 🌟
|
||||
{
|
||||
"status": 200,
|
||||
"frames": [
|
||||
{
|
||||
"schema": {
|
||||
"name": "Warnings",
|
||||
"meta": {
|
||||
"typeVersion": [
|
||||
0,
|
||||
0
|
||||
],
|
||||
"notices": [
|
||||
{
|
||||
"text": "info 1"
|
||||
},
|
||||
{
|
||||
"text": "info 2"
|
||||
}
|
||||
]
|
||||
},
|
||||
"fields": []
|
||||
},
|
||||
"data": {
|
||||
"values": []
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
8
pkg/promlib/converter/testdata/prom-infos-no-data.json
vendored
Normal file
8
pkg/promlib/converter/testdata/prom-infos-no-data.json
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"status" : "success",
|
||||
"data" : {
|
||||
"resultType" : "vector",
|
||||
"result" : []
|
||||
},
|
||||
"infos" : ["info 1", "info 2"]
|
||||
}
|
37
pkg/promlib/converter/testdata/prom-infos.json
vendored
Normal file
37
pkg/promlib/converter/testdata/prom-infos.json
vendored
Normal file
@ -0,0 +1,37 @@
|
||||
{
|
||||
"status" : "success",
|
||||
"data" : {
|
||||
"resultType" : "vector",
|
||||
"result" : [
|
||||
{
|
||||
"metric" : {
|
||||
"__name__" : "up",
|
||||
"job" : "prometheus",
|
||||
"instance" : "localhost:9090"
|
||||
},
|
||||
"value": [ 1435781451.781, "1" ]
|
||||
},
|
||||
{
|
||||
"metric" : {
|
||||
"__name__" : "up",
|
||||
"job" : "node",
|
||||
"instance" : "localhost:9100"
|
||||
},
|
||||
"value" : [ 1435781451.781, "0" ]
|
||||
},
|
||||
{
|
||||
"metric": { "level": "error", "location": "moon"},
|
||||
"value": [1645029699, "+Inf"]
|
||||
},
|
||||
{
|
||||
"metric": { "level": "info", "location": "moon" },
|
||||
"value": [1645029699, "-Inf"]
|
||||
},
|
||||
{
|
||||
"metric": { "level": "debug", "location": "moon" },
|
||||
"value": [1645029699, "NaN"]
|
||||
}
|
||||
]
|
||||
},
|
||||
"infos" : ["info 1", "info 2"]
|
||||
}
|
@ -170,7 +170,7 @@ describe('filterPanelDataToQuery', () => {
|
||||
});
|
||||
|
||||
describe('frame results with warnings', () => {
|
||||
const meta = {
|
||||
const metaWarning = {
|
||||
notices: [
|
||||
{
|
||||
severity: 'warning',
|
||||
@ -178,25 +178,77 @@ describe('frame results with warnings', () => {
|
||||
},
|
||||
],
|
||||
};
|
||||
const metaInfo = {
|
||||
notices: [
|
||||
{
|
||||
text: 'For your info, something is up.',
|
||||
},
|
||||
],
|
||||
};
|
||||
const metaWarningAndInfo = {
|
||||
notices: [
|
||||
{
|
||||
severity: 'warning',
|
||||
text: 'Reduce operation is not needed. Input query or expression A is already reduced data.',
|
||||
},
|
||||
{
|
||||
text: 'For your info, something is up.',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const dataWithWarnings: PanelData = {
|
||||
const dataWithWarningsAndInfo: PanelData = {
|
||||
state: LoadingState.Done,
|
||||
series: [
|
||||
toDataFrame({
|
||||
refId: 'B',
|
||||
fields: [{ name: 'B1' }],
|
||||
meta,
|
||||
meta: metaWarningAndInfo,
|
||||
}),
|
||||
toDataFrame({
|
||||
refId: 'B',
|
||||
fields: [{ name: 'B2' }],
|
||||
meta,
|
||||
meta: metaWarningAndInfo,
|
||||
}),
|
||||
],
|
||||
timeRange: { from: dateTime(), to: dateTime(), raw: { from: 'now-1d', to: 'now' } },
|
||||
};
|
||||
|
||||
const dataWithoutWarnings: PanelData = {
|
||||
const dataWithWarningsOnly: PanelData = {
|
||||
state: LoadingState.Done,
|
||||
series: [
|
||||
toDataFrame({
|
||||
refId: 'B',
|
||||
fields: [{ name: 'B1' }],
|
||||
meta: metaWarning,
|
||||
}),
|
||||
toDataFrame({
|
||||
refId: 'B',
|
||||
fields: [{ name: 'B2' }],
|
||||
meta: metaWarning,
|
||||
}),
|
||||
],
|
||||
timeRange: { from: dateTime(), to: dateTime(), raw: { from: 'now-1d', to: 'now' } },
|
||||
};
|
||||
|
||||
const dataWithInfosOnly: PanelData = {
|
||||
state: LoadingState.Done,
|
||||
series: [
|
||||
toDataFrame({
|
||||
refId: 'B',
|
||||
fields: [{ name: 'B1' }],
|
||||
meta: metaInfo,
|
||||
}),
|
||||
toDataFrame({
|
||||
refId: 'B',
|
||||
fields: [{ name: 'B2' }],
|
||||
meta: metaInfo,
|
||||
}),
|
||||
],
|
||||
timeRange: { from: dateTime(), to: dateTime(), raw: { from: 'now-1d', to: 'now' } },
|
||||
};
|
||||
|
||||
const dataWithoutWarningsOrInfo: PanelData = {
|
||||
state: LoadingState.Done,
|
||||
series: [
|
||||
toDataFrame({
|
||||
@ -213,33 +265,79 @@ describe('frame results with warnings', () => {
|
||||
timeRange: { from: dateTime(), to: dateTime(), raw: { from: 'now-1d', to: 'now' } },
|
||||
};
|
||||
|
||||
it('should show a warning badge and de-duplicate warning messages', () => {
|
||||
it('should show both badges and de-duplicate messages', () => {
|
||||
// @ts-ignore: there are _way_ too many props to inject here :(
|
||||
const editorRow = new QueryEditorRow({
|
||||
data: dataWithWarnings,
|
||||
data: dataWithWarningsAndInfo,
|
||||
query: {
|
||||
refId: 'B',
|
||||
},
|
||||
});
|
||||
|
||||
const warningsComponent = editorRow.renderWarnings();
|
||||
const warningsComponent = editorRow.renderWarnings('warning');
|
||||
expect(warningsComponent).not.toBe(null);
|
||||
|
||||
const infosComponent = editorRow.renderWarnings('info');
|
||||
expect(infosComponent).not.toBe(null);
|
||||
|
||||
render(warningsComponent!);
|
||||
render(infosComponent!);
|
||||
expect(screen.getByText('1 warning')).toBeInTheDocument();
|
||||
expect(screen.getByText('1 info')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should show a warning badge and de-duplicate warning messages', () => {
|
||||
// @ts-ignore: there are _way_ too many props to inject here :(
|
||||
const editorRow = new QueryEditorRow({
|
||||
data: dataWithWarningsOnly,
|
||||
query: {
|
||||
refId: 'B',
|
||||
},
|
||||
});
|
||||
|
||||
const warningsComponent = editorRow.renderWarnings('warning');
|
||||
expect(warningsComponent).not.toBe(null);
|
||||
|
||||
const infosComponent = editorRow.renderWarnings('info');
|
||||
expect(infosComponent).toBe(null);
|
||||
|
||||
render(warningsComponent!);
|
||||
expect(screen.getByText('1 warning')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should not show a warning badge when there are no warnings', () => {
|
||||
it('should show an info badge and de-duplicate info messages', () => {
|
||||
// @ts-ignore: there are _way_ too many props to inject here :(
|
||||
const editorRow = new QueryEditorRow({
|
||||
data: dataWithoutWarnings,
|
||||
data: dataWithInfosOnly,
|
||||
query: {
|
||||
refId: 'B',
|
||||
},
|
||||
});
|
||||
|
||||
const warningsComponent = editorRow.renderWarnings();
|
||||
const warningsComponent = editorRow.renderWarnings('warning');
|
||||
expect(warningsComponent).toBe(null);
|
||||
|
||||
const infosComponent = editorRow.renderWarnings('info');
|
||||
expect(infosComponent).not.toBe(null);
|
||||
|
||||
render(infosComponent!);
|
||||
expect(screen.getByText('1 info')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should not show any badge when there are no warnings or info', () => {
|
||||
// @ts-ignore: there are _way_ too many props to inject here :(
|
||||
const editorRow = new QueryEditorRow({
|
||||
data: dataWithoutWarningsOrInfo,
|
||||
query: {
|
||||
refId: 'B',
|
||||
},
|
||||
});
|
||||
|
||||
const warningsComponent = editorRow.renderWarnings('warning');
|
||||
expect(warningsComponent).toBe(null);
|
||||
|
||||
const infosComponent = editorRow.renderWarnings('info');
|
||||
expect(infosComponent).toBe(null);
|
||||
});
|
||||
});
|
||||
describe('QueryEditorRow', () => {
|
||||
|
@ -389,7 +389,7 @@ export class QueryEditorRow<TQuery extends DataQuery> extends PureComponent<Prop
|
||||
return null;
|
||||
}
|
||||
|
||||
renderWarnings = (): JSX.Element | null => {
|
||||
renderWarnings = (type: string): JSX.Element | null => {
|
||||
const { data, query } = this.props;
|
||||
const dataFilteredByRefId = filterPanelDataToQuery(data, query.refId)?.series ?? [];
|
||||
|
||||
@ -398,7 +398,17 @@ export class QueryEditorRow<TQuery extends DataQuery> extends PureComponent<Prop
|
||||
return acc;
|
||||
}
|
||||
|
||||
const warnings = filter(serie.meta.notices, { severity: 'warning' }) ?? [];
|
||||
let criterion;
|
||||
if (type === 'warning') {
|
||||
criterion = (item: QueryResultMetaNotice) => item.severity === 'warning';
|
||||
} else {
|
||||
// The first condition is because sometimes info notices are not marked as info.
|
||||
// We don't filter on severity not being equal to warnings because there's still
|
||||
// the error severity, which does not seem to be used as errors are indicated
|
||||
// separately, but we do this just to be safe.
|
||||
criterion = (item: QueryResultMetaNotice) => !('severity' in item) || item.severity === 'info';
|
||||
}
|
||||
const warnings = filter(serie.meta.notices, criterion) ?? [];
|
||||
return acc.concat(warnings);
|
||||
}, []);
|
||||
|
||||
@ -409,16 +419,20 @@ export class QueryEditorRow<TQuery extends DataQuery> extends PureComponent<Prop
|
||||
return null;
|
||||
}
|
||||
|
||||
const key = 'query-' + type + 's';
|
||||
const colour = type === 'warning' ? 'orange' : 'blue';
|
||||
const iconName = type === 'warning' ? 'exclamation-triangle' : 'file-landscape-alt';
|
||||
|
||||
const serializedWarnings = uniqueWarnings.map((warning) => warning.text).join('\n');
|
||||
|
||||
return (
|
||||
<Badge
|
||||
key="query-warning"
|
||||
color="orange"
|
||||
icon="exclamation-triangle"
|
||||
key={key}
|
||||
color={colour}
|
||||
icon={iconName}
|
||||
text={
|
||||
<>
|
||||
{uniqueWarnings.length} {pluralize('warning', uniqueWarnings.length)}
|
||||
{uniqueWarnings.length} {pluralize(type, uniqueWarnings.length)}
|
||||
</>
|
||||
}
|
||||
tooltip={serializedWarnings}
|
||||
@ -450,7 +464,8 @@ export class QueryEditorRow<TQuery extends DataQuery> extends PureComponent<Prop
|
||||
)
|
||||
.filter(Boolean);
|
||||
|
||||
extraActions.push(this.renderWarnings());
|
||||
extraActions.push(this.renderWarnings('info'));
|
||||
extraActions.push(this.renderWarnings('warning'));
|
||||
|
||||
return extraActions;
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user