mirror of https://github.com/grafana/grafana
Dashboard Migrations: V30 value mappings and tooltip options (#107970)
* Dashboard Migrations: V30 value mappings and tooltip optionspull/108088/head^2
parent
b839090de5
commit
1200b684c6
@ -0,0 +1,393 @@ |
|||||||
|
package schemaversion |
||||||
|
|
||||||
|
import ( |
||||||
|
"strconv" |
||||||
|
) |
||||||
|
|
||||||
|
// V30 upgrades value mappings and migrates tooltip options for panels.
|
||||||
|
//
|
||||||
|
// This migration addresses two key improvements to panel configurations:
|
||||||
|
// 1. Value mappings upgrade: Converts legacy value mapping format to the new structured format
|
||||||
|
// 2. Tooltip options migration: Renames tooltipOptions to tooltip in specific panel types: timeseries, xychart, xychart2
|
||||||
|
//
|
||||||
|
// The migration works by:
|
||||||
|
// 1. Iterating through all panels in the dashboard, including nested panels in collapsed rows
|
||||||
|
// 2. For each panel, upgrading value mappings in fieldConfig.defaults and fieldConfig.overrides
|
||||||
|
// 3. Migrating tooltip options for timeseries, xychart, and xychart2 panels
|
||||||
|
// 4. Preserving all other panel configurations and options
|
||||||
|
//
|
||||||
|
// Value Mappings Migration:
|
||||||
|
// - Converts legacy mapping types (1 = ValueToText, 2 = RangeToText) to new format
|
||||||
|
// - Handles special "null" values by converting them to SpecialValue mappings
|
||||||
|
// - Preserves threshold colors when available
|
||||||
|
// - Consolidates multiple value mappings into a single ValueToText mapping
|
||||||
|
// - Maintains range mappings as separate RangeToText mappings
|
||||||
|
//
|
||||||
|
// Tooltip Options Migration:
|
||||||
|
// - Renames panel.options.tooltipOptions to panel.options.tooltip
|
||||||
|
// - Only applies to timeseries, xychart, and xychart2 panel types
|
||||||
|
// - Preserves all tooltip configuration options
|
||||||
|
//
|
||||||
|
// Example value mappings transformation:
|
||||||
|
//
|
||||||
|
// Before migration:
|
||||||
|
//
|
||||||
|
// panel: {
|
||||||
|
// "fieldConfig": {
|
||||||
|
// "defaults": {
|
||||||
|
// "mappings": [
|
||||||
|
// { "id": 0, "text": "Up", "type": 1, "value": "1" },
|
||||||
|
// { "id": 1, "text": "Down", "type": 1, "value": "0" },
|
||||||
|
// { "from": "10", "to": "20", "text": "Medium", "type": 2 }
|
||||||
|
// ]
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// After migration:
|
||||||
|
//
|
||||||
|
// panel: {
|
||||||
|
// "fieldConfig": {
|
||||||
|
// "defaults": {
|
||||||
|
// "mappings": [
|
||||||
|
// {
|
||||||
|
// "type": "value",
|
||||||
|
// "options": {
|
||||||
|
// "1": { "text": "Up" },
|
||||||
|
// "0": { "text": "Down" }
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// "type": "range",
|
||||||
|
// "options": {
|
||||||
|
// "from": 10,
|
||||||
|
// "to": 20,
|
||||||
|
// "result": { "text": "Medium" }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// ]
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// Example tooltip options transformation:
|
||||||
|
//
|
||||||
|
// Before migration:
|
||||||
|
//
|
||||||
|
// panel: {
|
||||||
|
// "type": "timeseries",
|
||||||
|
// "options": {
|
||||||
|
// "tooltipOptions": { "mode": "multi" }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// After migration:
|
||||||
|
//
|
||||||
|
// panel: {
|
||||||
|
// "type": "timeseries",
|
||||||
|
// "options": {
|
||||||
|
// "tooltip": { "mode": "multi" }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
func V30(dashboard map[string]interface{}) error { |
||||||
|
dashboard["schemaVersion"] = 30 |
||||||
|
|
||||||
|
panels, ok := dashboard["panels"].([]interface{}) |
||||||
|
if !ok { |
||||||
|
return nil |
||||||
|
} |
||||||
|
|
||||||
|
for _, panel := range panels { |
||||||
|
panelMap, ok := panel.(map[string]interface{}) |
||||||
|
if !ok { |
||||||
|
continue |
||||||
|
} |
||||||
|
|
||||||
|
upgradeValueMappingsForPanel(panelMap) |
||||||
|
migrateTooltipOptions(panelMap) |
||||||
|
|
||||||
|
// Handle nested panels in collapsed rows
|
||||||
|
nestedPanels, hasNested := panelMap["panels"].([]interface{}) |
||||||
|
if !hasNested { |
||||||
|
continue |
||||||
|
} |
||||||
|
|
||||||
|
for _, nestedPanel := range nestedPanels { |
||||||
|
nestedPanelMap, ok := nestedPanel.(map[string]interface{}) |
||||||
|
if !ok { |
||||||
|
continue |
||||||
|
} |
||||||
|
upgradeValueMappingsForPanel(nestedPanelMap) |
||||||
|
migrateTooltipOptions(nestedPanelMap) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return nil |
||||||
|
} |
||||||
|
|
||||||
|
// upgradeValueMappingsForPanel migrates value mappings from old format to new format
|
||||||
|
func upgradeValueMappingsForPanel(panel map[string]interface{}) { |
||||||
|
fieldConfig, ok := panel["fieldConfig"].(map[string]interface{}) |
||||||
|
if !ok { |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
// Upgrade defaults mappings
|
||||||
|
if defaults, ok := fieldConfig["defaults"].(map[string]interface{}); ok { |
||||||
|
if mappings, ok := defaults["mappings"].([]interface{}); ok { |
||||||
|
var thresholds map[string]interface{} |
||||||
|
if t, ok := defaults["thresholds"].(map[string]interface{}); ok { |
||||||
|
thresholds = t |
||||||
|
} |
||||||
|
defaults["mappings"] = upgradeValueMappings(mappings, thresholds) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Upgrade overrides mappings
|
||||||
|
overrides, hasOverrides := fieldConfig["overrides"].([]interface{}) |
||||||
|
if !hasOverrides { |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
for _, override := range overrides { |
||||||
|
overrideMap, ok := override.(map[string]interface{}) |
||||||
|
if !ok { |
||||||
|
continue |
||||||
|
} |
||||||
|
|
||||||
|
properties, hasProperties := overrideMap["properties"].([]interface{}) |
||||||
|
if !hasProperties { |
||||||
|
continue |
||||||
|
} |
||||||
|
|
||||||
|
for _, property := range properties { |
||||||
|
propertyMap, ok := property.(map[string]interface{}) |
||||||
|
if !ok { |
||||||
|
continue |
||||||
|
} |
||||||
|
|
||||||
|
if propertyMap["id"] != "mappings" { |
||||||
|
continue |
||||||
|
} |
||||||
|
|
||||||
|
mappings, ok := propertyMap["value"].([]interface{}) |
||||||
|
if !ok { |
||||||
|
continue |
||||||
|
} |
||||||
|
|
||||||
|
propertyMap["value"] = upgradeValueMappings(mappings, nil) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// upgradeValueMappings converts legacy value mappings to new format
|
||||||
|
func upgradeValueMappings(oldMappings []interface{}, thresholds map[string]interface{}) []interface{} { |
||||||
|
if len(oldMappings) == 0 { |
||||||
|
return oldMappings |
||||||
|
} |
||||||
|
|
||||||
|
valueMaps := map[string]interface{}{ |
||||||
|
"type": "value", |
||||||
|
"options": map[string]interface{}{}, |
||||||
|
} |
||||||
|
|
||||||
|
var newMappings []interface{} |
||||||
|
hasValueMappings := false |
||||||
|
|
||||||
|
for _, mapping := range oldMappings { |
||||||
|
if mappingMap, ok := mapping.(map[string]interface{}); ok { |
||||||
|
// Check if this is already the new format
|
||||||
|
if mappingType, ok := mappingMap["type"].(string); ok && mappingType != "" { |
||||||
|
if mappingType == "value" { |
||||||
|
// Consolidate existing value mappings
|
||||||
|
if options, ok := mappingMap["options"].(map[string]interface{}); ok { |
||||||
|
valueMapsOptions := valueMaps["options"].(map[string]interface{}) |
||||||
|
for k, v := range options { |
||||||
|
valueMapsOptions[k] = v |
||||||
|
} |
||||||
|
hasValueMappings = true |
||||||
|
} |
||||||
|
} else { |
||||||
|
newMappings = append(newMappings, mappingMap) |
||||||
|
} |
||||||
|
continue |
||||||
|
} |
||||||
|
|
||||||
|
// Handle legacy format
|
||||||
|
var color interface{} |
||||||
|
if thresholds != nil { |
||||||
|
// Try to get color from threshold based on the mapping value
|
||||||
|
if value, ok := mappingMap["value"]; ok { |
||||||
|
if valueStr, ok := value.(string); ok { |
||||||
|
if numeric, err := strconv.ParseFloat(valueStr, 64); err == nil { |
||||||
|
color = getActiveThresholdColor(numeric, thresholds) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
// For range mappings, use the 'from' value to determine color
|
||||||
|
if fromVal, ok := mappingMap["from"]; ok { |
||||||
|
if fromStr, ok := fromVal.(string); ok { |
||||||
|
if numeric, err := strconv.ParseFloat(fromStr, 64); err == nil { |
||||||
|
color = getActiveThresholdColor(numeric, thresholds) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Convert legacy type numbers to new format
|
||||||
|
if mappingType, ok := mappingMap["type"].(float64); ok { |
||||||
|
switch int(mappingType) { |
||||||
|
case 1: // ValueToText
|
||||||
|
if value, ok := mappingMap["value"]; ok { |
||||||
|
if valueStr, ok := value.(string); ok && valueStr == "null" { |
||||||
|
// Handle null values as special value mapping
|
||||||
|
// For null values, use the base threshold color (lowest step)
|
||||||
|
if thresholds != nil { |
||||||
|
color = getBaseThresholdColor(thresholds) |
||||||
|
} |
||||||
|
newMappings = append(newMappings, map[string]interface{}{ |
||||||
|
"type": "special", |
||||||
|
"options": map[string]interface{}{ |
||||||
|
"match": "null", |
||||||
|
"result": map[string]interface{}{ |
||||||
|
"text": mappingMap["text"], |
||||||
|
"color": color, |
||||||
|
}, |
||||||
|
}, |
||||||
|
}) |
||||||
|
} else { |
||||||
|
// Regular value mapping
|
||||||
|
valueMapsOptions := valueMaps["options"].(map[string]interface{}) |
||||||
|
result := map[string]interface{}{ |
||||||
|
"text": mappingMap["text"], |
||||||
|
} |
||||||
|
if color != nil { |
||||||
|
result["color"] = color |
||||||
|
} |
||||||
|
valueMapsOptions[stringifyValue(value)] = result |
||||||
|
hasValueMappings = true |
||||||
|
} |
||||||
|
} |
||||||
|
case 2: // RangeToText
|
||||||
|
result := map[string]interface{}{ |
||||||
|
"text": mappingMap["text"], |
||||||
|
} |
||||||
|
if color != nil { |
||||||
|
result["color"] = color |
||||||
|
} |
||||||
|
|
||||||
|
from, _ := strconv.ParseFloat(stringifyValue(mappingMap["from"]), 64) |
||||||
|
to, _ := strconv.ParseFloat(stringifyValue(mappingMap["to"]), 64) |
||||||
|
|
||||||
|
newMappings = append(newMappings, map[string]interface{}{ |
||||||
|
"type": "range", |
||||||
|
"options": map[string]interface{}{ |
||||||
|
"from": from, |
||||||
|
"to": to, |
||||||
|
"result": result, |
||||||
|
}, |
||||||
|
}) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Add consolidated value mappings at the beginning if any exist
|
||||||
|
if hasValueMappings { |
||||||
|
newMappings = append([]interface{}{valueMaps}, newMappings...) |
||||||
|
} |
||||||
|
|
||||||
|
return newMappings |
||||||
|
} |
||||||
|
|
||||||
|
// getActiveThresholdColor returns the color for a value based on thresholds
|
||||||
|
func getActiveThresholdColor(value float64, thresholds map[string]interface{}) interface{} { |
||||||
|
if steps, ok := thresholds["steps"].([]interface{}); ok { |
||||||
|
var activeStep map[string]interface{} |
||||||
|
|
||||||
|
for _, step := range steps { |
||||||
|
if stepMap, ok := step.(map[string]interface{}); ok { |
||||||
|
if stepValue, ok := stepMap["value"]; ok { |
||||||
|
if stepValue == nil { |
||||||
|
// Null value represents negative infinity - this is always the base color
|
||||||
|
activeStep = stepMap |
||||||
|
continue |
||||||
|
} |
||||||
|
|
||||||
|
if stepNum, ok := stepValue.(float64); ok { |
||||||
|
if value >= stepNum { |
||||||
|
activeStep = stepMap |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if activeStep != nil { |
||||||
|
return activeStep["color"] |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return nil |
||||||
|
} |
||||||
|
|
||||||
|
// getBaseThresholdColor returns the base threshold color (first step with null value)
|
||||||
|
func getBaseThresholdColor(thresholds map[string]interface{}) interface{} { |
||||||
|
if steps, ok := thresholds["steps"].([]interface{}); ok { |
||||||
|
for _, step := range steps { |
||||||
|
if stepMap, ok := step.(map[string]interface{}); ok { |
||||||
|
if stepValue, ok := stepMap["value"]; ok { |
||||||
|
if stepValue == nil { |
||||||
|
// This is the base color (null value step)
|
||||||
|
return stepMap["color"] |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return nil |
||||||
|
} |
||||||
|
|
||||||
|
// migrateTooltipOptions renames tooltipOptions to tooltip for specific panel types
|
||||||
|
func migrateTooltipOptions(panel map[string]interface{}) { |
||||||
|
panelType, ok := panel["type"].(string) |
||||||
|
if !ok { |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
// Only migrate for specific panel types
|
||||||
|
if panelType != "timeseries" && panelType != "xychart" && panelType != "xychart2" { |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
options, ok := panel["options"].(map[string]interface{}) |
||||||
|
if !ok { |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
tooltipOptions, ok := options["tooltipOptions"] |
||||||
|
if !ok { |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
// Rename tooltipOptions to tooltip
|
||||||
|
options["tooltip"] = tooltipOptions |
||||||
|
delete(options, "tooltipOptions") |
||||||
|
} |
||||||
|
|
||||||
|
// stringifyValue converts a value to string
|
||||||
|
func stringifyValue(value interface{}) string { |
||||||
|
switch v := value.(type) { |
||||||
|
case string: |
||||||
|
return v |
||||||
|
case float64: |
||||||
|
return strconv.FormatFloat(v, 'f', -1, 64) |
||||||
|
case int: |
||||||
|
return strconv.Itoa(v) |
||||||
|
case bool: |
||||||
|
return strconv.FormatBool(v) |
||||||
|
default: |
||||||
|
return "" |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,499 @@ |
|||||||
|
package schemaversion_test |
||||||
|
|
||||||
|
import ( |
||||||
|
"testing" |
||||||
|
|
||||||
|
"github.com/grafana/grafana/apps/dashboard/pkg/migration/schemaversion" |
||||||
|
) |
||||||
|
|
||||||
|
func TestV30(t *testing.T) { |
||||||
|
tests := []migrationTestCase{ |
||||||
|
{ |
||||||
|
name: "panel with legacy value mappings gets upgraded to new format", |
||||||
|
input: map[string]interface{}{ |
||||||
|
"title": "V30 Value Mappings Migration Test Dashboard", |
||||||
|
"schemaVersion": 29, |
||||||
|
"panels": []interface{}{ |
||||||
|
map[string]interface{}{ |
||||||
|
"type": "timeseries", |
||||||
|
"title": "Panel with legacy value mappings", |
||||||
|
"id": 1, |
||||||
|
"fieldConfig": map[string]interface{}{ |
||||||
|
"defaults": map[string]interface{}{ |
||||||
|
"thresholds": map[string]interface{}{ |
||||||
|
"mode": "absolute", |
||||||
|
"steps": []interface{}{ |
||||||
|
map[string]interface{}{ |
||||||
|
"color": "green", |
||||||
|
"value": nil, |
||||||
|
}, |
||||||
|
map[string]interface{}{ |
||||||
|
"color": "red", |
||||||
|
"value": float64(80), |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
"mappings": []interface{}{ |
||||||
|
map[string]interface{}{ |
||||||
|
"id": 0, |
||||||
|
"text": "Up", |
||||||
|
"type": float64(1), |
||||||
|
"value": "1", |
||||||
|
}, |
||||||
|
map[string]interface{}{ |
||||||
|
"id": 1, |
||||||
|
"text": "Down", |
||||||
|
"type": float64(1), |
||||||
|
"value": "0", |
||||||
|
}, |
||||||
|
map[string]interface{}{ |
||||||
|
"from": "10", |
||||||
|
"to": "20", |
||||||
|
"text": "Medium", |
||||||
|
"type": float64(2), |
||||||
|
}, |
||||||
|
map[string]interface{}{ |
||||||
|
"type": float64(1), |
||||||
|
"value": "null", |
||||||
|
"text": "Null Value", |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
"overrides": []interface{}{ |
||||||
|
map[string]interface{}{ |
||||||
|
"matcher": map[string]interface{}{ |
||||||
|
"id": "byName", |
||||||
|
"options": "test-field", |
||||||
|
}, |
||||||
|
"properties": []interface{}{ |
||||||
|
map[string]interface{}{ |
||||||
|
"id": "mappings", |
||||||
|
"value": []interface{}{ |
||||||
|
map[string]interface{}{ |
||||||
|
"id": 0, |
||||||
|
"text": "Override Up", |
||||||
|
"type": float64(1), |
||||||
|
"value": "1", |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
expected: map[string]interface{}{ |
||||||
|
"title": "V30 Value Mappings Migration Test Dashboard", |
||||||
|
"schemaVersion": 30, |
||||||
|
"panels": []interface{}{ |
||||||
|
map[string]interface{}{ |
||||||
|
"type": "timeseries", |
||||||
|
"title": "Panel with legacy value mappings", |
||||||
|
"id": 1, |
||||||
|
"fieldConfig": map[string]interface{}{ |
||||||
|
"defaults": map[string]interface{}{ |
||||||
|
"thresholds": map[string]interface{}{ |
||||||
|
"mode": "absolute", |
||||||
|
"steps": []interface{}{ |
||||||
|
map[string]interface{}{ |
||||||
|
"color": "green", |
||||||
|
"value": nil, |
||||||
|
}, |
||||||
|
map[string]interface{}{ |
||||||
|
"color": "red", |
||||||
|
"value": float64(80), |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
"mappings": []interface{}{ |
||||||
|
map[string]interface{}{ |
||||||
|
"type": "value", |
||||||
|
"options": map[string]interface{}{ |
||||||
|
"1": map[string]interface{}{ |
||||||
|
"text": "Up", |
||||||
|
"color": "green", |
||||||
|
}, |
||||||
|
"0": map[string]interface{}{ |
||||||
|
"text": "Down", |
||||||
|
"color": "green", |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
map[string]interface{}{ |
||||||
|
"type": "range", |
||||||
|
"options": map[string]interface{}{ |
||||||
|
"from": float64(10), |
||||||
|
"to": float64(20), |
||||||
|
"result": map[string]interface{}{ |
||||||
|
"text": "Medium", |
||||||
|
"color": "green", |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
map[string]interface{}{ |
||||||
|
"type": "special", |
||||||
|
"options": map[string]interface{}{ |
||||||
|
"match": "null", |
||||||
|
"result": map[string]interface{}{ |
||||||
|
"text": "Null Value", |
||||||
|
"color": "green", |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
"overrides": []interface{}{ |
||||||
|
map[string]interface{}{ |
||||||
|
"matcher": map[string]interface{}{ |
||||||
|
"id": "byName", |
||||||
|
"options": "test-field", |
||||||
|
}, |
||||||
|
"properties": []interface{}{ |
||||||
|
map[string]interface{}{ |
||||||
|
"id": "mappings", |
||||||
|
"value": []interface{}{ |
||||||
|
map[string]interface{}{ |
||||||
|
"type": "value", |
||||||
|
"options": map[string]interface{}{ |
||||||
|
"1": map[string]interface{}{ |
||||||
|
"text": "Override Up", |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
{ |
||||||
|
name: "panel with tooltip options gets migrated to tooltip", |
||||||
|
input: map[string]interface{}{ |
||||||
|
"title": "V30 Tooltip Options Migration Test Dashboard", |
||||||
|
"schemaVersion": 29, |
||||||
|
"panels": []interface{}{ |
||||||
|
map[string]interface{}{ |
||||||
|
"type": "timeseries", |
||||||
|
"title": "Panel with tooltipOptions", |
||||||
|
"id": 1, |
||||||
|
"options": map[string]interface{}{ |
||||||
|
"tooltipOptions": map[string]interface{}{ |
||||||
|
"mode": "multi", |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
map[string]interface{}{ |
||||||
|
"type": "xychart", |
||||||
|
"title": "XY Chart with tooltipOptions", |
||||||
|
"id": 2, |
||||||
|
"options": map[string]interface{}{ |
||||||
|
"tooltipOptions": map[string]interface{}{ |
||||||
|
"mode": "single", |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
map[string]interface{}{ |
||||||
|
"type": "xychart2", |
||||||
|
"title": "XY Chart2 with tooltipOptions", |
||||||
|
"id": 3, |
||||||
|
"options": map[string]interface{}{ |
||||||
|
"tooltipOptions": map[string]interface{}{ |
||||||
|
"mode": "single", |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
expected: map[string]interface{}{ |
||||||
|
"title": "V30 Tooltip Options Migration Test Dashboard", |
||||||
|
"schemaVersion": 30, |
||||||
|
"panels": []interface{}{ |
||||||
|
map[string]interface{}{ |
||||||
|
"type": "timeseries", |
||||||
|
"title": "Panel with tooltipOptions", |
||||||
|
"id": 1, |
||||||
|
"options": map[string]interface{}{ |
||||||
|
"tooltip": map[string]interface{}{ |
||||||
|
"mode": "multi", |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
map[string]interface{}{ |
||||||
|
"type": "xychart", |
||||||
|
"title": "XY Chart with tooltipOptions", |
||||||
|
"id": 2, |
||||||
|
"options": map[string]interface{}{ |
||||||
|
"tooltip": map[string]interface{}{ |
||||||
|
"mode": "single", |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
map[string]interface{}{ |
||||||
|
"type": "xychart2", |
||||||
|
"title": "XY Chart2 with tooltipOptions", |
||||||
|
"id": 3, |
||||||
|
"options": map[string]interface{}{ |
||||||
|
"tooltip": map[string]interface{}{ |
||||||
|
"mode": "single", |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
{ |
||||||
|
name: "panel with nested panels in collapsed row gets migrated", |
||||||
|
input: map[string]interface{}{ |
||||||
|
"title": "V30 Nested Panels Migration Test Dashboard", |
||||||
|
"schemaVersion": 29, |
||||||
|
"panels": []interface{}{ |
||||||
|
map[string]interface{}{ |
||||||
|
"type": "row", |
||||||
|
"title": "Collapsed Row", |
||||||
|
"id": 1, |
||||||
|
"collapsed": true, |
||||||
|
"panels": []interface{}{ |
||||||
|
map[string]interface{}{ |
||||||
|
"type": "timeseries", |
||||||
|
"title": "Nested panel with tooltipOptions", |
||||||
|
"id": 2, |
||||||
|
"options": map[string]interface{}{ |
||||||
|
"tooltipOptions": map[string]interface{}{ |
||||||
|
"mode": "multi", |
||||||
|
}, |
||||||
|
}, |
||||||
|
"fieldConfig": map[string]interface{}{ |
||||||
|
"defaults": map[string]interface{}{ |
||||||
|
"mappings": []interface{}{ |
||||||
|
map[string]interface{}{ |
||||||
|
"id": 0, |
||||||
|
"text": "On", |
||||||
|
"type": float64(1), |
||||||
|
"value": "1", |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
expected: map[string]interface{}{ |
||||||
|
"title": "V30 Nested Panels Migration Test Dashboard", |
||||||
|
"schemaVersion": 30, |
||||||
|
"panels": []interface{}{ |
||||||
|
map[string]interface{}{ |
||||||
|
"type": "row", |
||||||
|
"title": "Collapsed Row", |
||||||
|
"id": 1, |
||||||
|
"collapsed": true, |
||||||
|
"panels": []interface{}{ |
||||||
|
map[string]interface{}{ |
||||||
|
"type": "timeseries", |
||||||
|
"title": "Nested panel with tooltipOptions", |
||||||
|
"id": 2, |
||||||
|
"options": map[string]interface{}{ |
||||||
|
"tooltip": map[string]interface{}{ |
||||||
|
"mode": "multi", |
||||||
|
}, |
||||||
|
}, |
||||||
|
"fieldConfig": map[string]interface{}{ |
||||||
|
"defaults": map[string]interface{}{ |
||||||
|
"mappings": []interface{}{ |
||||||
|
map[string]interface{}{ |
||||||
|
"type": "value", |
||||||
|
"options": map[string]interface{}{ |
||||||
|
"1": map[string]interface{}{ |
||||||
|
"text": "On", |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
{ |
||||||
|
name: "panel with no mappings or tooltip options remains unchanged", |
||||||
|
input: map[string]interface{}{ |
||||||
|
"title": "V30 No Changes Test Dashboard", |
||||||
|
"schemaVersion": 29, |
||||||
|
"panels": []interface{}{ |
||||||
|
map[string]interface{}{ |
||||||
|
"type": "timeseries", |
||||||
|
"title": "Panel with no relevant configurations", |
||||||
|
"id": 1, |
||||||
|
"fieldConfig": map[string]interface{}{ |
||||||
|
"defaults": map[string]interface{}{ |
||||||
|
"unit": "bytes", |
||||||
|
}, |
||||||
|
}, |
||||||
|
"options": map[string]interface{}{ |
||||||
|
"legend": map[string]interface{}{ |
||||||
|
"displayMode": "list", |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
expected: map[string]interface{}{ |
||||||
|
"title": "V30 No Changes Test Dashboard", |
||||||
|
"schemaVersion": 30, |
||||||
|
"panels": []interface{}{ |
||||||
|
map[string]interface{}{ |
||||||
|
"type": "timeseries", |
||||||
|
"title": "Panel with no relevant configurations", |
||||||
|
"id": 1, |
||||||
|
"fieldConfig": map[string]interface{}{ |
||||||
|
"defaults": map[string]interface{}{ |
||||||
|
"unit": "bytes", |
||||||
|
}, |
||||||
|
}, |
||||||
|
"options": map[string]interface{}{ |
||||||
|
"legend": map[string]interface{}{ |
||||||
|
"displayMode": "list", |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
{ |
||||||
|
name: "panels remain unchanged when no V30 specific migrations apply", |
||||||
|
input: map[string]interface{}{ |
||||||
|
"title": "V30 Panel Types Unchanged Test Dashboard", |
||||||
|
"schemaVersion": 29, |
||||||
|
"panels": []interface{}{ |
||||||
|
map[string]interface{}{ |
||||||
|
"type": "graph", |
||||||
|
"title": "Graph panel", |
||||||
|
"id": 1, |
||||||
|
}, |
||||||
|
map[string]interface{}{ |
||||||
|
"type": "singlestat", |
||||||
|
"title": "Singlestat panel", |
||||||
|
"id": 2, |
||||||
|
}, |
||||||
|
map[string]interface{}{ |
||||||
|
"type": "timeseries", |
||||||
|
"title": "Already timeseries panel", |
||||||
|
"id": 3, |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
expected: map[string]interface{}{ |
||||||
|
"title": "V30 Panel Types Unchanged Test Dashboard", |
||||||
|
"schemaVersion": 30, |
||||||
|
"panels": []interface{}{ |
||||||
|
map[string]interface{}{ |
||||||
|
"type": "graph", |
||||||
|
"title": "Graph panel", |
||||||
|
"id": 1, |
||||||
|
}, |
||||||
|
map[string]interface{}{ |
||||||
|
"type": "singlestat", |
||||||
|
"title": "Singlestat panel", |
||||||
|
"id": 2, |
||||||
|
}, |
||||||
|
map[string]interface{}{ |
||||||
|
"type": "timeseries", |
||||||
|
"title": "Already timeseries panel", |
||||||
|
"id": 3, |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
{ |
||||||
|
name: "graph panels with different configurations remain unchanged in V30", |
||||||
|
input: map[string]interface{}{ |
||||||
|
"title": "V30 Graph Panel Configurations Test Dashboard", |
||||||
|
"schemaVersion": 29, |
||||||
|
"panels": []interface{}{ |
||||||
|
map[string]interface{}{ |
||||||
|
"type": "graph", |
||||||
|
"title": "Graph with series mode and legend values", |
||||||
|
"id": 1, |
||||||
|
"xaxis": map[string]interface{}{ |
||||||
|
"mode": "series", |
||||||
|
}, |
||||||
|
"legend": map[string]interface{}{ |
||||||
|
"values": true, |
||||||
|
}, |
||||||
|
}, |
||||||
|
map[string]interface{}{ |
||||||
|
"type": "graph", |
||||||
|
"title": "Graph with series mode", |
||||||
|
"id": 2, |
||||||
|
"xaxis": map[string]interface{}{ |
||||||
|
"mode": "series", |
||||||
|
}, |
||||||
|
}, |
||||||
|
map[string]interface{}{ |
||||||
|
"type": "graph", |
||||||
|
"title": "Graph with histogram mode", |
||||||
|
"id": 3, |
||||||
|
"xaxis": map[string]interface{}{ |
||||||
|
"mode": "histogram", |
||||||
|
}, |
||||||
|
}, |
||||||
|
map[string]interface{}{ |
||||||
|
"type": "graph", |
||||||
|
"title": "Graph with default configuration", |
||||||
|
"id": 4, |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
expected: map[string]interface{}{ |
||||||
|
"title": "V30 Graph Panel Configurations Test Dashboard", |
||||||
|
"schemaVersion": 30, |
||||||
|
"panels": []interface{}{ |
||||||
|
map[string]interface{}{ |
||||||
|
"type": "graph", |
||||||
|
"title": "Graph with series mode and legend values", |
||||||
|
"id": 1, |
||||||
|
"xaxis": map[string]interface{}{ |
||||||
|
"mode": "series", |
||||||
|
}, |
||||||
|
"legend": map[string]interface{}{ |
||||||
|
"values": true, |
||||||
|
}, |
||||||
|
}, |
||||||
|
map[string]interface{}{ |
||||||
|
"type": "graph", |
||||||
|
"title": "Graph with series mode", |
||||||
|
"id": 2, |
||||||
|
"xaxis": map[string]interface{}{ |
||||||
|
"mode": "series", |
||||||
|
}, |
||||||
|
}, |
||||||
|
map[string]interface{}{ |
||||||
|
"type": "graph", |
||||||
|
"title": "Graph with histogram mode", |
||||||
|
"id": 3, |
||||||
|
"xaxis": map[string]interface{}{ |
||||||
|
"mode": "histogram", |
||||||
|
}, |
||||||
|
}, |
||||||
|
map[string]interface{}{ |
||||||
|
"type": "graph", |
||||||
|
"title": "Graph with default configuration", |
||||||
|
"id": 4, |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
} |
||||||
|
|
||||||
|
runMigrationTests(t, tests, schemaversion.V30) |
||||||
|
} |
@ -0,0 +1,214 @@ |
|||||||
|
{ |
||||||
|
"title": "V30 Value Mappings and Tooltip Options Migration Test Dashboard", |
||||||
|
"schemaVersion": 29, |
||||||
|
"panels": [ |
||||||
|
{ |
||||||
|
"type": "timeseries", |
||||||
|
"title": "Panel with legacy value mappings and tooltip options", |
||||||
|
"id": 1, |
||||||
|
"fieldConfig": { |
||||||
|
"defaults": { |
||||||
|
"thresholds": { |
||||||
|
"mode": "absolute", |
||||||
|
"steps": [ |
||||||
|
{ |
||||||
|
"color": "green", |
||||||
|
"value": null |
||||||
|
}, |
||||||
|
{ |
||||||
|
"color": "red", |
||||||
|
"value": 80 |
||||||
|
} |
||||||
|
] |
||||||
|
}, |
||||||
|
"mappings": [ |
||||||
|
{ |
||||||
|
"id": 0, |
||||||
|
"text": "Up", |
||||||
|
"type": 1, |
||||||
|
"value": "1" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"id": 1, |
||||||
|
"text": "Down", |
||||||
|
"type": 1, |
||||||
|
"value": "0" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"from": "10", |
||||||
|
"to": "20", |
||||||
|
"text": "Medium", |
||||||
|
"type": 2 |
||||||
|
}, |
||||||
|
{ |
||||||
|
"type": 1, |
||||||
|
"value": "null", |
||||||
|
"text": "Null Value" |
||||||
|
} |
||||||
|
] |
||||||
|
}, |
||||||
|
"overrides": [ |
||||||
|
{ |
||||||
|
"matcher": { |
||||||
|
"id": "byName", |
||||||
|
"options": "test-field" |
||||||
|
}, |
||||||
|
"properties": [ |
||||||
|
{ |
||||||
|
"id": "mappings", |
||||||
|
"value": [ |
||||||
|
{ |
||||||
|
"id": 0, |
||||||
|
"text": "Override Up", |
||||||
|
"type": 1, |
||||||
|
"value": "1" |
||||||
|
} |
||||||
|
] |
||||||
|
} |
||||||
|
] |
||||||
|
} |
||||||
|
] |
||||||
|
}, |
||||||
|
"options": { |
||||||
|
"tooltipOptions": { |
||||||
|
"mode": "multi" |
||||||
|
} |
||||||
|
} |
||||||
|
}, |
||||||
|
{ |
||||||
|
"type": "xychart", |
||||||
|
"title": "XY Chart with tooltip options only", |
||||||
|
"id": 2, |
||||||
|
"options": { |
||||||
|
"tooltipOptions": { |
||||||
|
"mode": "single" |
||||||
|
} |
||||||
|
} |
||||||
|
}, |
||||||
|
{ |
||||||
|
"type": "xychart2", |
||||||
|
"title": "XY Chart2 with tooltip options", |
||||||
|
"id": 3, |
||||||
|
"options": { |
||||||
|
"tooltipOptions": { |
||||||
|
"mode": "single", |
||||||
|
"sort": "none" |
||||||
|
} |
||||||
|
} |
||||||
|
}, |
||||||
|
{ |
||||||
|
"type": "graph", |
||||||
|
"title": "Graph panel gets migrated to timeseries and tooltip", |
||||||
|
"id": 4, |
||||||
|
"options": { |
||||||
|
"tooltip": { |
||||||
|
"mode": "single" |
||||||
|
} |
||||||
|
} |
||||||
|
}, |
||||||
|
{ |
||||||
|
"type": "stat", |
||||||
|
"title": "Panel with complex value mappings", |
||||||
|
"id": 5, |
||||||
|
"fieldConfig": { |
||||||
|
"defaults": { |
||||||
|
"mappings": [ |
||||||
|
{ |
||||||
|
"id": 0, |
||||||
|
"text": "Critical", |
||||||
|
"type": 1, |
||||||
|
"value": "100" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"from": "50", |
||||||
|
"to": "99", |
||||||
|
"text": "Warning", |
||||||
|
"type": 2 |
||||||
|
}, |
||||||
|
{ |
||||||
|
"from": "0", |
||||||
|
"to": "49", |
||||||
|
"text": "OK", |
||||||
|
"type": 2 |
||||||
|
} |
||||||
|
] |
||||||
|
} |
||||||
|
} |
||||||
|
}, |
||||||
|
{ |
||||||
|
"type": "row", |
||||||
|
"title": "Collapsed Row with nested panels", |
||||||
|
"id": 6, |
||||||
|
"collapsed": true, |
||||||
|
"panels": [ |
||||||
|
{ |
||||||
|
"type": "timeseries", |
||||||
|
"title": "Nested panel with both migrations", |
||||||
|
"id": 7, |
||||||
|
"fieldConfig": { |
||||||
|
"defaults": { |
||||||
|
"mappings": [ |
||||||
|
{ |
||||||
|
"id": 0, |
||||||
|
"text": "On", |
||||||
|
"type": 1, |
||||||
|
"value": "1" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"id": 1, |
||||||
|
"text": "Off", |
||||||
|
"type": 1, |
||||||
|
"value": "0" |
||||||
|
} |
||||||
|
] |
||||||
|
} |
||||||
|
}, |
||||||
|
"options": { |
||||||
|
"tooltipOptions": { |
||||||
|
"mode": "multi" |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
] |
||||||
|
}, |
||||||
|
{ |
||||||
|
"type": "timeseries", |
||||||
|
"title": "Panel with no relevant configurations", |
||||||
|
"id": 8, |
||||||
|
"fieldConfig": { |
||||||
|
"defaults": { |
||||||
|
"unit": "bytes" |
||||||
|
} |
||||||
|
}, |
||||||
|
"options": { |
||||||
|
"legend": { |
||||||
|
"displayMode": "list" |
||||||
|
} |
||||||
|
} |
||||||
|
}, |
||||||
|
{ |
||||||
|
"type": "stat", |
||||||
|
"title": "Panel with empty mappings array - should return null", |
||||||
|
"id": 9, |
||||||
|
"fieldConfig": { |
||||||
|
"defaults": { |
||||||
|
"mappings": [] |
||||||
|
}, |
||||||
|
"overrides": [ |
||||||
|
{ |
||||||
|
"matcher": { |
||||||
|
"id": "byName", |
||||||
|
"options": "empty-field" |
||||||
|
}, |
||||||
|
"properties": [ |
||||||
|
{ |
||||||
|
"id": "mappings", |
||||||
|
"value": [] |
||||||
|
} |
||||||
|
] |
||||||
|
} |
||||||
|
] |
||||||
|
} |
||||||
|
} |
||||||
|
] |
||||||
|
} |
@ -0,0 +1,373 @@ |
|||||||
|
{ |
||||||
|
"panels": [ |
||||||
|
{ |
||||||
|
"datasource": { |
||||||
|
"apiVersion": "v1", |
||||||
|
"type": "prometheus", |
||||||
|
"uid": "default-ds-uid" |
||||||
|
}, |
||||||
|
"fieldConfig": { |
||||||
|
"defaults": { |
||||||
|
"mappings": [ |
||||||
|
{ |
||||||
|
"options": { |
||||||
|
"0": { |
||||||
|
"color": "green", |
||||||
|
"text": "Down" |
||||||
|
}, |
||||||
|
"1": { |
||||||
|
"color": "green", |
||||||
|
"text": "Up" |
||||||
|
} |
||||||
|
}, |
||||||
|
"type": "value" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"options": { |
||||||
|
"from": 10, |
||||||
|
"result": { |
||||||
|
"color": "green", |
||||||
|
"text": "Medium" |
||||||
|
}, |
||||||
|
"to": 20 |
||||||
|
}, |
||||||
|
"type": "range" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"options": { |
||||||
|
"match": "null", |
||||||
|
"result": { |
||||||
|
"color": "green", |
||||||
|
"text": "Null Value" |
||||||
|
} |
||||||
|
}, |
||||||
|
"type": "special" |
||||||
|
} |
||||||
|
], |
||||||
|
"thresholds": { |
||||||
|
"mode": "absolute", |
||||||
|
"steps": [ |
||||||
|
{ |
||||||
|
"color": "green", |
||||||
|
"value": null |
||||||
|
}, |
||||||
|
{ |
||||||
|
"color": "red", |
||||||
|
"value": 80 |
||||||
|
} |
||||||
|
] |
||||||
|
} |
||||||
|
}, |
||||||
|
"overrides": [ |
||||||
|
{ |
||||||
|
"matcher": { |
||||||
|
"id": "byName", |
||||||
|
"options": "test-field" |
||||||
|
}, |
||||||
|
"properties": [ |
||||||
|
{ |
||||||
|
"id": "mappings", |
||||||
|
"value": [ |
||||||
|
{ |
||||||
|
"options": { |
||||||
|
"1": { |
||||||
|
"text": "Override Up" |
||||||
|
} |
||||||
|
}, |
||||||
|
"type": "value" |
||||||
|
} |
||||||
|
] |
||||||
|
} |
||||||
|
] |
||||||
|
} |
||||||
|
] |
||||||
|
}, |
||||||
|
"id": 1, |
||||||
|
"options": { |
||||||
|
"tooltip": { |
||||||
|
"mode": "multi" |
||||||
|
} |
||||||
|
}, |
||||||
|
"targets": [ |
||||||
|
{ |
||||||
|
"datasource": { |
||||||
|
"apiVersion": "v1", |
||||||
|
"type": "prometheus", |
||||||
|
"uid": "default-ds-uid" |
||||||
|
}, |
||||||
|
"refId": "A" |
||||||
|
} |
||||||
|
], |
||||||
|
"title": "Panel with legacy value mappings and tooltip options", |
||||||
|
"type": "timeseries" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"datasource": { |
||||||
|
"apiVersion": "v1", |
||||||
|
"type": "prometheus", |
||||||
|
"uid": "default-ds-uid" |
||||||
|
}, |
||||||
|
"id": 2, |
||||||
|
"options": { |
||||||
|
"tooltip": { |
||||||
|
"mode": "single" |
||||||
|
} |
||||||
|
}, |
||||||
|
"targets": [ |
||||||
|
{ |
||||||
|
"datasource": { |
||||||
|
"apiVersion": "v1", |
||||||
|
"type": "prometheus", |
||||||
|
"uid": "default-ds-uid" |
||||||
|
}, |
||||||
|
"refId": "A" |
||||||
|
} |
||||||
|
], |
||||||
|
"title": "XY Chart with tooltip options only", |
||||||
|
"type": "xychart" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"datasource": { |
||||||
|
"apiVersion": "v1", |
||||||
|
"type": "prometheus", |
||||||
|
"uid": "default-ds-uid" |
||||||
|
}, |
||||||
|
"id": 3, |
||||||
|
"options": { |
||||||
|
"tooltip": { |
||||||
|
"mode": "single", |
||||||
|
"sort": "none" |
||||||
|
} |
||||||
|
}, |
||||||
|
"targets": [ |
||||||
|
{ |
||||||
|
"datasource": { |
||||||
|
"apiVersion": "v1", |
||||||
|
"type": "prometheus", |
||||||
|
"uid": "default-ds-uid" |
||||||
|
}, |
||||||
|
"refId": "A" |
||||||
|
} |
||||||
|
], |
||||||
|
"title": "XY Chart2 with tooltip options", |
||||||
|
"type": "xychart2" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"datasource": { |
||||||
|
"apiVersion": "v1", |
||||||
|
"type": "prometheus", |
||||||
|
"uid": "default-ds-uid" |
||||||
|
}, |
||||||
|
"id": 4, |
||||||
|
"options": { |
||||||
|
"tooltip": { |
||||||
|
"mode": "single" |
||||||
|
} |
||||||
|
}, |
||||||
|
"targets": [ |
||||||
|
{ |
||||||
|
"datasource": { |
||||||
|
"apiVersion": "v1", |
||||||
|
"type": "prometheus", |
||||||
|
"uid": "default-ds-uid" |
||||||
|
}, |
||||||
|
"refId": "A" |
||||||
|
} |
||||||
|
], |
||||||
|
"title": "Graph panel gets migrated to timeseries and tooltip", |
||||||
|
"type": "graph" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"datasource": { |
||||||
|
"apiVersion": "v1", |
||||||
|
"type": "prometheus", |
||||||
|
"uid": "default-ds-uid" |
||||||
|
}, |
||||||
|
"fieldConfig": { |
||||||
|
"defaults": { |
||||||
|
"mappings": [ |
||||||
|
{ |
||||||
|
"options": { |
||||||
|
"100": { |
||||||
|
"text": "Critical" |
||||||
|
} |
||||||
|
}, |
||||||
|
"type": "value" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"options": { |
||||||
|
"from": 50, |
||||||
|
"result": { |
||||||
|
"text": "Warning" |
||||||
|
}, |
||||||
|
"to": 99 |
||||||
|
}, |
||||||
|
"type": "range" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"options": { |
||||||
|
"from": 0, |
||||||
|
"result": { |
||||||
|
"text": "OK" |
||||||
|
}, |
||||||
|
"to": 49 |
||||||
|
}, |
||||||
|
"type": "range" |
||||||
|
} |
||||||
|
] |
||||||
|
} |
||||||
|
}, |
||||||
|
"id": 5, |
||||||
|
"targets": [ |
||||||
|
{ |
||||||
|
"datasource": { |
||||||
|
"apiVersion": "v1", |
||||||
|
"type": "prometheus", |
||||||
|
"uid": "default-ds-uid" |
||||||
|
}, |
||||||
|
"refId": "A" |
||||||
|
} |
||||||
|
], |
||||||
|
"title": "Panel with complex value mappings", |
||||||
|
"type": "stat" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"collapsed": true, |
||||||
|
"datasource": { |
||||||
|
"apiVersion": "v1", |
||||||
|
"type": "prometheus", |
||||||
|
"uid": "default-ds-uid" |
||||||
|
}, |
||||||
|
"id": 6, |
||||||
|
"panels": [ |
||||||
|
{ |
||||||
|
"datasource": { |
||||||
|
"apiVersion": "v1", |
||||||
|
"type": "prometheus", |
||||||
|
"uid": "default-ds-uid" |
||||||
|
}, |
||||||
|
"fieldConfig": { |
||||||
|
"defaults": { |
||||||
|
"mappings": [ |
||||||
|
{ |
||||||
|
"options": { |
||||||
|
"0": { |
||||||
|
"text": "Off" |
||||||
|
}, |
||||||
|
"1": { |
||||||
|
"text": "On" |
||||||
|
} |
||||||
|
}, |
||||||
|
"type": "value" |
||||||
|
} |
||||||
|
] |
||||||
|
} |
||||||
|
}, |
||||||
|
"id": 7, |
||||||
|
"options": { |
||||||
|
"tooltip": { |
||||||
|
"mode": "multi" |
||||||
|
} |
||||||
|
}, |
||||||
|
"targets": [ |
||||||
|
{ |
||||||
|
"datasource": { |
||||||
|
"apiVersion": "v1", |
||||||
|
"type": "prometheus", |
||||||
|
"uid": "default-ds-uid" |
||||||
|
}, |
||||||
|
"refId": "A" |
||||||
|
} |
||||||
|
], |
||||||
|
"title": "Nested panel with both migrations", |
||||||
|
"type": "timeseries" |
||||||
|
} |
||||||
|
], |
||||||
|
"targets": [ |
||||||
|
{ |
||||||
|
"datasource": { |
||||||
|
"apiVersion": "v1", |
||||||
|
"type": "prometheus", |
||||||
|
"uid": "default-ds-uid" |
||||||
|
}, |
||||||
|
"refId": "A" |
||||||
|
} |
||||||
|
], |
||||||
|
"title": "Collapsed Row with nested panels", |
||||||
|
"type": "row" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"datasource": { |
||||||
|
"apiVersion": "v1", |
||||||
|
"type": "prometheus", |
||||||
|
"uid": "default-ds-uid" |
||||||
|
}, |
||||||
|
"fieldConfig": { |
||||||
|
"defaults": { |
||||||
|
"unit": "bytes" |
||||||
|
} |
||||||
|
}, |
||||||
|
"id": 8, |
||||||
|
"options": { |
||||||
|
"legend": { |
||||||
|
"displayMode": "list", |
||||||
|
"showLegend": true |
||||||
|
} |
||||||
|
}, |
||||||
|
"targets": [ |
||||||
|
{ |
||||||
|
"datasource": { |
||||||
|
"apiVersion": "v1", |
||||||
|
"type": "prometheus", |
||||||
|
"uid": "default-ds-uid" |
||||||
|
}, |
||||||
|
"refId": "A" |
||||||
|
} |
||||||
|
], |
||||||
|
"title": "Panel with no relevant configurations", |
||||||
|
"type": "timeseries" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"datasource": { |
||||||
|
"apiVersion": "v1", |
||||||
|
"type": "prometheus", |
||||||
|
"uid": "default-ds-uid" |
||||||
|
}, |
||||||
|
"fieldConfig": { |
||||||
|
"defaults": { |
||||||
|
"mappings": [] |
||||||
|
}, |
||||||
|
"overrides": [ |
||||||
|
{ |
||||||
|
"matcher": { |
||||||
|
"id": "byName", |
||||||
|
"options": "empty-field" |
||||||
|
}, |
||||||
|
"properties": [ |
||||||
|
{ |
||||||
|
"id": "mappings", |
||||||
|
"value": [] |
||||||
|
} |
||||||
|
] |
||||||
|
} |
||||||
|
] |
||||||
|
}, |
||||||
|
"id": 9, |
||||||
|
"targets": [ |
||||||
|
{ |
||||||
|
"datasource": { |
||||||
|
"apiVersion": "v1", |
||||||
|
"type": "prometheus", |
||||||
|
"uid": "default-ds-uid" |
||||||
|
}, |
||||||
|
"refId": "A" |
||||||
|
} |
||||||
|
], |
||||||
|
"title": "Panel with empty mappings array - should return null", |
||||||
|
"type": "stat" |
||||||
|
} |
||||||
|
], |
||||||
|
"refresh": "", |
||||||
|
"schemaVersion": 41, |
||||||
|
"title": "V30 Value Mappings and Tooltip Options Migration Test Dashboard" |
||||||
|
} |
Loading…
Reference in new issue