Compare commits

..

1 Commits

Author SHA1 Message Date
Steve Simpson
20957297d0 Alerting: Remove Dummy kind form historian app.
This kind was only needed as a workaround, with the new app-sdk, and other fixes
in Grafana, we don't need it anymore.
2025-12-10 19:41:28 +01:00
537 changed files with 2962 additions and 9343 deletions

View File

@@ -9,18 +9,7 @@ manifest: {
groupOverride: "historian.alerting.grafana.app"
versions: {
"v0alpha1": {
kinds: [dummyv0alpha1]
routes: v0alpha1.routes
}
}
}
dummyv0alpha1: {
kind: "Dummy"
schema: {
// Spec is the schema of our resource. The spec should include all the user-editable information for the kind.
spec: {
dummyField: int
}
}
}

View File

@@ -1,18 +0,0 @@
package v0alpha1
import "k8s.io/apimachinery/pkg/runtime/schema"
const (
// APIGroup is the API group used by all kinds in this package
APIGroup = "historian.alerting.grafana.app"
// APIVersion is the API version used by all kinds in this package
APIVersion = "v0alpha1"
)
var (
// GroupVersion is a schema.GroupVersion consisting of the Group and Version constants for this package
GroupVersion = schema.GroupVersion{
Group: APIGroup,
Version: APIVersion,
}
)

View File

@@ -1,99 +0,0 @@
package v0alpha1
import (
"context"
"github.com/grafana/grafana-app-sdk/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
type DummyClient struct {
client *resource.TypedClient[*Dummy, *DummyList]
}
func NewDummyClient(client resource.Client) *DummyClient {
return &DummyClient{
client: resource.NewTypedClient[*Dummy, *DummyList](client, DummyKind()),
}
}
func NewDummyClientFromGenerator(generator resource.ClientGenerator) (*DummyClient, error) {
c, err := generator.ClientFor(DummyKind())
if err != nil {
return nil, err
}
return NewDummyClient(c), nil
}
func (c *DummyClient) Get(ctx context.Context, identifier resource.Identifier) (*Dummy, error) {
return c.client.Get(ctx, identifier)
}
func (c *DummyClient) List(ctx context.Context, namespace string, opts resource.ListOptions) (*DummyList, error) {
return c.client.List(ctx, namespace, opts)
}
func (c *DummyClient) ListAll(ctx context.Context, namespace string, opts resource.ListOptions) (*DummyList, error) {
resp, err := c.client.List(ctx, namespace, resource.ListOptions{
ResourceVersion: opts.ResourceVersion,
Limit: opts.Limit,
LabelFilters: opts.LabelFilters,
FieldSelectors: opts.FieldSelectors,
})
if err != nil {
return nil, err
}
for resp.GetContinue() != "" {
page, err := c.client.List(ctx, namespace, resource.ListOptions{
Continue: resp.GetContinue(),
ResourceVersion: opts.ResourceVersion,
Limit: opts.Limit,
LabelFilters: opts.LabelFilters,
FieldSelectors: opts.FieldSelectors,
})
if err != nil {
return nil, err
}
resp.SetContinue(page.GetContinue())
resp.SetResourceVersion(page.GetResourceVersion())
resp.SetItems(append(resp.GetItems(), page.GetItems()...))
}
return resp, nil
}
func (c *DummyClient) Create(ctx context.Context, obj *Dummy, opts resource.CreateOptions) (*Dummy, error) {
// Make sure apiVersion and kind are set
obj.APIVersion = GroupVersion.Identifier()
obj.Kind = DummyKind().Kind()
return c.client.Create(ctx, obj, opts)
}
func (c *DummyClient) Update(ctx context.Context, obj *Dummy, opts resource.UpdateOptions) (*Dummy, error) {
return c.client.Update(ctx, obj, opts)
}
func (c *DummyClient) Patch(ctx context.Context, identifier resource.Identifier, req resource.PatchRequest, opts resource.PatchOptions) (*Dummy, error) {
return c.client.Patch(ctx, identifier, req, opts)
}
func (c *DummyClient) UpdateStatus(ctx context.Context, identifier resource.Identifier, newStatus DummyStatus, opts resource.UpdateOptions) (*Dummy, error) {
return c.client.Update(ctx, &Dummy{
TypeMeta: metav1.TypeMeta{
Kind: DummyKind().Kind(),
APIVersion: GroupVersion.Identifier(),
},
ObjectMeta: metav1.ObjectMeta{
ResourceVersion: opts.ResourceVersion,
Namespace: identifier.Namespace,
Name: identifier.Name,
},
Status: newStatus,
}, resource.UpdateOptions{
Subresource: "status",
ResourceVersion: opts.ResourceVersion,
})
}
func (c *DummyClient) Delete(ctx context.Context, identifier resource.Identifier, opts resource.DeleteOptions) error {
return c.client.Delete(ctx, identifier, opts)
}

View File

@@ -1,28 +0,0 @@
//
// Code generated by grafana-app-sdk. DO NOT EDIT.
//
package v0alpha1
import (
"encoding/json"
"io"
"github.com/grafana/grafana-app-sdk/resource"
)
// DummyJSONCodec is an implementation of resource.Codec for kubernetes JSON encoding
type DummyJSONCodec struct{}
// Read reads JSON-encoded bytes from `reader` and unmarshals them into `into`
func (*DummyJSONCodec) Read(reader io.Reader, into resource.Object) error {
return json.NewDecoder(reader).Decode(into)
}
// Write writes JSON-encoded bytes into `writer` marshaled from `from`
func (*DummyJSONCodec) Write(writer io.Writer, from resource.Object) error {
return json.NewEncoder(writer).Encode(from)
}
// Interface compliance checks
var _ resource.Codec = &DummyJSONCodec{}

View File

@@ -1,31 +0,0 @@
// Code generated - EDITING IS FUTILE. DO NOT EDIT.
package v0alpha1
import (
time "time"
)
// metadata contains embedded CommonMetadata and can be extended with custom string fields
// TODO: use CommonMetadata instead of redefining here; currently needs to be defined here
// without external reference as using the CommonMetadata reference breaks thema codegen.
type DummyMetadata struct {
UpdateTimestamp time.Time `json:"updateTimestamp"`
CreatedBy string `json:"createdBy"`
Uid string `json:"uid"`
CreationTimestamp time.Time `json:"creationTimestamp"`
DeletionTimestamp *time.Time `json:"deletionTimestamp,omitempty"`
Finalizers []string `json:"finalizers"`
ResourceVersion string `json:"resourceVersion"`
Generation int64 `json:"generation"`
UpdatedBy string `json:"updatedBy"`
Labels map[string]string `json:"labels"`
}
// NewDummyMetadata creates a new DummyMetadata object.
func NewDummyMetadata() *DummyMetadata {
return &DummyMetadata{
Finalizers: []string{},
Labels: map[string]string{},
}
}

View File

@@ -1,319 +0,0 @@
//
// Code generated by grafana-app-sdk. DO NOT EDIT.
//
package v0alpha1
import (
"fmt"
"github.com/grafana/grafana-app-sdk/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/types"
"time"
)
// +k8s:openapi-gen=true
type Dummy struct {
metav1.TypeMeta `json:",inline" yaml:",inline"`
metav1.ObjectMeta `json:"metadata" yaml:"metadata"`
// Spec is the spec of the Dummy
Spec DummySpec `json:"spec" yaml:"spec"`
Status DummyStatus `json:"status" yaml:"status"`
}
func (o *Dummy) GetSpec() any {
return o.Spec
}
func (o *Dummy) SetSpec(spec any) error {
cast, ok := spec.(DummySpec)
if !ok {
return fmt.Errorf("cannot set spec type %#v, not of type Spec", spec)
}
o.Spec = cast
return nil
}
func (o *Dummy) GetSubresources() map[string]any {
return map[string]any{
"status": o.Status,
}
}
func (o *Dummy) GetSubresource(name string) (any, bool) {
switch name {
case "status":
return o.Status, true
default:
return nil, false
}
}
func (o *Dummy) SetSubresource(name string, value any) error {
switch name {
case "status":
cast, ok := value.(DummyStatus)
if !ok {
return fmt.Errorf("cannot set status type %#v, not of type DummyStatus", value)
}
o.Status = cast
return nil
default:
return fmt.Errorf("subresource '%s' does not exist", name)
}
}
func (o *Dummy) GetStaticMetadata() resource.StaticMetadata {
gvk := o.GroupVersionKind()
return resource.StaticMetadata{
Name: o.ObjectMeta.Name,
Namespace: o.ObjectMeta.Namespace,
Group: gvk.Group,
Version: gvk.Version,
Kind: gvk.Kind,
}
}
func (o *Dummy) SetStaticMetadata(metadata resource.StaticMetadata) {
o.Name = metadata.Name
o.Namespace = metadata.Namespace
o.SetGroupVersionKind(schema.GroupVersionKind{
Group: metadata.Group,
Version: metadata.Version,
Kind: metadata.Kind,
})
}
func (o *Dummy) GetCommonMetadata() resource.CommonMetadata {
dt := o.DeletionTimestamp
var deletionTimestamp *time.Time
if dt != nil {
deletionTimestamp = &dt.Time
}
// Legacy ExtraFields support
extraFields := make(map[string]any)
if o.Annotations != nil {
extraFields["annotations"] = o.Annotations
}
if o.ManagedFields != nil {
extraFields["managedFields"] = o.ManagedFields
}
if o.OwnerReferences != nil {
extraFields["ownerReferences"] = o.OwnerReferences
}
return resource.CommonMetadata{
UID: string(o.UID),
ResourceVersion: o.ResourceVersion,
Generation: o.Generation,
Labels: o.Labels,
CreationTimestamp: o.CreationTimestamp.Time,
DeletionTimestamp: deletionTimestamp,
Finalizers: o.Finalizers,
UpdateTimestamp: o.GetUpdateTimestamp(),
CreatedBy: o.GetCreatedBy(),
UpdatedBy: o.GetUpdatedBy(),
ExtraFields: extraFields,
}
}
func (o *Dummy) SetCommonMetadata(metadata resource.CommonMetadata) {
o.UID = types.UID(metadata.UID)
o.ResourceVersion = metadata.ResourceVersion
o.Generation = metadata.Generation
o.Labels = metadata.Labels
o.CreationTimestamp = metav1.NewTime(metadata.CreationTimestamp)
if metadata.DeletionTimestamp != nil {
dt := metav1.NewTime(*metadata.DeletionTimestamp)
o.DeletionTimestamp = &dt
} else {
o.DeletionTimestamp = nil
}
o.Finalizers = metadata.Finalizers
if o.Annotations == nil {
o.Annotations = make(map[string]string)
}
if !metadata.UpdateTimestamp.IsZero() {
o.SetUpdateTimestamp(metadata.UpdateTimestamp)
}
if metadata.CreatedBy != "" {
o.SetCreatedBy(metadata.CreatedBy)
}
if metadata.UpdatedBy != "" {
o.SetUpdatedBy(metadata.UpdatedBy)
}
// Legacy support for setting Annotations, ManagedFields, and OwnerReferences via ExtraFields
if metadata.ExtraFields != nil {
if annotations, ok := metadata.ExtraFields["annotations"]; ok {
if cast, ok := annotations.(map[string]string); ok {
o.Annotations = cast
}
}
if managedFields, ok := metadata.ExtraFields["managedFields"]; ok {
if cast, ok := managedFields.([]metav1.ManagedFieldsEntry); ok {
o.ManagedFields = cast
}
}
if ownerReferences, ok := metadata.ExtraFields["ownerReferences"]; ok {
if cast, ok := ownerReferences.([]metav1.OwnerReference); ok {
o.OwnerReferences = cast
}
}
}
}
func (o *Dummy) GetCreatedBy() string {
if o.ObjectMeta.Annotations == nil {
o.ObjectMeta.Annotations = make(map[string]string)
}
return o.ObjectMeta.Annotations["grafana.com/createdBy"]
}
func (o *Dummy) SetCreatedBy(createdBy string) {
if o.ObjectMeta.Annotations == nil {
o.ObjectMeta.Annotations = make(map[string]string)
}
o.ObjectMeta.Annotations["grafana.com/createdBy"] = createdBy
}
func (o *Dummy) GetUpdateTimestamp() time.Time {
if o.ObjectMeta.Annotations == nil {
o.ObjectMeta.Annotations = make(map[string]string)
}
parsed, _ := time.Parse(time.RFC3339, o.ObjectMeta.Annotations["grafana.com/updateTimestamp"])
return parsed
}
func (o *Dummy) SetUpdateTimestamp(updateTimestamp time.Time) {
if o.ObjectMeta.Annotations == nil {
o.ObjectMeta.Annotations = make(map[string]string)
}
o.ObjectMeta.Annotations["grafana.com/updateTimestamp"] = updateTimestamp.Format(time.RFC3339)
}
func (o *Dummy) GetUpdatedBy() string {
if o.ObjectMeta.Annotations == nil {
o.ObjectMeta.Annotations = make(map[string]string)
}
return o.ObjectMeta.Annotations["grafana.com/updatedBy"]
}
func (o *Dummy) SetUpdatedBy(updatedBy string) {
if o.ObjectMeta.Annotations == nil {
o.ObjectMeta.Annotations = make(map[string]string)
}
o.ObjectMeta.Annotations["grafana.com/updatedBy"] = updatedBy
}
func (o *Dummy) Copy() resource.Object {
return resource.CopyObject(o)
}
func (o *Dummy) DeepCopyObject() runtime.Object {
return o.Copy()
}
func (o *Dummy) DeepCopy() *Dummy {
cpy := &Dummy{}
o.DeepCopyInto(cpy)
return cpy
}
func (o *Dummy) DeepCopyInto(dst *Dummy) {
dst.TypeMeta.APIVersion = o.TypeMeta.APIVersion
dst.TypeMeta.Kind = o.TypeMeta.Kind
o.ObjectMeta.DeepCopyInto(&dst.ObjectMeta)
o.Spec.DeepCopyInto(&dst.Spec)
o.Status.DeepCopyInto(&dst.Status)
}
// Interface compliance compile-time check
var _ resource.Object = &Dummy{}
// +k8s:openapi-gen=true
type DummyList struct {
metav1.TypeMeta `json:",inline" yaml:",inline"`
metav1.ListMeta `json:"metadata" yaml:"metadata"`
Items []Dummy `json:"items" yaml:"items"`
}
func (o *DummyList) DeepCopyObject() runtime.Object {
return o.Copy()
}
func (o *DummyList) Copy() resource.ListObject {
cpy := &DummyList{
TypeMeta: o.TypeMeta,
Items: make([]Dummy, len(o.Items)),
}
o.ListMeta.DeepCopyInto(&cpy.ListMeta)
for i := 0; i < len(o.Items); i++ {
if item, ok := o.Items[i].Copy().(*Dummy); ok {
cpy.Items[i] = *item
}
}
return cpy
}
func (o *DummyList) GetItems() []resource.Object {
items := make([]resource.Object, len(o.Items))
for i := 0; i < len(o.Items); i++ {
items[i] = &o.Items[i]
}
return items
}
func (o *DummyList) SetItems(items []resource.Object) {
o.Items = make([]Dummy, len(items))
for i := 0; i < len(items); i++ {
o.Items[i] = *items[i].(*Dummy)
}
}
func (o *DummyList) DeepCopy() *DummyList {
cpy := &DummyList{}
o.DeepCopyInto(cpy)
return cpy
}
func (o *DummyList) DeepCopyInto(dst *DummyList) {
resource.CopyObjectInto(dst, o)
}
// Interface compliance compile-time check
var _ resource.ListObject = &DummyList{}
// Copy methods for all subresource types
// DeepCopy creates a full deep copy of Spec
func (s *DummySpec) DeepCopy() *DummySpec {
cpy := &DummySpec{}
s.DeepCopyInto(cpy)
return cpy
}
// DeepCopyInto deep copies Spec into another Spec object
func (s *DummySpec) DeepCopyInto(dst *DummySpec) {
resource.CopyObjectInto(dst, s)
}
// DeepCopy creates a full deep copy of DummyStatus
func (s *DummyStatus) DeepCopy() *DummyStatus {
cpy := &DummyStatus{}
s.DeepCopyInto(cpy)
return cpy
}
// DeepCopyInto deep copies DummyStatus into another DummyStatus object
func (s *DummyStatus) DeepCopyInto(dst *DummyStatus) {
resource.CopyObjectInto(dst, s)
}

View File

@@ -1,34 +0,0 @@
//
// Code generated by grafana-app-sdk. DO NOT EDIT.
//
package v0alpha1
import (
"github.com/grafana/grafana-app-sdk/resource"
)
// schema is unexported to prevent accidental overwrites
var (
schemaDummy = resource.NewSimpleSchema("historian.alerting.grafana.app", "v0alpha1", &Dummy{}, &DummyList{}, resource.WithKind("Dummy"),
resource.WithPlural("dummys"), resource.WithScope(resource.NamespacedScope))
kindDummy = resource.Kind{
Schema: schemaDummy,
Codecs: map[resource.KindEncoding]resource.Codec{
resource.KindEncodingJSON: &DummyJSONCodec{},
},
}
)
// Kind returns a resource.Kind for this Schema with a JSON codec
func DummyKind() resource.Kind {
return kindDummy
}
// Schema returns a resource.SimpleSchema representation of Dummy
func DummySchema() *resource.SimpleSchema {
return schemaDummy
}
// Interface compliance checks
var _ resource.Schema = kindDummy

View File

@@ -1,14 +0,0 @@
// Code generated - EDITING IS FUTILE. DO NOT EDIT.
package v0alpha1
// Spec is the schema of our resource. The spec should include all the user-editable information for the kind.
// +k8s:openapi-gen=true
type DummySpec struct {
DummyField int64 `json:"dummyField"`
}
// NewDummySpec creates a new DummySpec object.
func NewDummySpec() *DummySpec {
return &DummySpec{}
}

View File

@@ -1,44 +0,0 @@
// Code generated - EDITING IS FUTILE. DO NOT EDIT.
package v0alpha1
// +k8s:openapi-gen=true
type DummystatusOperatorState struct {
// lastEvaluation is the ResourceVersion last evaluated
LastEvaluation string `json:"lastEvaluation"`
// state describes the state of the lastEvaluation.
// It is limited to three possible states for machine evaluation.
State DummyStatusOperatorStateState `json:"state"`
// descriptiveState is an optional more descriptive state field which has no requirements on format
DescriptiveState *string `json:"descriptiveState,omitempty"`
// details contains any extra information that is operator-specific
Details map[string]interface{} `json:"details,omitempty"`
}
// NewDummystatusOperatorState creates a new DummystatusOperatorState object.
func NewDummystatusOperatorState() *DummystatusOperatorState {
return &DummystatusOperatorState{}
}
// +k8s:openapi-gen=true
type DummyStatus struct {
// operatorStates is a map of operator ID to operator state evaluations.
// Any operator which consumes this kind SHOULD add its state evaluation information to this field.
OperatorStates map[string]DummystatusOperatorState `json:"operatorStates,omitempty"`
// additionalFields is reserved for future use
AdditionalFields map[string]interface{} `json:"additionalFields,omitempty"`
}
// NewDummyStatus creates a new DummyStatus object.
func NewDummyStatus() *DummyStatus {
return &DummyStatus{}
}
// +k8s:openapi-gen=true
type DummyStatusOperatorStateState string
const (
DummyStatusOperatorStateStateSuccess DummyStatusOperatorStateState = "success"
DummyStatusOperatorStateStateInProgress DummyStatusOperatorStateState = "in_progress"
DummyStatusOperatorStateStateFailed DummyStatusOperatorStateState = "failed"
)

View File

@@ -6,7 +6,6 @@
package apis
import (
"encoding/json"
"fmt"
"strings"
@@ -19,12 +18,6 @@ import (
v0alpha1 "github.com/grafana/grafana/apps/alerting/historian/pkg/apis/alertinghistorian/v0alpha1"
)
var (
rawSchemaDummyv0alpha1 = []byte(`{"Dummy":{"properties":{"spec":{"$ref":"#/components/schemas/spec"},"status":{"$ref":"#/components/schemas/status"}},"required":["spec"]},"OperatorState":{"additionalProperties":false,"properties":{"descriptiveState":{"description":"descriptiveState is an optional more descriptive state field which has no requirements on format","type":"string"},"details":{"additionalProperties":{"additionalProperties":{},"type":"object"},"description":"details contains any extra information that is operator-specific","type":"object"},"lastEvaluation":{"description":"lastEvaluation is the ResourceVersion last evaluated","type":"string"},"state":{"description":"state describes the state of the lastEvaluation.\nIt is limited to three possible states for machine evaluation.","enum":["success","in_progress","failed"],"type":"string"}},"required":["lastEvaluation","state"],"type":"object"},"spec":{"additionalProperties":false,"description":"Spec is the schema of our resource. The spec should include all the user-editable information for the kind.","properties":{"dummyField":{"type":"integer"}},"required":["dummyField"],"type":"object"},"status":{"additionalProperties":false,"properties":{"additionalFields":{"additionalProperties":{"additionalProperties":{},"type":"object"},"description":"additionalFields is reserved for future use","type":"object"},"operatorStates":{"additionalProperties":{"$ref":"#/components/schemas/OperatorState"},"description":"operatorStates is a map of operator ID to operator state evaluations.\nAny operator which consumes this kind SHOULD add its state evaluation information to this field.","type":"object"}},"type":"object"}}`)
versionSchemaDummyv0alpha1 app.VersionSchema
_ = json.Unmarshal(rawSchemaDummyv0alpha1, &versionSchemaDummyv0alpha1)
)
var appManifestData = app.ManifestData{
AppName: "alerting-historian",
Group: "historian.alerting.grafana.app",
@@ -33,15 +26,7 @@ var appManifestData = app.ManifestData{
{
Name: "v0alpha1",
Served: true,
Kinds: []app.ManifestVersionKind{
{
Kind: "Dummy",
Plural: "Dummys",
Scope: "Namespaced",
Conversion: false,
Schema: &versionSchemaDummyv0alpha1,
},
},
Kinds: []app.ManifestVersionKind{},
Routes: app.ManifestVersionRoutes{
Namespaced: map[string]spec3.PathProps{
"/alertstate/history": {
@@ -181,6 +166,13 @@ var appManifestData = app.ManifestData{
"entries": {
SchemaProps: spec.SchemaProps{
Type: []string{"array"},
Items: &spec.SchemaOrArray{
Schema: &spec.Schema{
SchemaProps: spec.SchemaProps{
Ref: spec.MustCreateRef("#/components/schemas/createNotificationqueryNotificationEntry"),
}},
},
},
},
},
@@ -235,6 +227,13 @@ var appManifestData = app.ManifestData{
"createNotificationqueryMatchers": {
SchemaProps: spec.SchemaProps{
Type: []string{"array"},
Items: &spec.SchemaOrArray{
Schema: &spec.Schema{
SchemaProps: spec.SchemaProps{
Ref: spec.MustCreateRef("#/components/schemas/createNotificationqueryMatcher"),
}},
},
},
},
"createNotificationqueryNotificationEntry": {
@@ -245,6 +244,13 @@ var appManifestData = app.ManifestData{
SchemaProps: spec.SchemaProps{
Type: []string{"array"},
Description: "Alerts are the alerts grouped into the notification.",
Items: &spec.SchemaOrArray{
Schema: &spec.Schema{
SchemaProps: spec.SchemaProps{
Ref: spec.MustCreateRef("#/components/schemas/createNotificationqueryNotificationEntryAlert"),
}},
},
},
},
"duration": {
@@ -420,9 +426,7 @@ func RemoteManifest() app.Manifest {
return app.NewAPIServerManifest("alerting-historian")
}
var kindVersionToGoType = map[string]resource.Kind{
"Dummy/v0alpha1": v0alpha1.DummyKind(),
}
var kindVersionToGoType = map[string]resource.Kind{}
// ManifestGoTypeAssociator returns the associated resource.Kind instance for a given Kind and Version, if one exists.
// If there is no association for the provided Kind and Version, exists will return false.

View File

@@ -12,7 +12,6 @@ import (
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/grafana/grafana/apps/alerting/historian/pkg/apis/alertinghistorian/v0alpha1"
"github.com/grafana/grafana/apps/alerting/historian/pkg/app/config"
"github.com/grafana/grafana/apps/alerting/historian/pkg/app/notification"
)
@@ -47,12 +46,6 @@ func New(cfg app.Config) (app.App, error) {
}: notificationHandler.QueryHandler,
},
},
// TODO: Remove when SDK is fixed.
ManagedKinds: []simple.AppManagedKind{
{
Kind: v0alpha1.DummyKind(),
},
},
}
a, err := simple.NewApp(simpleConfig)

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

@@ -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

@@ -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": {}
}

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