From 1a857552a18d737645528c3efe366bf3d747e2ff Mon Sep 17 00:00:00 2001 From: Drew Slobodnjak <60050885+drew08t@users.noreply.github.com> Date: Thu, 13 Jul 2023 19:28:58 -0700 Subject: [PATCH] Trend: Support disconnect values and connect nulls options (#70616) Co-authored-by: Leon Sorokin Co-authored-by: nmarrs --- .../panel-timeseries/timeseries-nulls.json | 1694 ++++++++++++----- .../src/components/GraphNG/GraphNG.tsx | 2 +- .../components/GraphNG/nullInsertThreshold.ts | 9 +- .../src/components/GraphNG/utils.ts | 30 +- .../plugins/panel/state-timeline/module.tsx | 7 +- .../panel/timeseries/InsertNullsEditor.tsx | 11 +- .../panel/timeseries/NullsThresholdInput.tsx | 22 +- .../panel/timeseries/SpanNullsEditor.tsx | 11 +- public/app/plugins/panel/timeseries/config.ts | 10 +- public/app/plugins/panel/trend/TrendPanel.tsx | 27 +- public/app/plugins/panel/trend/module.tsx | 2 +- 11 files changed, 1336 insertions(+), 489 deletions(-) diff --git a/devenv/dev-dashboards/panel-timeseries/timeseries-nulls.json b/devenv/dev-dashboards/panel-timeseries/timeseries-nulls.json index b3040deb06a..89499b0d2e2 100644 --- a/devenv/dev-dashboards/panel-timeseries/timeseries-nulls.json +++ b/devenv/dev-dashboards/panel-timeseries/timeseries-nulls.json @@ -61,6 +61,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 2, "pointSize": 7, @@ -82,7 +83,8 @@ "mode": "absolute", "steps": [ { - "color": "green" + "color": "green", + "value": null }, { "color": "red", @@ -172,6 +174,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 2, "pointSize": 6, @@ -194,7 +197,8 @@ "mode": "absolute", "steps": [ { - "color": "green" + "color": "green", + "value": null }, { "color": "red", @@ -292,6 +296,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 2, "pointSize": 6, @@ -314,7 +319,8 @@ "mode": "absolute", "steps": [ { - "color": "green" + "color": "green", + "value": null }, { "color": "red", @@ -431,6 +437,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 2, "pointSize": 7, @@ -452,7 +459,8 @@ "mode": "absolute", "steps": [ { - "color": "green" + "color": "green", + "value": null }, { "color": "red", @@ -542,6 +550,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 2, "pointSize": 6, @@ -564,7 +573,8 @@ "mode": "absolute", "steps": [ { - "color": "green" + "color": "green", + "value": null }, { "color": "red", @@ -662,6 +672,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 2, "pointSize": 6, @@ -684,7 +695,8 @@ "mode": "absolute", "steps": [ { - "color": "green" + "color": "green", + "value": null }, { "color": "red", @@ -801,6 +813,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 2, "pointSize": 5, @@ -822,7 +835,8 @@ "mode": "absolute", "steps": [ { - "color": "green" + "color": "green", + "value": null }, { "color": "red", @@ -926,8 +940,7 @@ }, { "datasource": { - "type": "testdata", - "uid": "PD8C576611E62080A" + "type": "testdata" }, "fieldConfig": { "defaults": { @@ -948,13 +961,14 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 8, + "lineWidth": 2, + "pointSize": 5, "scaleDistribution": { "type": "linear" }, - "showPoints": "always", + "showPoints": "auto", "spanNulls": false, "stacking": { "group": "A", @@ -969,7 +983,8 @@ "mode": "absolute", "steps": [ { - "color": "green" + "color": "green", + "value": null }, { "color": "red", @@ -977,21 +992,54 @@ } ] }, - "unit": "short" + "unit": "celsius" }, - "overrides": [] + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "A-series" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "C-series" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + } + ] }, "gridPos": { - "h": 6, + "h": 8, "w": 7, "x": 7, "y": 14 }, - "id": 32, + "id": 9, "options": { "legend": { + "asTable": false, "calcs": [], "displayMode": "list", + "isVisible": true, "placement": "bottom", "showLegend": true }, @@ -1000,20 +1048,42 @@ "sort": "none" } }, - "pluginVersion": "7.5.0-pre", + "pluginVersion": "7.2.0-pre", "targets": [ { "alias": "", - "csvContent": "time, val\n2023-06-14T08:16:41Z, 20\n2023-06-14T08:16:42Z, 22\n2023-06-14T08:16:43Z, 24\n2023-06-14T08:16:45Z, 10\n2023-06-14T08:16:46Z, 12\n2023-06-14T08:17:46Z, 13\n2023-06-14T08:17:47Z, 14\n2023-06-14T08:17:57Z, 20\n2023-06-14T08:17:58Z, null\n2023-06-14T08:18:00Z, 22\n2023-06-14T08:18:25Z, 22", - "datasource": { - "type": "testdata", - "uid": "PD8C576611E62080A" + "csvWave": { + "timeStep": 60, + "valuesCSV": "0,0,2,2,1,1" }, + "lines": 10, + "points": [], + "pulseWave": { + "offCount": 3, + "offValue": 1, + "onCount": 3, + "onValue": 2, + "timeStep": 60 + }, + "refId": "C", + "scenarioId": "csv_metric_values", + "stream": { + "bands": 1, + "noise": 2.2, + "speed": 250, + "spread": 3.5, + "type": "signal" + }, + "stringInput": "1,20,90,30,5,0" + }, + { "refId": "A", - "scenarioId": "csv_content" + "scenarioId": "csv_metric_values", + "stringInput": "10,25,null,null,50,10" } ], - "title": "Default (only null disconnect)", + "title": "Null values in second series show gaps (bugged)", + "transformations": [], "type": "timeseries" }, { @@ -1040,6 +1110,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineStyle": { "fill": "solid" @@ -1064,7 +1135,8 @@ "mode": "absolute", "steps": [ { - "color": "green" + "color": "green", + "value": null }, { "color": "red", @@ -1128,6 +1200,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineStyle": { "fill": "solid" @@ -1152,7 +1225,8 @@ "mode": "absolute", "steps": [ { - "color": "green" + "color": "green", + "value": null }, { "color": "red", @@ -1196,424 +1270,6 @@ "title": "Always show points between gaps", "type": "timeseries" }, - { - "datasource": { - "type": "datasource", - "uid": "-- Dashboard --" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 10, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 8, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "always", - "spanNulls": 10000, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "short" - }, - "overrides": [] - }, - "gridPos": { - "h": 6, - "w": 7, - "x": 7, - "y": 20 - }, - "id": 31, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom", - "showLegend": true - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "pluginVersion": "7.5.0-pre", - "targets": [ - { - "datasource": { - "type": "datasource", - "uid": "-- Dashboard --" - }, - "panelId": 32, - "refId": "A" - } - ], - "title": "Connect Nulls < 10s", - "type": "timeseries" - }, - { - "datasource": { - "type": "testdata" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 10, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 2, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "celsius" - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "A-series" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "C-series" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "green", - "mode": "fixed" - } - } - ] - } - ] - }, - "gridPos": { - "h": 8, - "w": 7, - "x": 0, - "y": 22 - }, - "id": 9, - "options": { - "legend": { - "asTable": false, - "calcs": [], - "displayMode": "list", - "isVisible": true, - "placement": "bottom", - "showLegend": true - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "pluginVersion": "7.2.0-pre", - "targets": [ - { - "alias": "", - "csvWave": { - "timeStep": 60, - "valuesCSV": "0,0,2,2,1,1" - }, - "lines": 10, - "points": [], - "pulseWave": { - "offCount": 3, - "offValue": 1, - "onCount": 3, - "onValue": 2, - "timeStep": 60 - }, - "refId": "C", - "scenarioId": "csv_metric_values", - "stream": { - "bands": 1, - "noise": 2.2, - "speed": 250, - "spread": 3.5, - "type": "signal" - }, - "stringInput": "1,20,90,30,5,0" - }, - { - "refId": "A", - "scenarioId": "csv_metric_values", - "stringInput": "10,25,null,null,50,10" - } - ], - "title": "Null values in second series show gaps (bugged)", - "transformations": [], - "type": "timeseries" - }, - { - "datasource": { - "type": "datasource", - "uid": "-- Dashboard --" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 10, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "insertNulls": 59000, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 8, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "always", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "short" - }, - "overrides": [] - }, - "gridPos": { - "h": 6, - "w": 7, - "x": 7, - "y": 26 - }, - "id": 30, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom", - "showLegend": true - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "pluginVersion": "7.5.0-pre", - "targets": [ - { - "datasource": { - "type": "datasource", - "uid": "-- Dashboard --" - }, - "panelId": 32, - "refId": "A" - } - ], - "title": "Disconnect Values > 59s", - "type": "timeseries" - }, - { - "datasource": { - "type": "datasource", - "uid": "-- Dashboard --" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 10, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "insertNulls": 59000, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 8, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "always", - "spanNulls": 10000, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "short" - }, - "overrides": [] - }, - "gridPos": { - "h": 6, - "w": 7, - "x": 7, - "y": 32 - }, - "id": 29, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom", - "showLegend": true - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "pluginVersion": "7.5.0-pre", - "targets": [ - { - "datasource": { - "type": "datasource", - "uid": "-- Dashboard --" - }, - "panelId": 32, - "refId": "A" - } - ], - "title": "Connect Nulls < 10s, Disconnect Values > 59s", - "type": "timeseries" - }, { "datasource": { "type": "testdata", @@ -1638,6 +1294,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, @@ -1659,7 +1316,8 @@ "mode": "absolute", "steps": [ { - "color": "green" + "color": "green", + "value": null }, { "color": "red", @@ -1674,7 +1332,7 @@ "h": 11, "w": 24, "x": 0, - "y": 38 + "y": 22 }, "id": 18, "maxDataPoints": 150, @@ -1728,6 +1386,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, @@ -1749,7 +1408,8 @@ "mode": "absolute", "steps": [ { - "color": "green" + "color": "green", + "value": null }, { "color": "red", @@ -1764,7 +1424,7 @@ "h": 10, "w": 12, "x": 0, - "y": 49 + "y": 33 }, "id": 20, "maxDataPoints": 150, @@ -1818,6 +1478,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, @@ -1839,7 +1500,8 @@ "mode": "absolute", "steps": [ { - "color": "green" + "color": "green", + "value": null }, { "color": "red", @@ -1854,7 +1516,7 @@ "h": 10, "w": 12, "x": 12, - "y": 49 + "y": 33 }, "id": 22, "maxDataPoints": 150, @@ -1908,6 +1570,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, @@ -1929,7 +1592,8 @@ "mode": "absolute", "steps": [ { - "color": "green" + "color": "green", + "value": null }, { "color": "red", @@ -1944,7 +1608,7 @@ "h": 10, "w": 8, "x": 0, - "y": 59 + "y": 43 }, "id": 24, "maxDataPoints": 150, @@ -1998,6 +1662,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, @@ -2019,7 +1684,8 @@ "mode": "absolute", "steps": [ { - "color": "green" + "color": "green", + "value": null }, { "color": "red", @@ -2034,7 +1700,7 @@ "h": 10, "w": 8, "x": 8, - "y": 59 + "y": 43 }, "id": 26, "maxDataPoints": 150, @@ -2088,6 +1754,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, @@ -2109,7 +1776,8 @@ "mode": "absolute", "steps": [ { - "color": "green" + "color": "green", + "value": null }, { "color": "red", @@ -2124,7 +1792,7 @@ "h": 10, "w": 8, "x": 16, - "y": 59 + "y": 43 }, "id": 28, "maxDataPoints": 150, @@ -2153,15 +1821,1121 @@ ], "title": "Higher density (mostly nulls, no leading/trailing)", "type": "timeseries" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 53 + }, + "id": 34, + "panels": [], + "title": "Connect nulls + disconnect values", + "type": "row" + }, + { + "datasource": { + "type": "testdata", + "uid": "PD8C576611E62080A" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 8, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "always", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 7, + "x": 0, + "y": 54 + }, + "id": 32, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "7.5.0-pre", + "targets": [ + { + "alias": "", + "csvContent": "time, val\n2023-06-14T08:16:41Z, 20\n2023-06-14T08:16:42Z, 22\n2023-06-14T08:16:43Z, 24\n2023-06-14T08:16:45Z, 10\n2023-06-14T08:16:46Z, 12\n2023-06-14T08:17:46Z, 13\n2023-06-14T08:17:47Z, 14\n2023-06-14T08:17:57Z, 20\n2023-06-14T08:17:58Z, null\n2023-06-14T08:18:00Z, 22\n2023-06-14T08:18:25Z, 22", + "datasource": { + "type": "testdata", + "uid": "PD8C576611E62080A" + }, + "refId": "A", + "scenarioId": "csv_content" + } + ], + "title": "Default (only null disconnect)", + "type": "timeseries" + }, + { + "datasource": { + "type": "testdata", + "uid": "PD8C576611E62080A" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 7, + "x": 7, + "y": 54 + }, + "id": 35, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "7.5.0-pre", + "targets": [ + { + "alias": "", + "csvContent": "x, val\n1, 20\n2, 22\n3, 24\n5, 10\n6, 12\n66, 13\n67, 14\n77, 20\n78, null\n80, 22\n105, 22", + "datasource": { + "type": "testdata", + "uid": "PD8C576611E62080A" + }, + "refId": "A", + "scenarioId": "csv_content" + } + ], + "title": "Default (only null disconnect)", + "type": "trend" + }, + { + "datasource": { + "type": "testdata", + "uid": "PD8C576611E62080A" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "fillOpacity": 70, + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineWidth": 0, + "spanNulls": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "#EAB839", + "value": 10 + }, + { + "color": "#6ED0E0", + "value": 20 + }, + { + "color": "#EF843C", + "value": 22 + }, + { + "color": "#E24D42", + "value": 24 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 10, + "x": 14, + "y": 54 + }, + "id": 39, + "options": { + "alignValue": "left", + "legend": { + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "mergeValues": true, + "rowHeight": 0.9, + "showValue": "auto", + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "7.5.0-pre", + "targets": [ + { + "alias": "", + "csvContent": "time, val\n2023-06-14T08:16:41Z, 20\n2023-06-14T08:16:42Z, 22\n2023-06-14T08:16:43Z, 24\n2023-06-14T08:16:45Z, 10\n2023-06-14T08:16:46Z, 12\n2023-06-14T08:17:46Z, 13\n2023-06-14T08:17:47Z, 14\n2023-06-14T08:17:57Z, 20\n2023-06-14T08:17:58Z, null\n2023-06-14T08:18:00Z, 22\n2023-06-14T08:18:25Z, 22", + "datasource": { + "type": "testdata", + "uid": "PD8C576611E62080A" + }, + "refId": "A", + "scenarioId": "csv_content" + } + ], + "title": "Default (only null disconnect)", + "type": "state-timeline" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Dashboard --" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 8, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "always", + "spanNulls": 10000, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 7, + "x": 0, + "y": 60 + }, + "id": 31, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "7.5.0-pre", + "targets": [ + { + "datasource": { + "type": "datasource", + "uid": "-- Dashboard --" + }, + "panelId": 32, + "refId": "A" + } + ], + "title": "Connect Nulls < 10s", + "type": "timeseries" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Dashboard --" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": 10, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 7, + "x": 7, + "y": 60 + }, + "id": 36, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "7.5.0-pre", + "targets": [ + { + "datasource": { + "type": "datasource", + "uid": "-- Dashboard --" + }, + "panelId": 35, + "refId": "A" + } + ], + "title": "Connect Nulls < 10", + "type": "trend" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Dashboard --" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "fillOpacity": 70, + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineWidth": 0, + "spanNulls": 10000 + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "#EAB839", + "value": 10 + }, + { + "color": "#6ED0E0", + "value": 20 + }, + { + "color": "#EF843C", + "value": 22 + }, + { + "color": "#E24D42", + "value": 24 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 10, + "x": 14, + "y": 60 + }, + "id": 40, + "options": { + "alignValue": "left", + "legend": { + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "mergeValues": true, + "rowHeight": 0.9, + "showValue": "auto", + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "7.5.0-pre", + "targets": [ + { + "datasource": { + "type": "datasource", + "uid": "-- Dashboard --" + }, + "panelId": 32, + "refId": "A" + } + ], + "title": "Connect Nulls < 10s", + "type": "state-timeline" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Dashboard --" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": 59000, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 8, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "always", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 7, + "x": 0, + "y": 66 + }, + "id": 30, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "7.5.0-pre", + "targets": [ + { + "datasource": { + "type": "datasource", + "uid": "-- Dashboard --" + }, + "panelId": 32, + "refId": "A" + } + ], + "title": "Disconnect Values > 59s", + "type": "timeseries" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Dashboard --" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": 59, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 7, + "x": 7, + "y": 66 + }, + "id": 37, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "7.5.0-pre", + "targets": [ + { + "datasource": { + "type": "datasource", + "uid": "-- Dashboard --" + }, + "panelId": 35, + "refId": "A" + } + ], + "title": "Disconnect Values > 59", + "type": "trend" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Dashboard --" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "fillOpacity": 70, + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": 59000, + "lineWidth": 0, + "spanNulls": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "#EAB839", + "value": 10 + }, + { + "color": "#6ED0E0", + "value": 20 + }, + { + "color": "#EF843C", + "value": 22 + }, + { + "color": "#E24D42", + "value": 24 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 10, + "x": 14, + "y": 66 + }, + "id": 41, + "options": { + "alignValue": "left", + "legend": { + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "mergeValues": true, + "rowHeight": 0.9, + "showValue": "auto", + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "7.5.0-pre", + "targets": [ + { + "datasource": { + "type": "datasource", + "uid": "-- Dashboard --" + }, + "panelId": 32, + "refId": "A" + } + ], + "title": "Disconnect Values > 59s", + "type": "state-timeline" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Dashboard --" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": 59000, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 8, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "always", + "spanNulls": 10000, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 7, + "x": 0, + "y": 72 + }, + "id": 29, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "7.5.0-pre", + "targets": [ + { + "datasource": { + "type": "datasource", + "uid": "-- Dashboard --" + }, + "panelId": 32, + "refId": "A" + } + ], + "title": "Connect Nulls < 10s, Disconnect Values > 59s", + "type": "timeseries" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Dashboard --" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": 59, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": 10, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 7, + "x": 7, + "y": 72 + }, + "id": 38, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "7.5.0-pre", + "targets": [ + { + "datasource": { + "type": "datasource", + "uid": "-- Dashboard --" + }, + "panelId": 35, + "refId": "A" + } + ], + "title": "Connect Nulls < 10, Disconnect Values > 59", + "type": "trend" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Dashboard --" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "fillOpacity": 70, + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": 59000, + "lineWidth": 0, + "spanNulls": 10000 + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "#EAB839", + "value": 10 + }, + { + "color": "#6ED0E0", + "value": 20 + }, + { + "color": "#EF843C", + "value": 22 + }, + { + "color": "#E24D42", + "value": 24 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 10, + "x": 14, + "y": 72 + }, + "id": 42, + "options": { + "alignValue": "left", + "legend": { + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "mergeValues": true, + "rowHeight": 0.9, + "showValue": "auto", + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "7.5.0-pre", + "targets": [ + { + "datasource": { + "type": "datasource", + "uid": "-- Dashboard --" + }, + "panelId": 32, + "refId": "A" + } + ], + "title": "Connect Nulls < 10s, Disconnect Values > 59s", + "type": "state-timeline" } ], - "refresh": false, + "refresh": "", "schemaVersion": 38, "style": "dark", "tags": [ "gdev", "panel-tests", - "graph-ng" + "graph-ng", + "timeseries", + "trend", + "state-timeline" ], "templating": { "list": [] @@ -2174,6 +2948,6 @@ "timezone": "", "title": "Panel Tests - Graph NG - Gaps and Connected", "uid": "8mmCAF1Mz", - "version": 10, + "version": 5, "weekStart": "" -} +} \ No newline at end of file diff --git a/packages/grafana-ui/src/components/GraphNG/GraphNG.tsx b/packages/grafana-ui/src/components/GraphNG/GraphNG.tsx index a9e3a22a265..131aa7670e3 100644 --- a/packages/grafana-ui/src/components/GraphNG/GraphNG.tsx +++ b/packages/grafana-ui/src/components/GraphNG/GraphNG.tsx @@ -54,7 +54,7 @@ export interface GraphNGProps extends Themeable2 { children?: (builder: UPlotConfigBuilder, alignedFrame: DataFrame) => React.ReactNode; prepConfig: (alignedFrame: DataFrame, allFrames: DataFrame[], getTimeRange: () => TimeRange) => UPlotConfigBuilder; propsToDiff?: Array; - preparePlotFrame?: (frames: DataFrame[], dimFields: XYFieldMatchers) => DataFrame; + preparePlotFrame?: (frames: DataFrame[], dimFields: XYFieldMatchers) => DataFrame | null; renderLegend: (config: UPlotConfigBuilder) => React.ReactElement | null; /** diff --git a/packages/grafana-ui/src/components/GraphNG/nullInsertThreshold.ts b/packages/grafana-ui/src/components/GraphNG/nullInsertThreshold.ts index 9d58f0cde29..352f2f0660b 100644 --- a/packages/grafana-ui/src/components/GraphNG/nullInsertThreshold.ts +++ b/packages/grafana-ui/src/components/GraphNG/nullInsertThreshold.ts @@ -1,4 +1,6 @@ -import { DataFrame, FieldType } from '@grafana/data'; +import { DataFrame } from '@grafana/data'; + +import { getRefField } from './utils'; type InsertMode = (prev: number, next: number, threshold: number) => number; @@ -29,10 +31,7 @@ export function applyNullInsertThreshold(opts: NullInsertOptions): DataFrame { insertMode = INSERT_MODES.threshold; } - const refField = frame.fields.find((field) => { - // note: getFieldDisplayName() would require full DF[] - return refFieldName != null ? field.name === refFieldName : field.type === FieldType.time; - }); + const refField = getRefField(frame, refFieldName); if (refField == null) { return frame; diff --git a/packages/grafana-ui/src/components/GraphNG/utils.ts b/packages/grafana-ui/src/components/GraphNG/utils.ts index 3f46c2d9dbe..cfdc8e36456 100644 --- a/packages/grafana-ui/src/components/GraphNG/utils.ts +++ b/packages/grafana-ui/src/components/GraphNG/utils.ts @@ -18,9 +18,17 @@ function isVisibleBarField(f: Field) { ); } +export function getRefField(frame: DataFrame, refFieldName?: string | null) { + return frame.fields.find((field) => { + // note: getFieldDisplayName() would require full DF[] + return refFieldName != null ? field.name === refFieldName : field.type === FieldType.time; + }); +} + // will mutate the DataFrame's fields' values -function applySpanNullsThresholds(frame: DataFrame) { - let refField = frame.fields.find((field) => field.type === FieldType.time); // this doesnt need to be time, just any numeric/asc join field +function applySpanNullsThresholds(frame: DataFrame, refFieldName?: string | null) { + const refField = getRefField(frame, refFieldName); + let refValues = refField?.values as any[]; for (let i = 0; i < frame.fields.length; i++) { @@ -43,12 +51,22 @@ function applySpanNullsThresholds(frame: DataFrame) { } export function preparePlotFrame(frames: DataFrame[], dimFields: XYFieldMatchers, timeRange?: TimeRange | null) { + let xField: Field; + loop: for (let frame of frames) { + for (let field of frame.fields) { + if (dimFields.x(field, frame, frames)) { + xField = field; + break loop; + } + } + } + // apply null insertions at interval frames = frames.map((frame) => { - if (!frame.fields[0].state?.nullThresholdApplied) { + if (!xField?.state?.nullThresholdApplied) { return applyNullInsertThreshold({ frame, - refFieldName: null, + refFieldName: xField.name, refFieldPseudoMin: timeRange?.from.valueOf(), refFieldPseudoMax: timeRange?.to.valueOf(), }); @@ -84,7 +102,7 @@ export function preparePlotFrame(frames: DataFrame[], dimFields: XYFieldMatchers return; } - const xVals = frame.fields[0].values; + const xVals = xField.values; for (let i = 0; i < xVals.length; i++) { if (i > 0) { @@ -102,7 +120,7 @@ export function preparePlotFrame(frames: DataFrame[], dimFields: XYFieldMatchers }); if (alignedFrame) { - alignedFrame = applySpanNullsThresholds(alignedFrame); + alignedFrame = applySpanNullsThresholds(alignedFrame, xField!.name); // append 2 null vals at minXDelta to bar series if (minXDelta !== Infinity) { diff --git a/public/app/plugins/panel/state-timeline/module.tsx b/public/app/plugins/panel/state-timeline/module.tsx index f2ed7a9bb91..8dfab7fcdce 100644 --- a/public/app/plugins/panel/state-timeline/module.tsx +++ b/public/app/plugins/panel/state-timeline/module.tsx @@ -10,6 +10,7 @@ import { commonOptionsBuilder } from '@grafana/ui'; import { InsertNullsEditor } from '../timeseries/InsertNullsEditor'; import { SpanNullsEditor } from '../timeseries/SpanNullsEditor'; +import { NullEditorSettings } from '../timeseries/config'; import { StateTimelinePanel } from './StateTimelinePanel'; import { timelinePanelChangedHandler } from './migrations'; @@ -51,7 +52,7 @@ export const plugin = new PanelPlugin(StateTimelinePanel) step: 1, }, }) - .addCustomEditor({ + .addCustomEditor({ id: 'spanNulls', path: 'spanNulls', name: 'Connect null values', @@ -60,8 +61,9 @@ export const plugin = new PanelPlugin(StateTimelinePanel) override: SpanNullsEditor, shouldApply: (field) => field.type !== FieldType.time, process: identityOverrideProcessor, + settings: { isTime: true }, }) - .addCustomEditor({ + .addCustomEditor({ id: 'insertNulls', path: 'insertNulls', name: 'Disconnect values', @@ -70,6 +72,7 @@ export const plugin = new PanelPlugin(StateTimelinePanel) override: InsertNullsEditor, shouldApply: (field) => field.type !== FieldType.time, process: identityOverrideProcessor, + settings: { isTime: true }, }); commonOptionsBuilder.addHideFrom(builder); diff --git a/public/app/plugins/panel/timeseries/InsertNullsEditor.tsx b/public/app/plugins/panel/timeseries/InsertNullsEditor.tsx index 45115628499..b516f069cd5 100644 --- a/public/app/plugins/panel/timeseries/InsertNullsEditor.tsx +++ b/public/app/plugins/panel/timeseries/InsertNullsEditor.tsx @@ -18,14 +18,21 @@ const DISCONNECT_OPTIONS: Array> = [ type Props = FieldOverrideEditorProps; -export const InsertNullsEditor = ({ value, onChange }: Props) => { +export const InsertNullsEditor = ({ value, onChange, item }: Props) => { const isThreshold = typeof value === 'number'; DISCONNECT_OPTIONS[1].value = isThreshold ? value : 3600000; // 1h return ( - {isThreshold && } + {isThreshold && ( + + )} ); }; diff --git a/public/app/plugins/panel/timeseries/NullsThresholdInput.tsx b/public/app/plugins/panel/timeseries/NullsThresholdInput.tsx index 39797b3c25e..8d9df298714 100644 --- a/public/app/plugins/panel/timeseries/NullsThresholdInput.tsx +++ b/public/app/plugins/panel/timeseries/NullsThresholdInput.tsx @@ -8,15 +8,27 @@ export enum InputPrefix { GreaterThan = 'greaterthan', } -type Props = { value: number; onChange: (value?: number | boolean | undefined) => void; inputPrefix?: InputPrefix }; +type Props = { + value: number; + onChange: (value?: number | boolean | undefined) => void; + inputPrefix?: InputPrefix; + isTime: boolean; +}; -export const NullsThresholdInput = ({ value, onChange, inputPrefix }: Props) => { - const formattedTime = rangeUtil.secondsToHms(value / 1000); +export const NullsThresholdInput = ({ value, onChange, inputPrefix, isTime }: Props) => { + let defaultValue = rangeUtil.secondsToHms(value / 1000); + if (!isTime) { + defaultValue = '10'; + } const checkAndUpdate = (txt: string) => { let val: boolean | number = false; if (txt) { try { - val = rangeUtil.intervalToMs(txt); + if (isTime && rangeUtil.isValidTimeSpan(txt)) { + val = rangeUtil.intervalToMs(txt); + } else { + val = Number(txt); + } } catch (err) { console.warn('ERROR', err); } @@ -47,7 +59,7 @@ export const NullsThresholdInput = ({ value, onChange, inputPrefix }: Props) => autoFocus={false} placeholder="never" width={10} - defaultValue={formattedTime} + defaultValue={defaultValue} onKeyDown={handleEnterKey} onBlur={handleBlur} prefix={prefix} diff --git a/public/app/plugins/panel/timeseries/SpanNullsEditor.tsx b/public/app/plugins/panel/timeseries/SpanNullsEditor.tsx index ee80c9e8c34..9912abf383b 100644 --- a/public/app/plugins/panel/timeseries/SpanNullsEditor.tsx +++ b/public/app/plugins/panel/timeseries/SpanNullsEditor.tsx @@ -22,14 +22,21 @@ const GAPS_OPTIONS: Array> = [ type Props = FieldOverrideEditorProps; -export const SpanNullsEditor = ({ value, onChange }: Props) => { +export const SpanNullsEditor = ({ value, onChange, item }: Props) => { const isThreshold = typeof value === 'number'; GAPS_OPTIONS[2].value = isThreshold ? value : 3600000; // 1h return ( - {isThreshold && } + {isThreshold && ( + + )} ); }; diff --git a/public/app/plugins/panel/timeseries/config.ts b/public/app/plugins/panel/timeseries/config.ts index 08e039d5b60..f863475a36b 100644 --- a/public/app/plugins/panel/timeseries/config.ts +++ b/public/app/plugins/panel/timeseries/config.ts @@ -42,7 +42,9 @@ export const defaultGraphConfig: GraphFieldConfig = { const categoryStyles = ['Graph styles']; -export function getGraphFieldConfig(cfg: GraphFieldConfig): SetFieldConfigOptionsArgs { +export type NullEditorSettings = { isTime: boolean }; + +export function getGraphFieldConfig(cfg: GraphFieldConfig, isTime = true): SetFieldConfigOptionsArgs { return { standardOptions: { [FieldConfigProperty.Color]: { @@ -143,7 +145,7 @@ export function getGraphFieldConfig(cfg: GraphFieldConfig): SetFieldConfigOption process: identityOverrideProcessor, shouldApply: (field) => field.type === FieldType.number, }) - .addCustomEditor({ + .addCustomEditor({ id: 'spanNulls', path: 'spanNulls', name: 'Connect null values', @@ -154,8 +156,9 @@ export function getGraphFieldConfig(cfg: GraphFieldConfig): SetFieldConfigOption showIf: (config) => config.drawStyle === GraphDrawStyle.Line, shouldApply: (field) => field.type !== FieldType.time, process: identityOverrideProcessor, + settings: { isTime }, }) - .addCustomEditor({ + .addCustomEditor({ id: 'insertNulls', path: 'insertNulls', name: 'Disconnect values', @@ -166,6 +169,7 @@ export function getGraphFieldConfig(cfg: GraphFieldConfig): SetFieldConfigOption showIf: (config) => config.drawStyle === GraphDrawStyle.Line, shouldApply: (field) => field.type !== FieldType.time, process: identityOverrideProcessor, + settings: { isTime }, }) .addRadio({ path: 'showPoints', diff --git a/public/app/plugins/panel/trend/TrendPanel.tsx b/public/app/plugins/panel/trend/TrendPanel.tsx index 3ae9c75b899..ccddf9b953b 100644 --- a/public/app/plugins/panel/trend/TrendPanel.tsx +++ b/public/app/plugins/panel/trend/TrendPanel.tsx @@ -1,9 +1,17 @@ import React, { useMemo } from 'react'; -import { FieldType, PanelProps } from '@grafana/data'; +import { DataFrame, FieldType, getFieldDisplayName, PanelProps, TimeRange } from '@grafana/data'; import { isLikelyAscendingVector } from '@grafana/data/src/transformations/transformers/joinDataFrames'; import { config, PanelDataErrorView } from '@grafana/runtime'; -import { KeyboardPlugin, TimeSeries, TooltipDisplayMode, TooltipPlugin, usePanelContext } from '@grafana/ui'; +import { + KeyboardPlugin, + preparePlotFrame, + TimeSeries, + TooltipDisplayMode, + TooltipPlugin, + usePanelContext, +} from '@grafana/ui'; +import { XYFieldMatchers } from '@grafana/ui/src/components/GraphNG/types'; import { findFieldIndex } from 'app/features/dimensions'; import { ContextMenuPlugin } from '../timeseries/plugins/ContextMenuPlugin'; @@ -23,6 +31,20 @@ export const TrendPanel = ({ id, }: PanelProps) => { const { sync } = usePanelContext(); + // Need to fallback to first number field if no xField is set in options otherwise panel crashes 😬 + const trendXFieldName = + options.xField ?? data.series[0].fields.find((field) => field.type === FieldType.number)?.name; + + const preparePlotFrameTimeless = (frames: DataFrame[], dimFields: XYFieldMatchers, timeRange?: TimeRange | null) => { + dimFields = { + ...dimFields, + x: (field, frame, frames) => { + return getFieldDisplayName(field, frame, frames) === trendXFieldName; + }, + }; + + return preparePlotFrame(frames, dimFields); + }; const info = useMemo(() => { if (data.series.length > 1) { @@ -90,6 +112,7 @@ export const TrendPanel = ({ height={height} legend={options.legend} options={options} + preparePlotFrame={preparePlotFrameTimeless} > {(config, alignedDataFrame) => { if (alignedDataFrame.fields.some((f) => Boolean(f.config.links?.length))) { diff --git a/public/app/plugins/panel/trend/module.tsx b/public/app/plugins/panel/trend/module.tsx index 422c263ee69..502840a9fe3 100644 --- a/public/app/plugins/panel/trend/module.tsx +++ b/public/app/plugins/panel/trend/module.tsx @@ -8,7 +8,7 @@ import { FieldConfig, Options } from './panelcfg.gen'; import { TrendSuggestionsSupplier } from './suggestions'; export const plugin = new PanelPlugin(TrendPanel) - .useFieldConfig(getGraphFieldConfig(defaultGraphConfig)) + .useFieldConfig(getGraphFieldConfig(defaultGraphConfig, false)) .setPanelOptions((builder) => { const category = ['X Axis']; builder.addFieldNamePicker({