Compare commits

..

1 Commits

Author SHA1 Message Date
Tobias Skarhed
74cbcb338e Remove unused import, blocking main 2025-12-10 16:00:12 +01:00
917 changed files with 6539 additions and 28633 deletions

3
.github/CODEOWNERS vendored
View File

@@ -520,7 +520,7 @@ i18next.config.ts @grafana/grafana-frontend-platform
/e2e-playwright/various-suite/solo-route.spec.ts @grafana/dashboards-squad
/e2e-playwright/various-suite/trace-view-scrolling.spec.ts @grafana/observability-traces-and-profiling
/e2e-playwright/various-suite/verify-i18n.spec.ts @grafana/grafana-frontend-platform
/e2e-playwright/various-suite/visualization-suggestions.spec.ts @grafana/dataviz-squad
/e2e-playwright/various-suite/visualization-suggestions.spec.ts @grafana/dashboards-squad
/e2e-playwright/various-suite/perf-test.spec.ts @grafana/grafana-frontend-platform
# Packages
@@ -956,7 +956,6 @@ playwright.storybook.config.ts @grafana/grafana-frontend-platform
/public/app/features/notifications/ @grafana/grafana-search-navigate-organise
/public/app/features/org/ @grafana/grafana-search-navigate-organise
/public/app/features/panel/ @grafana/dashboards-squad
/public/app/features/panel/components/VizTypePicker/VisualizationSuggestions.tsx @grafana/dataviz-squad
/public/app/features/panel/suggestions/ @grafana/dataviz-squad
/public/app/features/playlist/ @grafana/dashboards-squad
/public/app/features/plugins/ @grafana/plugins-platform-frontend

View File

@@ -8,8 +8,9 @@ import (
func (stars *StarsSpec) Add(group, kind, name string) {
for i, r := range stars.Resource {
if r.Group == group && r.Kind == kind {
stars.Resource[i].Names = append(r.Names, name)
stars.Normalize()
r.Names = append(r.Names, name)
slices.Sort(r.Names)
stars.Resource[i].Names = slices.Compact(r.Names)
return
}
}
@@ -45,15 +46,8 @@ func (stars *StarsSpec) Normalize() {
resources := make([]StarsResource, 0, len(stars.Resource))
for _, r := range stars.Resource {
if len(r.Names) > 0 {
unique := make([]string, 0, len(r.Names))
found := make(map[string]bool, len(r.Names))
for _, name := range r.Names {
if !found[name] {
unique = append(unique, name)
found[name] = true
}
}
r.Names = unique
slices.Sort(r.Names)
r.Names = slices.Compact(r.Names) // removes any duplicates
resources = append(resources, r)
}
}

View File

@@ -39,7 +39,7 @@ func TestStarsWrite(t *testing.T) {
Resource: []StarsResource{{
Group: "g",
Kind: "k",
Names: []string{"a", "b", "x", "c"}, // added c to the end
Names: []string{"a", "b", "c", "x"}, // added "b" (and sorted)
}},
},
}, {

View File

@@ -57,7 +57,6 @@ require (
github.com/hashicorp/go-hclog v1.6.3 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/hashicorp/go-plugin v1.7.0 // indirect
github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
github.com/hashicorp/yamux v0.1.2 // indirect
github.com/jaegertracing/jaeger-idl v0.5.0 // indirect
github.com/josharian/intern v1.0.0 // indirect

View File

@@ -112,8 +112,6 @@ github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+l
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
github.com/hashicorp/go-plugin v1.7.0 h1:YghfQH/0QmPNc/AZMTFE3ac8fipZyZECHdDPshfk+mA=
github.com/hashicorp/go-plugin v1.7.0/go.mod h1:BExt6KEaIYx804z8k4gRzRLEvxKVb+kn0NMcihqOqb8=
github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=
github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
github.com/hashicorp/yamux v0.1.2 h1:XtB8kyFOyHXYVFnwT5C3+Bdo8gArse7j2AQ0DA0Uey8=
github.com/hashicorp/yamux v0.1.2/go.mod h1:C+zze2n6e/7wshOZep2A70/aQU6QBRWJO/G6FT1wIns=
github.com/jaegertracing/jaeger-idl v0.5.0 h1:zFXR5NL3Utu7MhPg8ZorxtCBjHrL3ReM1VoB65FOFGE=

View File

@@ -1,454 +0,0 @@
package conversion
import (
"context"
"sync/atomic"
"testing"
"time"
dashv0 "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v0alpha1"
dashv1 "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v1beta1"
dashv2alpha1 "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1"
dashv2beta1 "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2beta1"
"github.com/grafana/grafana/apps/dashboard/pkg/migration"
"github.com/grafana/grafana/apps/dashboard/pkg/migration/schemaversion"
common "github.com/grafana/grafana/pkg/apimachinery/apis/common/v0alpha1"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
// countingDataSourceProvider tracks how many times Index() is called
type countingDataSourceProvider struct {
datasources []schemaversion.DataSourceInfo
callCount atomic.Int64
}
func newCountingDataSourceProvider(datasources []schemaversion.DataSourceInfo) *countingDataSourceProvider {
return &countingDataSourceProvider{
datasources: datasources,
}
}
func (p *countingDataSourceProvider) Index(_ context.Context) *schemaversion.DatasourceIndex {
p.callCount.Add(1)
return schemaversion.NewDatasourceIndex(p.datasources)
}
func (p *countingDataSourceProvider) getCallCount() int64 {
return p.callCount.Load()
}
// countingLibraryElementProvider tracks how many times GetLibraryElementInfo() is called
type countingLibraryElementProvider struct {
elements []schemaversion.LibraryElementInfo
callCount atomic.Int64
}
func newCountingLibraryElementProvider(elements []schemaversion.LibraryElementInfo) *countingLibraryElementProvider {
return &countingLibraryElementProvider{
elements: elements,
}
}
func (p *countingLibraryElementProvider) GetLibraryElementInfo(_ context.Context) []schemaversion.LibraryElementInfo {
p.callCount.Add(1)
return p.elements
}
func (p *countingLibraryElementProvider) getCallCount() int64 {
return p.callCount.Load()
}
// createTestV0Dashboard creates a minimal v0 dashboard for testing
// The dashboard has a datasource with UID only (no type) to force provider lookup
// and includes library panels to test library element provider caching
func createTestV0Dashboard(namespace, title string) *dashv0.Dashboard {
return &dashv0.Dashboard{
ObjectMeta: metav1.ObjectMeta{
Name: "test-dashboard",
Namespace: namespace,
},
Spec: common.Unstructured{
Object: map[string]interface{}{
"title": title,
"schemaVersion": schemaversion.LATEST_VERSION,
// Variables with datasource reference that requires lookup
"templating": map[string]interface{}{
"list": []interface{}{
map[string]interface{}{
"name": "query_var",
"type": "query",
"query": "label_values(up, job)",
// Datasource with UID only - type needs to be looked up
"datasource": map[string]interface{}{
"uid": "ds1",
// type is intentionally omitted to trigger provider lookup
},
},
},
},
"panels": []interface{}{
map[string]interface{}{
"id": 1,
"title": "Test Panel",
"type": "timeseries",
"targets": []interface{}{
map[string]interface{}{
// Datasource with UID only - type needs to be looked up
"datasource": map[string]interface{}{
"uid": "ds1",
},
},
},
},
// Library panel reference - triggers library element provider lookup
map[string]interface{}{
"id": 2,
"title": "Library Panel with Horizontal Repeat",
"type": "library-panel-ref",
"gridPos": map[string]interface{}{
"h": 8,
"w": 12,
"x": 0,
"y": 8,
},
"libraryPanel": map[string]interface{}{
"uid": "lib-panel-repeat-h",
"name": "Library Panel with Horizontal Repeat",
},
},
// Another library panel reference
map[string]interface{}{
"id": 3,
"title": "Library Panel without Repeat",
"type": "library-panel-ref",
"gridPos": map[string]interface{}{
"h": 3,
"w": 6,
"x": 0,
"y": 16,
},
"libraryPanel": map[string]interface{}{
"uid": "lib-panel-no-repeat",
"name": "Library Panel without Repeat",
},
},
},
},
},
}
}
// createTestV1Dashboard creates a minimal v1beta1 dashboard for testing
// The dashboard has a datasource with UID only (no type) to force provider lookup
// and includes library panels to test library element provider caching
func createTestV1Dashboard(namespace, title string) *dashv1.Dashboard {
return &dashv1.Dashboard{
ObjectMeta: metav1.ObjectMeta{
Name: "test-dashboard",
Namespace: namespace,
},
Spec: common.Unstructured{
Object: map[string]interface{}{
"title": title,
"schemaVersion": schemaversion.LATEST_VERSION,
// Variables with datasource reference that requires lookup
"templating": map[string]interface{}{
"list": []interface{}{
map[string]interface{}{
"name": "query_var",
"type": "query",
"query": "label_values(up, job)",
// Datasource with UID only - type needs to be looked up
"datasource": map[string]interface{}{
"uid": "ds1",
// type is intentionally omitted to trigger provider lookup
},
},
},
},
"panels": []interface{}{
map[string]interface{}{
"id": 1,
"title": "Test Panel",
"type": "timeseries",
"targets": []interface{}{
map[string]interface{}{
// Datasource with UID only - type needs to be looked up
"datasource": map[string]interface{}{
"uid": "ds1",
},
},
},
},
// Library panel reference - triggers library element provider lookup
map[string]interface{}{
"id": 2,
"title": "Library Panel with Vertical Repeat",
"type": "library-panel-ref",
"gridPos": map[string]interface{}{
"h": 4,
"w": 6,
"x": 0,
"y": 8,
},
"libraryPanel": map[string]interface{}{
"uid": "lib-panel-repeat-v",
"name": "Library Panel with Vertical Repeat",
},
},
// Another library panel reference
map[string]interface{}{
"id": 3,
"title": "Library Panel without Repeat",
"type": "library-panel-ref",
"gridPos": map[string]interface{}{
"h": 3,
"w": 6,
"x": 6,
"y": 8,
},
"libraryPanel": map[string]interface{}{
"uid": "lib-panel-no-repeat",
"name": "Library Panel without Repeat",
},
},
},
},
},
}
}
// TestConversionCaching_V0_to_V2alpha1 verifies caching works when converting V0 to V2alpha1
func TestConversionCaching_V0_to_V2alpha1(t *testing.T) {
datasources := []schemaversion.DataSourceInfo{
{UID: "ds1", Type: "prometheus", Name: "Prometheus", Default: true},
}
elements := []schemaversion.LibraryElementInfo{
{UID: "lib-panel-repeat-h", Name: "Library Panel with Horizontal Repeat", Type: "timeseries"},
{UID: "lib-panel-no-repeat", Name: "Library Panel without Repeat", Type: "graph"},
}
underlyingDS := newCountingDataSourceProvider(datasources)
underlyingLE := newCountingLibraryElementProvider(elements)
cachedDS := schemaversion.WrapIndexProviderWithCache(underlyingDS, time.Minute)
cachedLE := schemaversion.WrapLibraryElementProviderWithCache(underlyingLE, time.Minute)
migration.ResetForTesting()
migration.Initialize(cachedDS, cachedLE, migration.DefaultCacheTTL)
// Convert multiple dashboards in the same namespace
numDashboards := 5
namespace := "default"
for i := 0; i < numDashboards; i++ {
source := createTestV0Dashboard(namespace, "Dashboard "+string(rune('A'+i)))
target := &dashv2alpha1.Dashboard{}
err := Convert_V0_to_V2alpha1(source, target, nil, cachedDS, cachedLE)
require.NoError(t, err, "conversion %d should succeed", i)
require.NotNil(t, target.Spec)
}
// With caching, the underlying datasource provider should only be called once per namespace
// The test dashboard has datasources without type that require lookup
assert.Equal(t, int64(1), underlyingDS.getCallCount(),
"datasource provider should be called only once for %d conversions in same namespace", numDashboards)
// Library element provider should also be called only once per namespace due to caching
assert.Equal(t, int64(1), underlyingLE.getCallCount(),
"library element provider should be called only once for %d conversions in same namespace", numDashboards)
}
// TestConversionCaching_V0_to_V2beta1 verifies caching works when converting V0 to V2beta1
func TestConversionCaching_V0_to_V2beta1(t *testing.T) {
datasources := []schemaversion.DataSourceInfo{
{UID: "ds1", Type: "prometheus", Name: "Prometheus", Default: true},
}
elements := []schemaversion.LibraryElementInfo{
{UID: "lib-panel-repeat-h", Name: "Library Panel with Horizontal Repeat", Type: "timeseries"},
{UID: "lib-panel-no-repeat", Name: "Library Panel without Repeat", Type: "graph"},
}
underlyingDS := newCountingDataSourceProvider(datasources)
underlyingLE := newCountingLibraryElementProvider(elements)
cachedDS := schemaversion.WrapIndexProviderWithCache(underlyingDS, time.Minute)
cachedLE := schemaversion.WrapLibraryElementProviderWithCache(underlyingLE, time.Minute)
migration.ResetForTesting()
migration.Initialize(cachedDS, cachedLE, migration.DefaultCacheTTL)
numDashboards := 5
namespace := "default"
for i := 0; i < numDashboards; i++ {
source := createTestV0Dashboard(namespace, "Dashboard "+string(rune('A'+i)))
target := &dashv2beta1.Dashboard{}
err := Convert_V0_to_V2beta1(source, target, nil, cachedDS, cachedLE)
require.NoError(t, err, "conversion %d should succeed", i)
require.NotNil(t, target.Spec)
}
assert.Equal(t, int64(1), underlyingDS.getCallCount(),
"datasource provider should be called only once for %d conversions in same namespace", numDashboards)
assert.Equal(t, int64(1), underlyingLE.getCallCount(),
"library element provider should be called only once for %d conversions in same namespace", numDashboards)
}
// TestConversionCaching_V1beta1_to_V2alpha1 verifies caching works when converting V1beta1 to V2alpha1
func TestConversionCaching_V1beta1_to_V2alpha1(t *testing.T) {
datasources := []schemaversion.DataSourceInfo{
{UID: "ds1", Type: "prometheus", Name: "Prometheus", Default: true},
}
elements := []schemaversion.LibraryElementInfo{
{UID: "lib-panel-repeat-v", Name: "Library Panel with Vertical Repeat", Type: "timeseries"},
{UID: "lib-panel-no-repeat", Name: "Library Panel without Repeat", Type: "graph"},
}
underlyingDS := newCountingDataSourceProvider(datasources)
underlyingLE := newCountingLibraryElementProvider(elements)
cachedDS := schemaversion.WrapIndexProviderWithCache(underlyingDS, time.Minute)
cachedLE := schemaversion.WrapLibraryElementProviderWithCache(underlyingLE, time.Minute)
migration.ResetForTesting()
migration.Initialize(cachedDS, cachedLE, migration.DefaultCacheTTL)
numDashboards := 5
namespace := "default"
for i := 0; i < numDashboards; i++ {
source := createTestV1Dashboard(namespace, "Dashboard "+string(rune('A'+i)))
target := &dashv2alpha1.Dashboard{}
err := Convert_V1beta1_to_V2alpha1(source, target, nil, cachedDS, cachedLE)
require.NoError(t, err, "conversion %d should succeed", i)
require.NotNil(t, target.Spec)
}
assert.Equal(t, int64(1), underlyingDS.getCallCount(),
"datasource provider should be called only once for %d conversions in same namespace", numDashboards)
assert.Equal(t, int64(1), underlyingLE.getCallCount(),
"library element provider should be called only once for %d conversions in same namespace", numDashboards)
}
// TestConversionCaching_V1beta1_to_V2beta1 verifies caching works when converting V1beta1 to V2beta1
func TestConversionCaching_V1beta1_to_V2beta1(t *testing.T) {
datasources := []schemaversion.DataSourceInfo{
{UID: "ds1", Type: "prometheus", Name: "Prometheus", Default: true},
}
elements := []schemaversion.LibraryElementInfo{
{UID: "lib-panel-repeat-v", Name: "Library Panel with Vertical Repeat", Type: "timeseries"},
{UID: "lib-panel-no-repeat", Name: "Library Panel without Repeat", Type: "graph"},
}
underlyingDS := newCountingDataSourceProvider(datasources)
underlyingLE := newCountingLibraryElementProvider(elements)
cachedDS := schemaversion.WrapIndexProviderWithCache(underlyingDS, time.Minute)
cachedLE := schemaversion.WrapLibraryElementProviderWithCache(underlyingLE, time.Minute)
migration.ResetForTesting()
migration.Initialize(cachedDS, cachedLE, migration.DefaultCacheTTL)
numDashboards := 5
namespace := "default"
for i := 0; i < numDashboards; i++ {
source := createTestV1Dashboard(namespace, "Dashboard "+string(rune('A'+i)))
target := &dashv2beta1.Dashboard{}
err := Convert_V1beta1_to_V2beta1(source, target, nil, cachedDS, cachedLE)
require.NoError(t, err, "conversion %d should succeed", i)
require.NotNil(t, target.Spec)
}
assert.Equal(t, int64(1), underlyingDS.getCallCount(),
"datasource provider should be called only once for %d conversions in same namespace", numDashboards)
assert.Equal(t, int64(1), underlyingLE.getCallCount(),
"library element provider should be called only once for %d conversions in same namespace", numDashboards)
}
// TestConversionCaching_MultipleNamespaces verifies that different namespaces get separate cache entries
func TestConversionCaching_MultipleNamespaces(t *testing.T) {
datasources := []schemaversion.DataSourceInfo{
{UID: "ds1", Type: "prometheus", Name: "Prometheus", Default: true},
}
elements := []schemaversion.LibraryElementInfo{
{UID: "lib-panel-repeat-h", Name: "Library Panel with Horizontal Repeat", Type: "timeseries"},
{UID: "lib-panel-no-repeat", Name: "Library Panel without Repeat", Type: "graph"},
}
underlyingDS := newCountingDataSourceProvider(datasources)
underlyingLE := newCountingLibraryElementProvider(elements)
cachedDS := schemaversion.WrapIndexProviderWithCache(underlyingDS, time.Minute)
cachedLE := schemaversion.WrapLibraryElementProviderWithCache(underlyingLE, time.Minute)
migration.ResetForTesting()
migration.Initialize(cachedDS, cachedLE, migration.DefaultCacheTTL)
namespaces := []string{"default", "org-2", "org-3"}
numDashboardsPerNs := 3
for _, ns := range namespaces {
for i := 0; i < numDashboardsPerNs; i++ {
source := createTestV0Dashboard(ns, "Dashboard "+string(rune('A'+i)))
target := &dashv2alpha1.Dashboard{}
err := Convert_V0_to_V2alpha1(source, target, nil, cachedDS, cachedLE)
require.NoError(t, err, "conversion for namespace %s should succeed", ns)
}
}
// With caching, each namespace should result in one call to the underlying provider
expectedCalls := int64(len(namespaces))
assert.Equal(t, expectedCalls, underlyingDS.getCallCount(),
"datasource provider should be called once per namespace (%d namespaces)", len(namespaces))
assert.Equal(t, expectedCalls, underlyingLE.getCallCount(),
"library element provider should be called once per namespace (%d namespaces)", len(namespaces))
}
// TestConversionCaching_CacheDisabled verifies that TTL=0 disables caching
func TestConversionCaching_CacheDisabled(t *testing.T) {
datasources := []schemaversion.DataSourceInfo{
{UID: "ds1", Type: "prometheus", Name: "Prometheus", Default: true},
}
elements := []schemaversion.LibraryElementInfo{
{UID: "lib-panel-repeat-h", Name: "Library Panel with Horizontal Repeat", Type: "timeseries"},
{UID: "lib-panel-no-repeat", Name: "Library Panel without Repeat", Type: "graph"},
}
underlyingDS := newCountingDataSourceProvider(datasources)
underlyingLE := newCountingLibraryElementProvider(elements)
// TTL of 0 should disable caching - the wrapper returns the underlying provider directly
cachedDS := schemaversion.WrapIndexProviderWithCache(underlyingDS, 0)
cachedLE := schemaversion.WrapLibraryElementProviderWithCache(underlyingLE, 0)
migration.ResetForTesting()
migration.Initialize(cachedDS, cachedLE, migration.DefaultCacheTTL)
numDashboards := 3
namespace := "default"
for i := 0; i < numDashboards; i++ {
source := createTestV0Dashboard(namespace, "Dashboard "+string(rune('A'+i)))
target := &dashv2alpha1.Dashboard{}
err := Convert_V0_to_V2alpha1(source, target, nil, cachedDS, cachedLE)
require.NoError(t, err, "conversion %d should succeed", i)
}
// Without caching, each conversion calls the underlying provider multiple times
// (once for each datasource lookup needed - variables and panels)
// The key check is that the count is GREATER than 1 per conversion (no caching benefit)
assert.Greater(t, underlyingDS.getCallCount(), int64(numDashboards),
"with cache disabled, conversions should call datasource provider multiple times")
// Library element provider is also called for each conversion without caching
assert.GreaterOrEqual(t, underlyingLE.getCallCount(), int64(numDashboards),
"with cache disabled, conversions should call library element provider multiple times")
}

View File

@@ -4,6 +4,8 @@ import (
"errors"
"fmt"
"k8s.io/apimachinery/pkg/conversion"
dashv0 "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v0alpha1"
dashv1 "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v1beta1"
dashv2alpha1 "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1"
@@ -119,14 +121,6 @@ func countPanelsV0V1(spec map[string]interface{}) int {
return count
}
// countTargetsFromPanel counts the number of targets/queries in a panel.
func countTargetsFromPanel(panelMap map[string]interface{}) int {
if targets, ok := panelMap["targets"].([]interface{}); ok {
return len(targets)
}
return 0
}
// countQueriesV0V1 counts data queries in v0alpha1 or v1beta1 dashboard spec
// Note: Row panels are layout containers and should not have queries.
// We ignore any queries on row panels themselves, but count queries in their collapsed panels.
@@ -151,7 +145,9 @@ func countQueriesV0V1(spec map[string]interface{}) int {
// Count queries in regular panels (NOT row panels)
if panelType != "row" {
count += countTargetsFromPanel(panelMap)
if targets, ok := panelMap["targets"].([]interface{}); ok {
count += len(targets)
}
}
// Count queries in collapsed panels inside row panels
@@ -159,7 +155,9 @@ func countQueriesV0V1(spec map[string]interface{}) int {
if collapsedPanels, ok := panelMap["panels"].([]interface{}); ok {
for _, cp := range collapsedPanels {
if cpMap, ok := cp.(map[string]interface{}); ok {
count += countTargetsFromPanel(cpMap)
if targets, ok := cpMap["targets"].([]interface{}); ok {
count += len(targets)
}
}
}
}
@@ -444,3 +442,77 @@ func collectDashboardStats(dashboard interface{}) dashboardStats {
}
return dashboardStats{}
}
// withConversionDataLossDetection wraps a conversion function to detect data loss
func withConversionDataLossDetection(sourceFuncName, targetFuncName string, conversionFunc func(a, b interface{}, scope conversion.Scope) error) func(a, b interface{}, scope conversion.Scope) error {
return func(a, b interface{}, scope conversion.Scope) error {
// Collect source statistics
var sourceStats dashboardStats
switch source := a.(type) {
case *dashv0.Dashboard:
if source.Spec.Object != nil {
sourceStats = collectStatsV0V1(source.Spec.Object)
}
case *dashv1.Dashboard:
if source.Spec.Object != nil {
sourceStats = collectStatsV0V1(source.Spec.Object)
}
case *dashv2alpha1.Dashboard:
sourceStats = collectStatsV2alpha1(source.Spec)
case *dashv2beta1.Dashboard:
sourceStats = collectStatsV2beta1(source.Spec)
}
// Execute the conversion
err := conversionFunc(a, b, scope)
if err != nil {
return err
}
// Collect target statistics
var targetStats dashboardStats
switch target := b.(type) {
case *dashv0.Dashboard:
if target.Spec.Object != nil {
targetStats = collectStatsV0V1(target.Spec.Object)
}
case *dashv1.Dashboard:
if target.Spec.Object != nil {
targetStats = collectStatsV0V1(target.Spec.Object)
}
case *dashv2alpha1.Dashboard:
targetStats = collectStatsV2alpha1(target.Spec)
case *dashv2beta1.Dashboard:
targetStats = collectStatsV2beta1(target.Spec)
}
// Detect if data was lost
if dataLossErr := detectConversionDataLoss(sourceStats, targetStats, sourceFuncName, targetFuncName); dataLossErr != nil {
logger.Error("Dashboard conversion data loss detected",
"sourceFunc", sourceFuncName,
"targetFunc", targetFuncName,
"sourcePanels", sourceStats.panelCount,
"targetPanels", targetStats.panelCount,
"sourceQueries", sourceStats.queryCount,
"targetQueries", targetStats.queryCount,
"sourceAnnotations", sourceStats.annotationCount,
"targetAnnotations", targetStats.annotationCount,
"sourceLinks", sourceStats.linkCount,
"targetLinks", targetStats.linkCount,
"error", dataLossErr,
)
return dataLossErr
}
logger.Debug("Dashboard conversion completed without data loss",
"sourceFunc", sourceFuncName,
"targetFunc", targetFuncName,
"panels", targetStats.panelCount,
"queries", targetStats.queryCount,
"annotations", targetStats.annotationCount,
"links", targetStats.linkCount,
)
return nil
}
}

View File

@@ -35,7 +35,7 @@ func TestConversionMatrixExist(t *testing.T) {
dsProvider := migrationtestutil.NewDataSourceProvider(migrationtestutil.StandardTestConfig)
// Use TestLibraryElementProvider for tests that need library panel models with repeat options
leProvider := migrationtestutil.NewTestLibraryElementProvider()
migration.Initialize(dsProvider, leProvider, migration.DefaultCacheTTL)
migration.Initialize(dsProvider, leProvider)
versions := []metav1.Object{
&dashv0.Dashboard{Spec: common.Unstructured{Object: map[string]any{"title": "dashboardV0"}}},
@@ -89,7 +89,7 @@ func TestDashboardConversionToAllVersions(t *testing.T) {
dsProvider := migrationtestutil.NewDataSourceProvider(migrationtestutil.StandardTestConfig)
// Use TestLibraryElementProvider for tests that need library panel models with repeat options
leProvider := migrationtestutil.NewTestLibraryElementProvider()
migration.Initialize(dsProvider, leProvider, migration.DefaultCacheTTL)
migration.Initialize(dsProvider, leProvider)
// Set up conversion scheme
scheme := runtime.NewScheme()
@@ -309,7 +309,7 @@ func TestMigratedDashboardsConversion(t *testing.T) {
dsProvider := migrationtestutil.NewDataSourceProvider(migrationtestutil.StandardTestConfig)
// Use TestLibraryElementProvider for tests that need library panel models with repeat options
leProvider := migrationtestutil.NewTestLibraryElementProvider()
migration.Initialize(dsProvider, leProvider, migration.DefaultCacheTTL)
migration.Initialize(dsProvider, leProvider)
// Set up conversion scheme
scheme := runtime.NewScheme()
@@ -428,7 +428,7 @@ func setupTestConversionScheme(t *testing.T) *runtime.Scheme {
t.Helper()
dsProvider := migrationtestutil.NewDataSourceProvider(migrationtestutil.StandardTestConfig)
leProvider := migrationtestutil.NewLibraryElementProvider()
migration.Initialize(dsProvider, leProvider, migration.DefaultCacheTTL)
migration.Initialize(dsProvider, leProvider)
scheme := runtime.NewScheme()
err := RegisterConversions(scheme, dsProvider, leProvider)
@@ -527,7 +527,7 @@ func TestConversionMetrics(t *testing.T) {
dsProvider := migrationtestutil.NewDataSourceProvider(migrationtestutil.StandardTestConfig)
// Use TestLibraryElementProvider for tests that need library panel models with repeat options
leProvider := migrationtestutil.NewTestLibraryElementProvider()
migration.Initialize(dsProvider, leProvider, migration.DefaultCacheTTL)
migration.Initialize(dsProvider, leProvider)
// Create a test registry for metrics
registry := prometheus.NewRegistry()
@@ -694,7 +694,7 @@ func TestConversionMetricsWrapper(t *testing.T) {
dsProvider := migrationtestutil.NewDataSourceProvider(migrationtestutil.StandardTestConfig)
// Use TestLibraryElementProvider for tests that need library panel models with repeat options
leProvider := migrationtestutil.NewTestLibraryElementProvider()
migration.Initialize(dsProvider, leProvider, migration.DefaultCacheTTL)
migration.Initialize(dsProvider, leProvider)
// Create a test registry for metrics
registry := prometheus.NewRegistry()
@@ -864,7 +864,7 @@ func TestSchemaVersionExtraction(t *testing.T) {
dsProvider := migrationtestutil.NewDataSourceProvider(migrationtestutil.StandardTestConfig)
// Use TestLibraryElementProvider for tests that need library panel models with repeat options
leProvider := migrationtestutil.NewTestLibraryElementProvider()
migration.Initialize(dsProvider, leProvider, migration.DefaultCacheTTL)
migration.Initialize(dsProvider, leProvider)
// Create a test registry for metrics
registry := prometheus.NewRegistry()
@@ -910,7 +910,7 @@ func TestConversionLogging(t *testing.T) {
dsProvider := migrationtestutil.NewDataSourceProvider(migrationtestutil.StandardTestConfig)
// Use TestLibraryElementProvider for tests that need library panel models with repeat options
leProvider := migrationtestutil.NewTestLibraryElementProvider()
migration.Initialize(dsProvider, leProvider, migration.DefaultCacheTTL)
migration.Initialize(dsProvider, leProvider)
// Create a test registry for metrics
registry := prometheus.NewRegistry()
@@ -1003,7 +1003,7 @@ func TestConversionLogLevels(t *testing.T) {
dsProvider := migrationtestutil.NewDataSourceProvider(migrationtestutil.StandardTestConfig)
// Use TestLibraryElementProvider for tests that need library panel models with repeat options
leProvider := migrationtestutil.NewTestLibraryElementProvider()
migration.Initialize(dsProvider, leProvider, migration.DefaultCacheTTL)
migration.Initialize(dsProvider, leProvider)
t.Run("log levels and structured fields verification", func(t *testing.T) {
// Create test wrapper to verify logging behavior
@@ -1076,7 +1076,7 @@ func TestConversionLoggingFields(t *testing.T) {
dsProvider := migrationtestutil.NewDataSourceProvider(migrationtestutil.StandardTestConfig)
// Use TestLibraryElementProvider for tests that need library panel models with repeat options
leProvider := migrationtestutil.NewTestLibraryElementProvider()
migration.Initialize(dsProvider, leProvider, migration.DefaultCacheTTL)
migration.Initialize(dsProvider, leProvider)
t.Run("verify all log fields are present", func(t *testing.T) {
// Test that the conversion wrapper includes all expected structured fields

View File

@@ -17,9 +17,7 @@ import (
"github.com/grafana/grafana/apps/dashboard/pkg/migration/schemaversion"
)
func getLogger() logging.Logger {
return logging.DefaultLogger.With("logger", "dashboard.conversion")
}
var logger = logging.DefaultLogger.With("logger", "dashboard.conversion")
// getErroredSchemaVersionFunc determines the schema version function that errored
func getErroredSchemaVersionFunc(err error) string {
@@ -199,9 +197,9 @@ func withConversionMetrics(sourceVersionAPI, targetVersionAPI string, conversion
)
if errorType == "schema_minimum_version_error" {
getLogger().Warn("Dashboard conversion failed", logFields...)
logger.Warn("Dashboard conversion failed", logFields...)
} else {
getLogger().Error("Dashboard conversion failed", logFields...)
logger.Error("Dashboard conversion failed", logFields...)
}
} else {
// Record success metrics
@@ -237,7 +235,7 @@ func withConversionMetrics(sourceVersionAPI, targetVersionAPI string, conversion
)
}
getLogger().Debug("Dashboard conversion succeeded", successLogFields...)
logger.Debug("Dashboard conversion succeeded", successLogFields...)
}
return nil

View File

@@ -76,9 +76,9 @@
"barGlow": false,
"centerGlow": false,
"rounded": true,
"spotlight": false,
"gradient": false
"spotlight": false
},
"gradient": "none",
"orientation": "auto",
"reduceOptions": {
"calcs": [
@@ -155,9 +155,9 @@
"barGlow": false,
"centerGlow": true,
"rounded": true,
"spotlight": false,
"gradient": false
"spotlight": false
},
"gradient": "none",
"orientation": "auto",
"reduceOptions": {
"calcs": [
@@ -234,9 +234,9 @@
"barGlow": true,
"centerGlow": true,
"rounded": true,
"spotlight": false,
"gradient": false
"spotlight": false
},
"gradient": "none",
"orientation": "auto",
"reduceOptions": {
"calcs": [
@@ -313,9 +313,9 @@
"barGlow": true,
"centerGlow": true,
"rounded": true,
"spotlight": true,
"gradient": false
"spotlight": true
},
"gradient": "none",
"orientation": "auto",
"reduceOptions": {
"calcs": [
@@ -392,9 +392,9 @@
"barGlow": true,
"centerGlow": true,
"rounded": true,
"spotlight": true,
"gradient": false
"spotlight": true
},
"gradient": "none",
"orientation": "auto",
"reduceOptions": {
"calcs": [
@@ -471,9 +471,9 @@
"barGlow": true,
"centerGlow": true,
"rounded": false,
"spotlight": true,
"gradient": false
"spotlight": true
},
"gradient": "none",
"orientation": "auto",
"reduceOptions": {
"calcs": [
@@ -550,9 +550,9 @@
"barGlow": true,
"centerGlow": true,
"rounded": false,
"spotlight": true,
"gradient": false
"spotlight": true
},
"gradient": "none",
"orientation": "auto",
"reduceOptions": {
"calcs": [
@@ -642,9 +642,9 @@
"barGlow": true,
"centerGlow": true,
"rounded": true,
"spotlight": true,
"gradient": false
"spotlight": true
},
"gradient": "none",
"orientation": "auto",
"reduceOptions": {
"calcs": [
@@ -721,9 +721,9 @@
"barGlow": true,
"centerGlow": true,
"rounded": true,
"spotlight": true,
"gradient": false
"spotlight": true
},
"gradient": "none",
"orientation": "auto",
"reduceOptions": {
"calcs": [
@@ -800,9 +800,9 @@
"barGlow": true,
"centerGlow": true,
"rounded": true,
"spotlight": true,
"gradient": false
"spotlight": true
},
"gradient": "none",
"orientation": "auto",
"reduceOptions": {
"calcs": [
@@ -879,9 +879,9 @@
"barGlow": true,
"centerGlow": true,
"rounded": true,
"spotlight": true,
"gradient": false
"spotlight": true
},
"gradient": "none",
"orientation": "auto",
"reduceOptions": {
"calcs": [
@@ -975,9 +975,9 @@
"barGlow": false,
"centerGlow": false,
"rounded": false,
"spotlight": false,
"gradient": false
"spotlight": false
},
"gradient": "none",
"orientation": "auto",
"reduceOptions": {
"calcs": [
@@ -1054,9 +1054,9 @@
"barGlow": false,
"centerGlow": false,
"rounded": false,
"spotlight": false,
"gradient": false
"spotlight": false
},
"gradient": "none",
"orientation": "auto",
"reduceOptions": {
"calcs": [
@@ -1133,9 +1133,9 @@
"barGlow": false,
"centerGlow": false,
"rounded": false,
"spotlight": false,
"gradient": true
"spotlight": false
},
"gradient": "auto",
"orientation": "auto",
"reduceOptions": {
"calcs": [
@@ -1212,9 +1212,9 @@
"barGlow": false,
"centerGlow": false,
"rounded": false,
"spotlight": false,
"gradient": false
"spotlight": false
},
"gradient": "none",
"orientation": "auto",
"reduceOptions": {
"calcs": [
@@ -1291,9 +1291,9 @@
"barGlow": false,
"centerGlow": false,
"rounded": false,
"spotlight": false,
"gradient": false
"spotlight": false
},
"gradient": "none",
"orientation": "auto",
"reduceOptions": {
"calcs": [
@@ -1387,9 +1387,9 @@
"barGlow": false,
"centerGlow": false,
"rounded": false,
"spotlight": false,
"gradient": true
"spotlight": false
},
"gradient": "auto",
"orientation": "auto",
"reduceOptions": {
"calcs": [
@@ -1470,9 +1470,9 @@
"barGlow": false,
"centerGlow": false,
"rounded": false,
"spotlight": false,
"gradient": true
"spotlight": false
},
"gradient": "auto",
"orientation": "auto",
"reduceOptions": {
"calcs": [
@@ -1553,9 +1553,9 @@
"barGlow": false,
"centerGlow": false,
"rounded": false,
"spotlight": false,
"gradient": true
"spotlight": false
},
"gradient": "auto",
"orientation": "auto",
"reduceOptions": {
"calcs": [
@@ -1645,10 +1645,10 @@
"barGlow": true,
"centerGlow": true,
"rounded": true,
"spotlight": true,
"gradient": true
"spotlight": true
},
"glow": "both",
"gradient": "auto",
"orientation": "auto",
"reduceOptions": {
"calcs": [
@@ -1731,10 +1731,10 @@
"barGlow": true,
"centerGlow": true,
"rounded": true,
"spotlight": true,
"gradient": true
"spotlight": true
},
"glow": "both",
"gradient": "scheme",
"orientation": "auto",
"reduceOptions": {
"calcs": [
@@ -1831,10 +1831,10 @@
"barGlow": true,
"centerGlow": true,
"rounded": true,
"spotlight": true,
"gradient": true
"spotlight": true
},
"glow": "both",
"gradient": "scheme",
"orientation": "auto",
"reduceOptions": {
"calcs": [
@@ -1919,10 +1919,10 @@
"centerGlow": true,
"rounded": true,
"sparkline": false,
"spotlight": true,
"gradient": true
"spotlight": true
},
"glow": "both",
"gradient": "scheme",
"orientation": "auto",
"reduceOptions": {
"calcs": [
@@ -2005,10 +2005,10 @@
"barGlow": true,
"centerGlow": true,
"rounded": true,
"spotlight": true,
"gradient": true
"spotlight": true
},
"glow": "both",
"gradient": "hue",
"orientation": "auto",
"reduceOptions": {
"calcs": [
@@ -2091,10 +2091,10 @@
"barGlow": true,
"centerGlow": true,
"rounded": true,
"spotlight": true,
"gradient": true
"spotlight": true
},
"glow": "both",
"gradient": "hue",
"orientation": "auto",
"reduceOptions": {
"calcs": [
@@ -2147,4 +2147,4 @@
"title": "Panel tests - Gauge (new)",
"uid": "panel-tests-gauge-new",
"weekStart": ""
}
}

View File

@@ -956,9 +956,9 @@
"barGlow": false,
"centerGlow": false,
"rounded": false,
"spotlight": false,
"gradient": false
"spotlight": false
},
"gradient": "none",
"orientation": "auto",
"reduceOptions": {
"calcs": [
@@ -1162,4 +1162,4 @@
"title": "Panel tests - Old gauge to new",
"uid": "panel-tests-old-gauge-to-new",
"weekStart": ""
}
}

View File

@@ -237,10 +237,5 @@
"title": "V10 Table Thresholds Test",
"variables": []
},
"status": {
"conversion": {
"failed": false,
"storedVersion": "v1beta1"
}
}
"status": {}
}

View File

@@ -244,10 +244,5 @@
"title": "V10 Table Thresholds Test",
"variables": []
},
"status": {
"conversion": {
"failed": false,
"storedVersion": "v1beta1"
}
}
"status": {}
}

View File

@@ -206,10 +206,5 @@
}
]
},
"status": {
"conversion": {
"failed": false,
"storedVersion": "v1beta1"
}
}
"status": {}
}

View File

@@ -213,10 +213,5 @@
}
]
},
"status": {
"conversion": {
"failed": false,
"storedVersion": "v1beta1"
}
}
"status": {}
}

View File

@@ -203,10 +203,5 @@
}
]
},
"status": {
"conversion": {
"failed": false,
"storedVersion": "v1beta1"
}
}
"status": {}
}

View File

@@ -216,10 +216,5 @@
}
]
},
"status": {
"conversion": {
"failed": false,
"storedVersion": "v1beta1"
}
}
"status": {}
}

View File

@@ -351,10 +351,5 @@
"title": "V13 Graph Thresholds Migration Test",
"variables": []
},
"status": {
"conversion": {
"failed": false,
"storedVersion": "v1beta1"
}
}
"status": {}
}

View File

@@ -362,10 +362,5 @@
"title": "V13 Graph Thresholds Migration Test",
"variables": []
},
"status": {
"conversion": {
"failed": false,
"storedVersion": "v1beta1"
}
}
"status": {}
}

View File

@@ -129,10 +129,5 @@
"title": "Dashboard with minimal graph panel settings",
"variables": []
},
"status": {
"conversion": {
"failed": false,
"storedVersion": "v1beta1"
}
}
"status": {}
}

View File

@@ -132,10 +132,5 @@
"title": "Dashboard with minimal graph panel settings",
"variables": []
},
"status": {
"conversion": {
"failed": false,
"storedVersion": "v1beta1"
}
}
"status": {}
}

View File

@@ -210,10 +210,5 @@
}
]
},
"status": {
"conversion": {
"failed": false,
"storedVersion": "v1beta1"
}
}
"status": {}
}

View File

@@ -217,10 +217,5 @@
}
]
},
"status": {
"conversion": {
"failed": false,
"storedVersion": "v1beta1"
}
}
"status": {}
}

View File

@@ -1004,10 +1004,5 @@
}
]
},
"status": {
"conversion": {
"failed": false,
"storedVersion": "v1beta1"
}
}
"status": {}
}

View File

@@ -1023,10 +1023,5 @@
}
]
},
"status": {
"conversion": {
"failed": false,
"storedVersion": "v1beta1"
}
}
"status": {}
}

View File

@@ -223,10 +223,5 @@
}
]
},
"status": {
"conversion": {
"failed": false,
"storedVersion": "v1beta1"
}
}
"status": {}
}

View File

@@ -231,10 +231,5 @@
}
]
},
"status": {
"conversion": {
"failed": false,
"storedVersion": "v1beta1"
}
}
"status": {}
}

View File

@@ -1455,10 +1455,5 @@
}
]
},
"status": {
"conversion": {
"failed": false,
"storedVersion": "v1beta1"
}
}
"status": {}
}

View File

@@ -1481,10 +1481,5 @@
}
]
},
"status": {
"conversion": {
"failed": false,
"storedVersion": "v1beta1"
}
}
"status": {}
}

View File

@@ -719,10 +719,5 @@
"title": "V16 Grid Layout Migration Test Dashboard",
"variables": []
},
"status": {
"conversion": {
"failed": false,
"storedVersion": "v1beta1"
}
}
"status": {}
}

View File

@@ -739,10 +739,5 @@
"title": "V16 Grid Layout Migration Test Dashboard",
"variables": []
},
"status": {
"conversion": {
"failed": false,
"storedVersion": "v1beta1"
}
}
"status": {}
}

View File

@@ -1655,10 +1655,5 @@
}
]
},
"status": {
"conversion": {
"failed": false,
"storedVersion": "v1beta1"
}
}
"status": {}
}

View File

@@ -1707,10 +1707,5 @@
}
]
},
"status": {
"conversion": {
"failed": false,
"storedVersion": "v1beta1"
}
}
"status": {}
}

View File

@@ -636,10 +636,5 @@
"title": "V17 MinSpan to MaxPerRow Migration Test Dashboard",
"variables": []
},
"status": {
"conversion": {
"failed": false,
"storedVersion": "v1beta1"
}
}
"status": {}
}

View File

@@ -657,10 +657,5 @@
"title": "V17 MinSpan to MaxPerRow Migration Test Dashboard",
"variables": []
},
"status": {
"conversion": {
"failed": false,
"storedVersion": "v1beta1"
}
}
"status": {}
}

View File

@@ -401,10 +401,5 @@
"title": "V18 Gauge Options Migration Test Dashboard",
"variables": []
},
"status": {
"conversion": {
"failed": false,
"storedVersion": "v1beta1"
}
}
"status": {}
}

View File

@@ -412,10 +412,5 @@
"title": "V18 Gauge Options Migration Test Dashboard",
"variables": []
},
"status": {
"conversion": {
"failed": false,
"storedVersion": "v1beta1"
}
}
"status": {}
}

View File

@@ -434,10 +434,5 @@
"title": "V19 Panel Links Migration Test Dashboard",
"variables": []
},
"status": {
"conversion": {
"failed": false,
"storedVersion": "v1beta1"
}
}
"status": {}
}

View File

@@ -447,10 +447,5 @@
"title": "V19 Panel Links Migration Test Dashboard",
"variables": []
},
"status": {
"conversion": {
"failed": false,
"storedVersion": "v1beta1"
}
}
"status": {}
}

View File

@@ -354,10 +354,5 @@
}
]
},
"status": {
"conversion": {
"failed": false,
"storedVersion": "v1beta1"
}
}
"status": {}
}

View File

@@ -365,10 +365,5 @@
}
]
},
"status": {
"conversion": {
"failed": false,
"storedVersion": "v1beta1"
}
}
"status": {}
}

View File

@@ -426,10 +426,5 @@
"title": "V20 Variable Syntax Migration Test Dashboard",
"variables": []
},
"status": {
"conversion": {
"failed": false,
"storedVersion": "v1beta1"
}
}
"status": {}
}

View File

@@ -437,10 +437,5 @@
"title": "V20 Variable Syntax Migration Test Dashboard",
"variables": []
},
"status": {
"conversion": {
"failed": false,
"storedVersion": "v1beta1"
}
}
"status": {}
}

View File

@@ -401,10 +401,5 @@
"title": "V21 Data Links Series to Field Migration Test Dashboard",
"variables": []
},
"status": {
"conversion": {
"failed": false,
"storedVersion": "v1beta1"
}
}
"status": {}
}

View File

@@ -412,10 +412,5 @@
"title": "V21 Data Links Series to Field Migration Test Dashboard",
"variables": []
},
"status": {
"conversion": {
"failed": false,
"storedVersion": "v1beta1"
}
}
"status": {}
}

View File

@@ -123,10 +123,5 @@
"title": "V22 Table Panel Styles Test",
"variables": []
},
"status": {
"conversion": {
"failed": false,
"storedVersion": "v1beta1"
}
}
"status": {}
}

View File

@@ -126,10 +126,5 @@
"title": "V22 Table Panel Styles Test",
"variables": []
},
"status": {
"conversion": {
"failed": false,
"storedVersion": "v1beta1"
}
}
"status": {}
}

View File

@@ -374,10 +374,5 @@
}
]
},
"status": {
"conversion": {
"failed": false,
"storedVersion": "v1beta1"
}
}
"status": {}
}

View File

@@ -391,10 +391,5 @@
}
]
},
"status": {
"conversion": {
"failed": false,
"storedVersion": "v1beta1"
}
}
"status": {}
}

View File

@@ -1065,10 +1065,5 @@
"title": "No Title",
"variables": []
},
"status": {
"conversion": {
"failed": false,
"storedVersion": "v1beta1"
}
}
"status": {}
}

View File

@@ -1101,10 +1101,5 @@
"title": "No Title",
"variables": []
},
"status": {
"conversion": {
"failed": false,
"storedVersion": "v1beta1"
}
}
"status": {}
}

View File

@@ -217,10 +217,5 @@
}
]
},
"status": {
"conversion": {
"failed": false,
"storedVersion": "v1beta1"
}
}
"status": {}
}

View File

@@ -226,10 +226,5 @@
}
]
},
"status": {
"conversion": {
"failed": false,
"storedVersion": "v1beta1"
}
}
"status": {}
}

View File

@@ -240,10 +240,5 @@
"title": "No Title",
"variables": []
},
"status": {
"conversion": {
"failed": false,
"storedVersion": "v1beta1"
}
}
"status": {}
}

View File

@@ -247,10 +247,5 @@
"title": "No Title",
"variables": []
},
"status": {
"conversion": {
"failed": false,
"storedVersion": "v1beta1"
}
}
"status": {}
}

View File

@@ -207,10 +207,5 @@
}
]
},
"status": {
"conversion": {
"failed": false,
"storedVersion": "v1beta1"
}
}
"status": {}
}

View File

@@ -211,10 +211,5 @@
}
]
},
"status": {
"conversion": {
"failed": false,
"storedVersion": "v1beta1"
}
}
"status": {}
}

View File

@@ -131,10 +131,5 @@
}
]
},
"status": {
"conversion": {
"failed": false,
"storedVersion": "v1beta1"
}
}
"status": {}
}

View File

@@ -134,10 +134,5 @@
}
]
},
"status": {
"conversion": {
"failed": false,
"storedVersion": "v1beta1"
}
}
"status": {}
}

View File

@@ -393,10 +393,5 @@
}
]
},
"status": {
"conversion": {
"failed": false,
"storedVersion": "v1beta1"
}
}
"status": {}
}

View File

@@ -406,10 +406,5 @@
}
]
},
"status": {
"conversion": {
"failed": false,
"storedVersion": "v1beta1"
}
}
"status": {}
}

View File

@@ -622,10 +622,5 @@
"title": "V28 Singlestat and Variable Properties Migration Test Dashboard",
"variables": []
},
"status": {
"conversion": {
"failed": false,
"storedVersion": "v1beta1"
}
}
"status": {}
}

View File

@@ -642,10 +642,5 @@
"title": "V28 Singlestat and Variable Properties Migration Test Dashboard",
"variables": []
},
"status": {
"conversion": {
"failed": false,
"storedVersion": "v1beta1"
}
}
"status": {}
}

View File

@@ -435,10 +435,5 @@
}
]
},
"status": {
"conversion": {
"failed": false,
"storedVersion": "v1beta1"
}
}
"status": {}
}

View File

@@ -458,10 +458,5 @@
}
]
},
"status": {
"conversion": {
"failed": false,
"storedVersion": "v1beta1"
}
}
"status": {}
}

View File

@@ -294,10 +294,5 @@
"title": "V3 No-Op Migration - but tests ensuring panel IDs are unique",
"variables": []
},
"status": {
"conversion": {
"failed": false,
"storedVersion": "v1beta1"
}
}
"status": {}
}

View File

@@ -303,10 +303,5 @@
"title": "V3 No-Op Migration - but tests ensuring panel IDs are unique",
"variables": []
},
"status": {
"conversion": {
"failed": false,
"storedVersion": "v1beta1"
}
}
"status": {}
}

View File

@@ -689,10 +689,5 @@
"title": "V30 Value Mappings and Tooltip Options Migration Test Dashboard",
"variables": []
},
"status": {
"conversion": {
"failed": false,
"storedVersion": "v1beta1"
}
}
"status": {}
}

View File

@@ -705,10 +705,5 @@
"title": "V30 Value Mappings and Tooltip Options Migration Test Dashboard",
"variables": []
},
"status": {
"conversion": {
"failed": false,
"storedVersion": "v1beta1"
}
}
"status": {}
}

View File

@@ -669,10 +669,5 @@
"title": "V31 LabelsToFields Merge Migration Test Dashboard",
"variables": []
},
"status": {
"conversion": {
"failed": false,
"storedVersion": "v1beta1"
}
}
"status": {}
}

View File

@@ -684,10 +684,5 @@
"title": "V31 LabelsToFields Merge Migration Test Dashboard",
"variables": []
},
"status": {
"conversion": {
"failed": false,
"storedVersion": "v1beta1"
}
}
"status": {}
}

View File

@@ -310,10 +310,5 @@
}
]
},
"status": {
"conversion": {
"failed": false,
"storedVersion": "v1beta1"
}
}
"status": {}
}

View File

@@ -320,10 +320,5 @@
}
]
},
"status": {
"conversion": {
"failed": false,
"storedVersion": "v1beta1"
}
}
"status": {}
}

View File

@@ -720,10 +720,5 @@
"title": "V33 Panel Datasource Name to Ref Test",
"variables": []
},
"status": {
"conversion": {
"failed": false,
"storedVersion": "v1beta1"
}
}
"status": {}
}

View File

@@ -746,10 +746,5 @@
"title": "V33 Panel Datasource Name to Ref Test",
"variables": []
},
"status": {
"conversion": {
"failed": false,
"storedVersion": "v1beta1"
}
}
"status": {}
}

View File

@@ -1900,10 +1900,5 @@
"title": "CloudWatch Multiple Statistics Test Dashboard",
"variables": []
},
"status": {
"conversion": {
"failed": false,
"storedVersion": "v1beta1"
}
}
"status": {}
}

View File

@@ -1964,10 +1964,5 @@
"title": "CloudWatch Multiple Statistics Test Dashboard",
"variables": []
},
"status": {
"conversion": {
"failed": false,
"storedVersion": "v1beta1"
}
}
"status": {}
}

View File

@@ -595,10 +595,5 @@
"title": "X-Axis Visibility Test Dashboard",
"variables": []
},
"status": {
"conversion": {
"failed": false,
"storedVersion": "v1beta1"
}
}
"status": {}
}

View File

@@ -612,10 +612,5 @@
"title": "X-Axis Visibility Test Dashboard",
"variables": []
},
"status": {
"conversion": {
"failed": false,
"storedVersion": "v1beta1"
}
}
"status": {}
}

View File

@@ -1029,10 +1029,5 @@
}
]
},
"status": {
"conversion": {
"failed": false,
"storedVersion": "v1beta1"
}
}
"status": {}
}

View File

@@ -1065,10 +1065,5 @@
}
]
},
"status": {
"conversion": {
"failed": false,
"storedVersion": "v1beta1"
}
}
"status": {}
}

View File

@@ -629,10 +629,5 @@
"title": "V37 Legend Normalization Test Dashboard",
"variables": []
},
"status": {
"conversion": {
"failed": false,
"storedVersion": "v1beta1"
}
}
"status": {}
}

View File

@@ -642,10 +642,5 @@
"title": "V37 Legend Normalization Test Dashboard",
"variables": []
},
"status": {
"conversion": {
"failed": false,
"storedVersion": "v1beta1"
}
}
"status": {}
}

View File

@@ -659,10 +659,5 @@
"title": "V38 Table Migration Comprehensive Test Dashboard",
"variables": []
},
"status": {
"conversion": {
"failed": false,
"storedVersion": "v1beta1"
}
}
"status": {}
}

View File

@@ -671,10 +671,5 @@
"title": "V38 Table Migration Comprehensive Test Dashboard",
"variables": []
},
"status": {
"conversion": {
"failed": false,
"storedVersion": "v1beta1"
}
}
"status": {}
}

View File

@@ -659,10 +659,5 @@
"title": "V38 Table Migration Test Dashboard",
"variables": []
},
"status": {
"conversion": {
"failed": false,
"storedVersion": "v1beta1"
}
}
"status": {}
}

View File

@@ -671,10 +671,5 @@
"title": "V38 Table Migration Test Dashboard",
"variables": []
},
"status": {
"conversion": {
"failed": false,
"storedVersion": "v1beta1"
}
}
"status": {}
}

View File

@@ -586,10 +586,5 @@
"title": "V39 TimeSeriesTable Transformation Migration Test Dashboard",
"variables": []
},
"status": {
"conversion": {
"failed": false,
"storedVersion": "v1beta1"
}
}
"status": {}
}

View File

@@ -596,10 +596,5 @@
"title": "V39 TimeSeriesTable Transformation Migration Test Dashboard",
"variables": []
},
"status": {
"conversion": {
"failed": false,
"storedVersion": "v1beta1"
}
}
"status": {}
}

View File

@@ -237,10 +237,5 @@
"title": "V4 No-Op Migration Test",
"variables": []
},
"status": {
"conversion": {
"failed": false,
"storedVersion": "v1beta1"
}
}
"status": {}
}

View File

@@ -244,10 +244,5 @@
"title": "V4 No-Op Migration Test",
"variables": []
},
"status": {
"conversion": {
"failed": false,
"storedVersion": "v1beta1"
}
}
"status": {}
}

View File

@@ -64,10 +64,5 @@
"title": "Empty String Refresh Test Dashboard",
"variables": []
},
"status": {
"conversion": {
"failed": false,
"storedVersion": "v1beta1"
}
}
"status": {}
}

View File

@@ -65,10 +65,5 @@
"title": "Empty String Refresh Test Dashboard",
"variables": []
},
"status": {
"conversion": {
"failed": false,
"storedVersion": "v1beta1"
}
}
"status": {}
}

View File

@@ -64,10 +64,5 @@
"title": "Boolean False Refresh Test Dashboard",
"variables": []
},
"status": {
"conversion": {
"failed": false,
"storedVersion": "v1beta1"
}
}
"status": {}
}

View File

@@ -65,10 +65,5 @@
"title": "Boolean False Refresh Test Dashboard",
"variables": []
},
"status": {
"conversion": {
"failed": false,
"storedVersion": "v1beta1"
}
}
"status": {}
}

View File

@@ -64,10 +64,5 @@
"title": "Refresh Not Set Test Dashboard",
"variables": []
},
"status": {
"conversion": {
"failed": false,
"storedVersion": "v1beta1"
}
}
"status": {}
}

View File

@@ -65,10 +65,5 @@
"title": "Refresh Not Set Test Dashboard",
"variables": []
},
"status": {
"conversion": {
"failed": false,
"storedVersion": "v1beta1"
}
}
"status": {}
}

View File

@@ -64,10 +64,5 @@
"title": "Numeric Refresh Test Dashboard",
"variables": []
},
"status": {
"conversion": {
"failed": false,
"storedVersion": "v1beta1"
}
}
"status": {}
}

View File

@@ -65,10 +65,5 @@
"title": "Numeric Refresh Test Dashboard",
"variables": []
},
"status": {
"conversion": {
"failed": false,
"storedVersion": "v1beta1"
}
}
"status": {}
}

Some files were not shown because too many files have changed in this diff Show More