Merge remote-tracking branch 'origin/main' into ds-apiserver-with-configs
This commit is contained in:
@@ -19,6 +19,9 @@ update-app-sdk: ## Update the Grafana App SDK dependency in go.mod
|
|||||||
go mod tidy
|
go mod tidy
|
||||||
|
|
||||||
.PHONY: generate
|
.PHONY: generate
|
||||||
generate: install-app-sdk update-app-sdk
|
generate: do-generate ## Run Grafana App SDK code generation
|
||||||
|
|
||||||
|
.PHONY: do-generate
|
||||||
|
do-generate: install-app-sdk update-app-sdk
|
||||||
## --defencoding=none and noschemasinmanifest are needed to avoid infinite loop while generating recursive models (see routingtree.cue)
|
## --defencoding=none and noschemasinmanifest are needed to avoid infinite loop while generating recursive models (see routingtree.cue)
|
||||||
@$(APP_SDK_BIN) generate --grouping=group --gogenpath=./pkg/apis --defencoding=none --postprocess --noschemasinmanifest
|
@$(APP_SDK_BIN) generate --grouping=group --gogenpath=./pkg/apis --defencoding=none --postprocess --noschemasinmanifest
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
APP_SDK_VERSION := v0.39.2
|
APP_SDK_VERSION := v0.39.0
|
||||||
APP_SDK_DIR := $(shell go env GOPATH)/bin/app-sdk-$(APP_SDK_VERSION)
|
APP_SDK_DIR := $(shell go env GOPATH)/bin/app-sdk-$(APP_SDK_VERSION)
|
||||||
APP_SDK_BIN := $(APP_SDK_DIR)/grafana-app-sdk
|
APP_SDK_BIN := $(APP_SDK_DIR)/grafana-app-sdk
|
||||||
|
|
||||||
|
|||||||
@@ -111,8 +111,6 @@ DashboardLink: {
|
|||||||
keepTime: bool | *false
|
keepTime: bool | *false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Keeping this for backwards compatibility for GroupByVariableSpec and AdhocVariableSpec
|
|
||||||
// This type is widely used in the codebase and changing it will have a big impact
|
|
||||||
DataSourceRef: {
|
DataSourceRef: {
|
||||||
// The plugin type-id
|
// The plugin type-id
|
||||||
type?: string
|
type?: string
|
||||||
@@ -387,14 +385,15 @@ VizConfigKind: {
|
|||||||
}
|
}
|
||||||
|
|
||||||
AnnotationQuerySpec: {
|
AnnotationQuerySpec: {
|
||||||
query: DataQueryKind
|
datasource?: DataSourceRef
|
||||||
|
query?: DataQueryKind
|
||||||
enable: bool
|
enable: bool
|
||||||
hide: bool
|
hide: bool
|
||||||
iconColor: string
|
iconColor: string
|
||||||
name: string
|
name: string
|
||||||
builtIn?: bool | *false
|
builtIn?: bool | *false
|
||||||
filter?: AnnotationPanelFilter
|
filter?: AnnotationPanelFilter
|
||||||
legacyOptions?: [string]: _ // Catch-all field for datasource-specific properties. Should not be available in as code tooling.
|
legacyOptions?: [string]: _ //Catch-all field for datasource-specific properties
|
||||||
}
|
}
|
||||||
|
|
||||||
AnnotationQueryKind: {
|
AnnotationQueryKind: {
|
||||||
@@ -413,19 +412,15 @@ QueryOptionsSpec: {
|
|||||||
}
|
}
|
||||||
|
|
||||||
DataQueryKind: {
|
DataQueryKind: {
|
||||||
kind: "DataQuery"
|
// The kind of a DataQueryKind is the datasource type
|
||||||
group: string
|
kind: string
|
||||||
version: string | *"v0"
|
|
||||||
// New type for datasource reference
|
|
||||||
// Not creating a new type until we figure out how to handle DS refs for group by, adhoc, and every place that uses DataSourceRef in TS.
|
|
||||||
datasource?: {
|
|
||||||
name?: string
|
|
||||||
}
|
|
||||||
spec: [string]: _
|
spec: [string]: _
|
||||||
}
|
}
|
||||||
|
|
||||||
PanelQuerySpec: {
|
PanelQuerySpec: {
|
||||||
query: DataQueryKind
|
query: DataQueryKind
|
||||||
|
datasource?: DataSourceRef
|
||||||
|
|
||||||
refId: string
|
refId: string
|
||||||
hidden: bool
|
hidden: bool
|
||||||
}
|
}
|
||||||
@@ -728,6 +723,7 @@ QueryVariableSpec: {
|
|||||||
refresh: VariableRefresh
|
refresh: VariableRefresh
|
||||||
skipUrlSync: bool | *false
|
skipUrlSync: bool | *false
|
||||||
description?: string
|
description?: string
|
||||||
|
datasource?: DataSourceRef
|
||||||
query: DataQueryKind
|
query: DataQueryKind
|
||||||
regex: string | *""
|
regex: string | *""
|
||||||
sort: VariableSort
|
sort: VariableSort
|
||||||
|
|||||||
@@ -115,8 +115,6 @@ DashboardLink: {
|
|||||||
keepTime: bool | *false
|
keepTime: bool | *false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Keeping this for backwards compatibility for GroupByVariableSpec and AdhocVariableSpec
|
|
||||||
// This type is widely used in the codebase and changing it will have a big impact
|
|
||||||
DataSourceRef: {
|
DataSourceRef: {
|
||||||
// The plugin type-id
|
// The plugin type-id
|
||||||
type?: string
|
type?: string
|
||||||
@@ -391,14 +389,15 @@ VizConfigKind: {
|
|||||||
}
|
}
|
||||||
|
|
||||||
AnnotationQuerySpec: {
|
AnnotationQuerySpec: {
|
||||||
query: DataQueryKind
|
datasource?: DataSourceRef
|
||||||
|
query?: DataQueryKind
|
||||||
enable: bool
|
enable: bool
|
||||||
hide: bool
|
hide: bool
|
||||||
iconColor: string
|
iconColor: string
|
||||||
name: string
|
name: string
|
||||||
builtIn?: bool | *false
|
builtIn?: bool | *false
|
||||||
filter?: AnnotationPanelFilter
|
filter?: AnnotationPanelFilter
|
||||||
legacyOptions?: [string]: _ // Catch-all field for datasource-specific properties. Should not be available in as code tooling.
|
legacyOptions?: [string]: _ //Catch-all field for datasource-specific properties
|
||||||
}
|
}
|
||||||
|
|
||||||
AnnotationQueryKind: {
|
AnnotationQueryKind: {
|
||||||
@@ -417,19 +416,15 @@ QueryOptionsSpec: {
|
|||||||
}
|
}
|
||||||
|
|
||||||
DataQueryKind: {
|
DataQueryKind: {
|
||||||
kind: "DataQuery"
|
// The kind of a DataQueryKind is the datasource type
|
||||||
group: string
|
kind: string
|
||||||
version: string | *"v0"
|
|
||||||
// New type for datasource reference
|
|
||||||
// Not creating a new type until we figure out how to handle DS refs for group by, adhoc, and every place that uses DataSourceRef in TS.
|
|
||||||
datasource?: {
|
|
||||||
name?: string
|
|
||||||
}
|
|
||||||
spec: [string]: _
|
spec: [string]: _
|
||||||
}
|
}
|
||||||
|
|
||||||
PanelQuerySpec: {
|
PanelQuerySpec: {
|
||||||
query: DataQueryKind
|
query: DataQueryKind
|
||||||
|
datasource?: DataSourceRef
|
||||||
|
|
||||||
refId: string
|
refId: string
|
||||||
hidden: bool
|
hidden: bool
|
||||||
}
|
}
|
||||||
@@ -732,6 +727,7 @@ QueryVariableSpec: {
|
|||||||
refresh: VariableRefresh
|
refresh: VariableRefresh
|
||||||
skipUrlSync: bool | *false
|
skipUrlSync: bool | *false
|
||||||
description?: string
|
description?: string
|
||||||
|
datasource?: DataSourceRef
|
||||||
query: DataQueryKind
|
query: DataQueryKind
|
||||||
regex: string | *""
|
regex: string | *""
|
||||||
sort: VariableSort
|
sort: VariableSort
|
||||||
|
|||||||
@@ -23,42 +23,49 @@ func NewDashboardAnnotationQueryKind() *DashboardAnnotationQueryKind {
|
|||||||
|
|
||||||
// +k8s:openapi-gen=true
|
// +k8s:openapi-gen=true
|
||||||
type DashboardAnnotationQuerySpec struct {
|
type DashboardAnnotationQuerySpec struct {
|
||||||
Query DashboardDataQueryKind `json:"query"`
|
Datasource *DashboardDataSourceRef `json:"datasource,omitempty"`
|
||||||
Enable bool `json:"enable"`
|
Query *DashboardDataQueryKind `json:"query,omitempty"`
|
||||||
Hide bool `json:"hide"`
|
Enable bool `json:"enable"`
|
||||||
IconColor string `json:"iconColor"`
|
Hide bool `json:"hide"`
|
||||||
Name string `json:"name"`
|
IconColor string `json:"iconColor"`
|
||||||
BuiltIn *bool `json:"builtIn,omitempty"`
|
Name string `json:"name"`
|
||||||
Filter *DashboardAnnotationPanelFilter `json:"filter,omitempty"`
|
BuiltIn *bool `json:"builtIn,omitempty"`
|
||||||
// Catch-all field for datasource-specific properties. Should not be available in as code tooling.
|
Filter *DashboardAnnotationPanelFilter `json:"filter,omitempty"`
|
||||||
|
// Catch-all field for datasource-specific properties
|
||||||
LegacyOptions map[string]interface{} `json:"legacyOptions,omitempty"`
|
LegacyOptions map[string]interface{} `json:"legacyOptions,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewDashboardAnnotationQuerySpec creates a new DashboardAnnotationQuerySpec object.
|
// NewDashboardAnnotationQuerySpec creates a new DashboardAnnotationQuerySpec object.
|
||||||
func NewDashboardAnnotationQuerySpec() *DashboardAnnotationQuerySpec {
|
func NewDashboardAnnotationQuerySpec() *DashboardAnnotationQuerySpec {
|
||||||
return &DashboardAnnotationQuerySpec{
|
return &DashboardAnnotationQuerySpec{
|
||||||
Query: *NewDashboardDataQueryKind(),
|
|
||||||
BuiltIn: (func(input bool) *bool { return &input })(false),
|
BuiltIn: (func(input bool) *bool { return &input })(false),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// +k8s:openapi-gen=true
|
||||||
|
type DashboardDataSourceRef struct {
|
||||||
|
// The plugin type-id
|
||||||
|
Type *string `json:"type,omitempty"`
|
||||||
|
// Specific datasource instance
|
||||||
|
Uid *string `json:"uid,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewDashboardDataSourceRef creates a new DashboardDataSourceRef object.
|
||||||
|
func NewDashboardDataSourceRef() *DashboardDataSourceRef {
|
||||||
|
return &DashboardDataSourceRef{}
|
||||||
|
}
|
||||||
|
|
||||||
// +k8s:openapi-gen=true
|
// +k8s:openapi-gen=true
|
||||||
type DashboardDataQueryKind struct {
|
type DashboardDataQueryKind struct {
|
||||||
Kind string `json:"kind"`
|
// The kind of a DataQueryKind is the datasource type
|
||||||
Group string `json:"group"`
|
Kind string `json:"kind"`
|
||||||
Version string `json:"version"`
|
Spec map[string]interface{} `json:"spec"`
|
||||||
// New type for datasource reference
|
|
||||||
// Not creating a new type until we figure out how to handle DS refs for group by, adhoc, and every place that uses DataSourceRef in TS.
|
|
||||||
Datasource *DashboardV2alpha1DataQueryKindDatasource `json:"datasource,omitempty"`
|
|
||||||
Spec map[string]interface{} `json:"spec"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewDashboardDataQueryKind creates a new DashboardDataQueryKind object.
|
// NewDashboardDataQueryKind creates a new DashboardDataQueryKind object.
|
||||||
func NewDashboardDataQueryKind() *DashboardDataQueryKind {
|
func NewDashboardDataQueryKind() *DashboardDataQueryKind {
|
||||||
return &DashboardDataQueryKind{
|
return &DashboardDataQueryKind{
|
||||||
Kind: "DataQuery",
|
Spec: map[string]interface{}{},
|
||||||
Version: "v0",
|
|
||||||
Spec: map[string]interface{}{},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -192,9 +199,10 @@ func NewDashboardPanelQueryKind() *DashboardPanelQueryKind {
|
|||||||
|
|
||||||
// +k8s:openapi-gen=true
|
// +k8s:openapi-gen=true
|
||||||
type DashboardPanelQuerySpec struct {
|
type DashboardPanelQuerySpec struct {
|
||||||
Query DashboardDataQueryKind `json:"query"`
|
Query DashboardDataQueryKind `json:"query"`
|
||||||
RefId string `json:"refId"`
|
Datasource *DashboardDataSourceRef `json:"datasource,omitempty"`
|
||||||
Hidden bool `json:"hidden"`
|
RefId string `json:"refId"`
|
||||||
|
Hidden bool `json:"hidden"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewDashboardPanelQuerySpec creates a new DashboardPanelQuerySpec object.
|
// NewDashboardPanelQuerySpec creates a new DashboardPanelQuerySpec object.
|
||||||
@@ -755,9 +763,7 @@ type DashboardRepeatOptions struct {
|
|||||||
|
|
||||||
// NewDashboardRepeatOptions creates a new DashboardRepeatOptions object.
|
// NewDashboardRepeatOptions creates a new DashboardRepeatOptions object.
|
||||||
func NewDashboardRepeatOptions() *DashboardRepeatOptions {
|
func NewDashboardRepeatOptions() *DashboardRepeatOptions {
|
||||||
return &DashboardRepeatOptions{
|
return &DashboardRepeatOptions{}
|
||||||
Mode: DashboardRepeatMode,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// other repeat modes will be added in the future: label, frame
|
// other repeat modes will be added in the future: label, frame
|
||||||
@@ -932,9 +938,7 @@ type DashboardRowRepeatOptions struct {
|
|||||||
|
|
||||||
// NewDashboardRowRepeatOptions creates a new DashboardRowRepeatOptions object.
|
// NewDashboardRowRepeatOptions creates a new DashboardRowRepeatOptions object.
|
||||||
func NewDashboardRowRepeatOptions() *DashboardRowRepeatOptions {
|
func NewDashboardRowRepeatOptions() *DashboardRowRepeatOptions {
|
||||||
return &DashboardRowRepeatOptions{
|
return &DashboardRowRepeatOptions{}
|
||||||
Mode: DashboardRepeatMode,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// +k8s:openapi-gen=true
|
// +k8s:openapi-gen=true
|
||||||
@@ -1007,9 +1011,7 @@ type DashboardAutoGridRepeatOptions struct {
|
|||||||
|
|
||||||
// NewDashboardAutoGridRepeatOptions creates a new DashboardAutoGridRepeatOptions object.
|
// NewDashboardAutoGridRepeatOptions creates a new DashboardAutoGridRepeatOptions object.
|
||||||
func NewDashboardAutoGridRepeatOptions() *DashboardAutoGridRepeatOptions {
|
func NewDashboardAutoGridRepeatOptions() *DashboardAutoGridRepeatOptions {
|
||||||
return &DashboardAutoGridRepeatOptions{
|
return &DashboardAutoGridRepeatOptions{}
|
||||||
Mode: DashboardRepeatMode,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// +k8s:openapi-gen=true
|
// +k8s:openapi-gen=true
|
||||||
@@ -1075,9 +1077,7 @@ type DashboardTabRepeatOptions struct {
|
|||||||
|
|
||||||
// NewDashboardTabRepeatOptions creates a new DashboardTabRepeatOptions object.
|
// NewDashboardTabRepeatOptions creates a new DashboardTabRepeatOptions object.
|
||||||
func NewDashboardTabRepeatOptions() *DashboardTabRepeatOptions {
|
func NewDashboardTabRepeatOptions() *DashboardTabRepeatOptions {
|
||||||
return &DashboardTabRepeatOptions{
|
return &DashboardTabRepeatOptions{}
|
||||||
Mode: DashboardRepeatMode,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Links with references to other dashboards or external resources
|
// Links with references to other dashboards or external resources
|
||||||
@@ -1221,6 +1221,7 @@ type DashboardQueryVariableSpec struct {
|
|||||||
Refresh DashboardVariableRefresh `json:"refresh"`
|
Refresh DashboardVariableRefresh `json:"refresh"`
|
||||||
SkipUrlSync bool `json:"skipUrlSync"`
|
SkipUrlSync bool `json:"skipUrlSync"`
|
||||||
Description *string `json:"description,omitempty"`
|
Description *string `json:"description,omitempty"`
|
||||||
|
Datasource *DashboardDataSourceRef `json:"datasource,omitempty"`
|
||||||
Query DashboardDataQueryKind `json:"query"`
|
Query DashboardDataQueryKind `json:"query"`
|
||||||
Regex string `json:"regex"`
|
Regex string `json:"regex"`
|
||||||
Sort DashboardVariableSort `json:"sort"`
|
Sort DashboardVariableSort `json:"sort"`
|
||||||
@@ -1626,21 +1627,6 @@ func NewDashboardGroupByVariableSpec() *DashboardGroupByVariableSpec {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Keeping this for backwards compatibility for GroupByVariableSpec and AdhocVariableSpec
|
|
||||||
// This type is widely used in the codebase and changing it will have a big impact
|
|
||||||
// +k8s:openapi-gen=true
|
|
||||||
type DashboardDataSourceRef struct {
|
|
||||||
// The plugin type-id
|
|
||||||
Type *string `json:"type,omitempty"`
|
|
||||||
// Specific datasource instance
|
|
||||||
Uid *string `json:"uid,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewDashboardDataSourceRef creates a new DashboardDataSourceRef object.
|
|
||||||
func NewDashboardDataSourceRef() *DashboardDataSourceRef {
|
|
||||||
return &DashboardDataSourceRef{}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Adhoc variable kind
|
// Adhoc variable kind
|
||||||
// +k8s:openapi-gen=true
|
// +k8s:openapi-gen=true
|
||||||
type DashboardAdhocVariableKind struct {
|
type DashboardAdhocVariableKind struct {
|
||||||
@@ -1701,9 +1687,7 @@ type DashboardAdHocFilterWithLabels struct {
|
|||||||
|
|
||||||
// NewDashboardAdHocFilterWithLabels creates a new DashboardAdHocFilterWithLabels object.
|
// NewDashboardAdHocFilterWithLabels creates a new DashboardAdHocFilterWithLabels object.
|
||||||
func NewDashboardAdHocFilterWithLabels() *DashboardAdHocFilterWithLabels {
|
func NewDashboardAdHocFilterWithLabels() *DashboardAdHocFilterWithLabels {
|
||||||
return &DashboardAdHocFilterWithLabels{
|
return &DashboardAdHocFilterWithLabels{}
|
||||||
Origin: DashboardFilterOrigin,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Determine the origin of the adhoc variable filter
|
// Determine the origin of the adhoc variable filter
|
||||||
@@ -1774,16 +1758,6 @@ func NewDashboardSpec() *DashboardSpec {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// +k8s:openapi-gen=true
|
|
||||||
type DashboardV2alpha1DataQueryKindDatasource struct {
|
|
||||||
Name *string `json:"name,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewDashboardV2alpha1DataQueryKindDatasource creates a new DashboardV2alpha1DataQueryKindDatasource object.
|
|
||||||
func NewDashboardV2alpha1DataQueryKindDatasource() *DashboardV2alpha1DataQueryKindDatasource {
|
|
||||||
return &DashboardV2alpha1DataQueryKindDatasource{}
|
|
||||||
}
|
|
||||||
|
|
||||||
// +k8s:openapi-gen=true
|
// +k8s:openapi-gen=true
|
||||||
type DashboardV2alpha1FieldConfigSourceOverrides struct {
|
type DashboardV2alpha1FieldConfigSourceOverrides struct {
|
||||||
Matcher DashboardMatcherConfig `json:"matcher"`
|
Matcher DashboardMatcherConfig `json:"matcher"`
|
||||||
|
|||||||
@@ -109,7 +109,6 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA
|
|||||||
"github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1.DashboardTimeRangeOption": schema_pkg_apis_dashboard_v2alpha1_DashboardTimeRangeOption(ref),
|
"github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1.DashboardTimeRangeOption": schema_pkg_apis_dashboard_v2alpha1_DashboardTimeRangeOption(ref),
|
||||||
"github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1.DashboardTimeSettingsSpec": schema_pkg_apis_dashboard_v2alpha1_DashboardTimeSettingsSpec(ref),
|
"github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1.DashboardTimeSettingsSpec": schema_pkg_apis_dashboard_v2alpha1_DashboardTimeSettingsSpec(ref),
|
||||||
"github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1.DashboardTransformationKind": schema_pkg_apis_dashboard_v2alpha1_DashboardTransformationKind(ref),
|
"github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1.DashboardTransformationKind": schema_pkg_apis_dashboard_v2alpha1_DashboardTransformationKind(ref),
|
||||||
"github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1.DashboardV2alpha1DataQueryKindDatasource": schema_pkg_apis_dashboard_v2alpha1_DashboardV2alpha1DataQueryKindDatasource(ref),
|
|
||||||
"github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1.DashboardV2alpha1FieldConfigSourceOverrides": schema_pkg_apis_dashboard_v2alpha1_DashboardV2alpha1FieldConfigSourceOverrides(ref),
|
"github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1.DashboardV2alpha1FieldConfigSourceOverrides": schema_pkg_apis_dashboard_v2alpha1_DashboardV2alpha1FieldConfigSourceOverrides(ref),
|
||||||
"github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1.DashboardV2alpha1RangeMapOptions": schema_pkg_apis_dashboard_v2alpha1_DashboardV2alpha1RangeMapOptions(ref),
|
"github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1.DashboardV2alpha1RangeMapOptions": schema_pkg_apis_dashboard_v2alpha1_DashboardV2alpha1RangeMapOptions(ref),
|
||||||
"github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1.DashboardV2alpha1RegexMapOptions": schema_pkg_apis_dashboard_v2alpha1_DashboardV2alpha1RegexMapOptions(ref),
|
"github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1.DashboardV2alpha1RegexMapOptions": schema_pkg_apis_dashboard_v2alpha1_DashboardV2alpha1RegexMapOptions(ref),
|
||||||
@@ -596,10 +595,14 @@ func schema_pkg_apis_dashboard_v2alpha1_DashboardAnnotationQuerySpec(ref common.
|
|||||||
SchemaProps: spec.SchemaProps{
|
SchemaProps: spec.SchemaProps{
|
||||||
Type: []string{"object"},
|
Type: []string{"object"},
|
||||||
Properties: map[string]spec.Schema{
|
Properties: map[string]spec.Schema{
|
||||||
|
"datasource": {
|
||||||
|
SchemaProps: spec.SchemaProps{
|
||||||
|
Ref: ref("github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1.DashboardDataSourceRef"),
|
||||||
|
},
|
||||||
|
},
|
||||||
"query": {
|
"query": {
|
||||||
SchemaProps: spec.SchemaProps{
|
SchemaProps: spec.SchemaProps{
|
||||||
Default: map[string]interface{}{},
|
Ref: ref("github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1.DashboardDataQueryKind"),
|
||||||
Ref: ref("github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1.DashboardDataQueryKind"),
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"enable": {
|
"enable": {
|
||||||
@@ -643,7 +646,7 @@ func schema_pkg_apis_dashboard_v2alpha1_DashboardAnnotationQuerySpec(ref common.
|
|||||||
},
|
},
|
||||||
"legacyOptions": {
|
"legacyOptions": {
|
||||||
SchemaProps: spec.SchemaProps{
|
SchemaProps: spec.SchemaProps{
|
||||||
Description: "Catch-all field for datasource-specific properties. Should not be available in as code tooling.",
|
Description: "Catch-all field for datasource-specific properties",
|
||||||
Type: []string{"object"},
|
Type: []string{"object"},
|
||||||
AdditionalProperties: &spec.SchemaOrBool{
|
AdditionalProperties: &spec.SchemaOrBool{
|
||||||
Allows: true,
|
Allows: true,
|
||||||
@@ -657,11 +660,11 @@ func schema_pkg_apis_dashboard_v2alpha1_DashboardAnnotationQuerySpec(ref common.
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Required: []string{"query", "enable", "hide", "iconColor", "name"},
|
Required: []string{"enable", "hide", "iconColor", "name"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Dependencies: []string{
|
Dependencies: []string{
|
||||||
"github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1.DashboardAnnotationPanelFilter", "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1.DashboardDataQueryKind"},
|
"github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1.DashboardAnnotationPanelFilter", "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1.DashboardDataQueryKind", "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1.DashboardDataSourceRef"},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1502,29 +1505,10 @@ func schema_pkg_apis_dashboard_v2alpha1_DashboardDataQueryKind(ref common.Refere
|
|||||||
Properties: map[string]spec.Schema{
|
Properties: map[string]spec.Schema{
|
||||||
"kind": {
|
"kind": {
|
||||||
SchemaProps: spec.SchemaProps{
|
SchemaProps: spec.SchemaProps{
|
||||||
Default: "",
|
Description: "The kind of a DataQueryKind is the datasource type",
|
||||||
Type: []string{"string"},
|
Default: "",
|
||||||
Format: "",
|
Type: []string{"string"},
|
||||||
},
|
Format: "",
|
||||||
},
|
|
||||||
"group": {
|
|
||||||
SchemaProps: spec.SchemaProps{
|
|
||||||
Default: "",
|
|
||||||
Type: []string{"string"},
|
|
||||||
Format: "",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"version": {
|
|
||||||
SchemaProps: spec.SchemaProps{
|
|
||||||
Default: "",
|
|
||||||
Type: []string{"string"},
|
|
||||||
Format: "",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"datasource": {
|
|
||||||
SchemaProps: spec.SchemaProps{
|
|
||||||
Description: "New type for datasource reference Not creating a new type until we figure out how to handle DS refs for group by, adhoc, and every place that uses DataSourceRef in TS.",
|
|
||||||
Ref: ref("github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1.DashboardV2alpha1DataQueryKindDatasource"),
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"spec": {
|
"spec": {
|
||||||
@@ -1542,11 +1526,9 @@ func schema_pkg_apis_dashboard_v2alpha1_DashboardDataQueryKind(ref common.Refere
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Required: []string{"kind", "group", "version", "spec"},
|
Required: []string{"kind", "spec"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Dependencies: []string{
|
|
||||||
"github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1.DashboardV2alpha1DataQueryKindDatasource"},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1554,8 +1536,7 @@ func schema_pkg_apis_dashboard_v2alpha1_DashboardDataSourceRef(ref common.Refere
|
|||||||
return common.OpenAPIDefinition{
|
return common.OpenAPIDefinition{
|
||||||
Schema: spec.Schema{
|
Schema: spec.Schema{
|
||||||
SchemaProps: spec.SchemaProps{
|
SchemaProps: spec.SchemaProps{
|
||||||
Description: "Keeping this for backwards compatibility for GroupByVariableSpec and AdhocVariableSpec This type is widely used in the codebase and changing it will have a big impact",
|
Type: []string{"object"},
|
||||||
Type: []string{"object"},
|
|
||||||
Properties: map[string]spec.Schema{
|
Properties: map[string]spec.Schema{
|
||||||
"type": {
|
"type": {
|
||||||
SchemaProps: spec.SchemaProps{
|
SchemaProps: spec.SchemaProps{
|
||||||
@@ -2909,6 +2890,11 @@ func schema_pkg_apis_dashboard_v2alpha1_DashboardPanelQuerySpec(ref common.Refer
|
|||||||
Ref: ref("github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1.DashboardDataQueryKind"),
|
Ref: ref("github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1.DashboardDataQueryKind"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
"datasource": {
|
||||||
|
SchemaProps: spec.SchemaProps{
|
||||||
|
Ref: ref("github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1.DashboardDataSourceRef"),
|
||||||
|
},
|
||||||
|
},
|
||||||
"refId": {
|
"refId": {
|
||||||
SchemaProps: spec.SchemaProps{
|
SchemaProps: spec.SchemaProps{
|
||||||
Default: "",
|
Default: "",
|
||||||
@@ -2928,7 +2914,7 @@ func schema_pkg_apis_dashboard_v2alpha1_DashboardPanelQuerySpec(ref common.Refer
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
Dependencies: []string{
|
Dependencies: []string{
|
||||||
"github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1.DashboardDataQueryKind"},
|
"github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1.DashboardDataQueryKind", "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1.DashboardDataSourceRef"},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3264,6 +3250,11 @@ func schema_pkg_apis_dashboard_v2alpha1_DashboardQueryVariableSpec(ref common.Re
|
|||||||
Format: "",
|
Format: "",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
"datasource": {
|
||||||
|
SchemaProps: spec.SchemaProps{
|
||||||
|
Ref: ref("github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1.DashboardDataSourceRef"),
|
||||||
|
},
|
||||||
|
},
|
||||||
"query": {
|
"query": {
|
||||||
SchemaProps: spec.SchemaProps{
|
SchemaProps: spec.SchemaProps{
|
||||||
Default: map[string]interface{}{},
|
Default: map[string]interface{}{},
|
||||||
@@ -3341,7 +3332,7 @@ func schema_pkg_apis_dashboard_v2alpha1_DashboardQueryVariableSpec(ref common.Re
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
Dependencies: []string{
|
Dependencies: []string{
|
||||||
"github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1.DashboardDataQueryKind", "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1.DashboardVariableOption"},
|
"github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1.DashboardDataQueryKind", "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1.DashboardDataSourceRef", "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1.DashboardVariableOption"},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4329,24 +4320,6 @@ func schema_pkg_apis_dashboard_v2alpha1_DashboardTransformationKind(ref common.R
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func schema_pkg_apis_dashboard_v2alpha1_DashboardV2alpha1DataQueryKindDatasource(ref common.ReferenceCallback) common.OpenAPIDefinition {
|
|
||||||
return common.OpenAPIDefinition{
|
|
||||||
Schema: spec.Schema{
|
|
||||||
SchemaProps: spec.SchemaProps{
|
|
||||||
Type: []string{"object"},
|
|
||||||
Properties: map[string]spec.Schema{
|
|
||||||
"name": {
|
|
||||||
SchemaProps: spec.SchemaProps{
|
|
||||||
Type: []string{"string"},
|
|
||||||
Format: "",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func schema_pkg_apis_dashboard_v2alpha1_DashboardV2alpha1FieldConfigSourceOverrides(ref common.ReferenceCallback) common.OpenAPIDefinition {
|
func schema_pkg_apis_dashboard_v2alpha1_DashboardV2alpha1FieldConfigSourceOverrides(ref common.ReferenceCallback) common.OpenAPIDefinition {
|
||||||
return common.OpenAPIDefinition{
|
return common.OpenAPIDefinition{
|
||||||
Schema: spec.Schema{
|
Schema: spec.Schema{
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ import (
|
|||||||
v0alpha1 "github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1"
|
v0alpha1 "github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var ()
|
||||||
|
|
||||||
var appManifestData = app.ManifestData{
|
var appManifestData = app.ManifestData{
|
||||||
AppName: "iam",
|
AppName: "iam",
|
||||||
Group: "iam.grafana.app",
|
Group: "iam.grafana.app",
|
||||||
|
|||||||
@@ -1,257 +0,0 @@
|
|||||||
{
|
|
||||||
"kind": "Dashboard",
|
|
||||||
"apiVersion": "dashboard.grafana.app/v1beta1",
|
|
||||||
"metadata": {
|
|
||||||
"name": "test-v1-annotations",
|
|
||||||
"annotations": {
|
|
||||||
"hello": "world"
|
|
||||||
},
|
|
||||||
"labels": {
|
|
||||||
"region": "west"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"spec": {
|
|
||||||
"annotations": {
|
|
||||||
"list": [
|
|
||||||
{
|
|
||||||
"builtIn": 1,
|
|
||||||
"datasource": {
|
|
||||||
"type": "grafana",
|
|
||||||
"uid": "-- Grafana --"
|
|
||||||
},
|
|
||||||
"enable": true,
|
|
||||||
"hide": false,
|
|
||||||
"iconColor": "rgba(0, 211, 255, 1)",
|
|
||||||
"name": "Annotations & Alerts",
|
|
||||||
"target": {
|
|
||||||
"limit": 100,
|
|
||||||
"matchAny": false,
|
|
||||||
"tags": [],
|
|
||||||
"type": "dashboard"
|
|
||||||
},
|
|
||||||
"type": "dashboard"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"datasource": {
|
|
||||||
"type": "grafana-testdata-datasource",
|
|
||||||
"uid": "PD8C576611E62080A"
|
|
||||||
},
|
|
||||||
"enable": true,
|
|
||||||
"hide": false,
|
|
||||||
"iconColor": "blue",
|
|
||||||
"name": "testdata-annos",
|
|
||||||
"target": {
|
|
||||||
"lines": 10,
|
|
||||||
"refId": "Anno",
|
|
||||||
"scenarioId": "annotations"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"enable": true,
|
|
||||||
"hide": false,
|
|
||||||
"iconColor": "blue",
|
|
||||||
"name": "no-ds-testdata-annos",
|
|
||||||
"target": {
|
|
||||||
"lines": 10,
|
|
||||||
"refId": "Anno",
|
|
||||||
"scenarioId": "annotations"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"datasource": {
|
|
||||||
"type": "prometheus",
|
|
||||||
"uid": "gdev-prometheus"
|
|
||||||
},
|
|
||||||
"enable": true,
|
|
||||||
"hide": false,
|
|
||||||
"iconColor": "yellow",
|
|
||||||
"name": "prom-annos",
|
|
||||||
"target": {
|
|
||||||
"expr": "{action=\"add_client\"}",
|
|
||||||
"interval": "",
|
|
||||||
"lines": 10,
|
|
||||||
"refId": "Anno",
|
|
||||||
"scenarioId": "annotations"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"enable": true,
|
|
||||||
"hide": false,
|
|
||||||
"iconColor": "yellow",
|
|
||||||
"name": "no-ds-prom-annos",
|
|
||||||
"target": {
|
|
||||||
"expr": "{action=\"add_client\"}",
|
|
||||||
"interval": "",
|
|
||||||
"lines": 10,
|
|
||||||
"refId": "Anno",
|
|
||||||
"scenarioId": "annotations"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"datasource": {
|
|
||||||
"type": "grafana-postgresql-datasource",
|
|
||||||
"uid": "PBBCEC2D313BC06C3"
|
|
||||||
},
|
|
||||||
"enable": true,
|
|
||||||
"hide": false,
|
|
||||||
"iconColor": "red",
|
|
||||||
"name": "postgress-annos",
|
|
||||||
"target": {
|
|
||||||
"editorMode": "builder",
|
|
||||||
"format": "table",
|
|
||||||
"lines": 10,
|
|
||||||
"rawSql": "",
|
|
||||||
"refId": "Anno",
|
|
||||||
"scenarioId": "annotations",
|
|
||||||
"sql": {
|
|
||||||
"columns": [
|
|
||||||
{
|
|
||||||
"parameters": [],
|
|
||||||
"type": "function"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"groupBy": [
|
|
||||||
{
|
|
||||||
"property": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"type": "groupBy"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"limit": 50
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"datasource": {
|
|
||||||
"type": "elasticsearch",
|
|
||||||
"uid": "gdev-elasticsearch"
|
|
||||||
},
|
|
||||||
"enable": true,
|
|
||||||
"hide": false,
|
|
||||||
"iconColor": "red",
|
|
||||||
"name": "elastic - annos",
|
|
||||||
"tagsField": "asd",
|
|
||||||
"target": {
|
|
||||||
"lines": 10,
|
|
||||||
"query": "test query",
|
|
||||||
"refId": "Anno",
|
|
||||||
"scenarioId": "annotations"
|
|
||||||
},
|
|
||||||
"textField": "asd",
|
|
||||||
"timeEndField": "asdas",
|
|
||||||
"timeField": "asd"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"editable": true,
|
|
||||||
"fiscalYearStartMonth": 0,
|
|
||||||
"graphTooltip": 0,
|
|
||||||
"links": [],
|
|
||||||
"panels": [
|
|
||||||
{
|
|
||||||
"datasource": {
|
|
||||||
"type": "grafana-testdata-datasource",
|
|
||||||
"uid": "PD8C576611E62080A"
|
|
||||||
},
|
|
||||||
"fieldConfig": {
|
|
||||||
"defaults": {
|
|
||||||
"color": {
|
|
||||||
"mode": "palette-classic"
|
|
||||||
},
|
|
||||||
"custom": {
|
|
||||||
"axisBorderShow": false,
|
|
||||||
"axisCenteredZero": false,
|
|
||||||
"axisColorMode": "text",
|
|
||||||
"axisLabel": "",
|
|
||||||
"axisPlacement": "auto",
|
|
||||||
"barAlignment": 0,
|
|
||||||
"barWidthFactor": 0.6,
|
|
||||||
"drawStyle": "line",
|
|
||||||
"fillOpacity": 0,
|
|
||||||
"gradientMode": "none",
|
|
||||||
"hideFrom": {
|
|
||||||
"legend": false,
|
|
||||||
"tooltip": false,
|
|
||||||
"viz": false
|
|
||||||
},
|
|
||||||
"insertNulls": false,
|
|
||||||
"lineInterpolation": "linear",
|
|
||||||
"lineWidth": 1,
|
|
||||||
"pointSize": 5,
|
|
||||||
"scaleDistribution": {
|
|
||||||
"type": "linear"
|
|
||||||
},
|
|
||||||
"showPoints": "auto",
|
|
||||||
"spanNulls": false,
|
|
||||||
"stacking": {
|
|
||||||
"group": "A",
|
|
||||||
"mode": "none"
|
|
||||||
},
|
|
||||||
"thresholdsStyle": {
|
|
||||||
"mode": "off"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"mappings": [],
|
|
||||||
"thresholds": {
|
|
||||||
"mode": "absolute",
|
|
||||||
"steps": [
|
|
||||||
{
|
|
||||||
"color": "green",
|
|
||||||
"value": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"color": "red",
|
|
||||||
"value": 80
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"overrides": []
|
|
||||||
},
|
|
||||||
"gridPos": {
|
|
||||||
"h": 8,
|
|
||||||
"w": 12,
|
|
||||||
"x": 0,
|
|
||||||
"y": 0
|
|
||||||
},
|
|
||||||
"id": 1,
|
|
||||||
"options": {
|
|
||||||
"legend": {
|
|
||||||
"calcs": [],
|
|
||||||
"displayMode": "list",
|
|
||||||
"placement": "bottom",
|
|
||||||
"showLegend": true
|
|
||||||
},
|
|
||||||
"tooltip": {
|
|
||||||
"hideZeros": false,
|
|
||||||
"mode": "single",
|
|
||||||
"sort": "none"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"pluginVersion": "12.1.0-pre",
|
|
||||||
"targets": [
|
|
||||||
{
|
|
||||||
"refId": "A"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"title": "New panel",
|
|
||||||
"type": "timeseries"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"preload": false,
|
|
||||||
"schemaVersion": 41,
|
|
||||||
"tags": [],
|
|
||||||
"templating": {
|
|
||||||
"list": []
|
|
||||||
},
|
|
||||||
"time": {
|
|
||||||
"from": "now-6h",
|
|
||||||
"to": "now"
|
|
||||||
},
|
|
||||||
"timepicker": {},
|
|
||||||
"timezone": "browser",
|
|
||||||
"title": "Test: V1 dashboard with annotations",
|
|
||||||
"version": 8
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -10,44 +10,14 @@
|
|||||||
"kind": "AnnotationQuery",
|
"kind": "AnnotationQuery",
|
||||||
"spec": {
|
"spec": {
|
||||||
"builtIn": true,
|
"builtIn": true,
|
||||||
"enable": true,
|
"datasource": {
|
||||||
"filter": {
|
"type": "grafana",
|
||||||
"exclude": false,
|
"uid": "-- Grafana --"
|
||||||
"ids": [1]
|
|
||||||
},
|
},
|
||||||
|
"enable": true,
|
||||||
"hide": true,
|
"hide": true,
|
||||||
"iconColor": "rgba(0, 211, 255, 1)",
|
"iconColor": "rgba(0, 211, 255, 1)",
|
||||||
"name": "Annotations \u0026 Alerts",
|
"name": "Annotations \u0026 Alerts"
|
||||||
"query": {
|
|
||||||
"group": "grafana",
|
|
||||||
"kind": "DataQuery",
|
|
||||||
"spec": {},
|
|
||||||
"version": "v0"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"kind": "AnnotationQuery",
|
|
||||||
"spec": {
|
|
||||||
"query": {
|
|
||||||
"kind": "DataQuery",
|
|
||||||
"group": "grafana-testdata-datasource",
|
|
||||||
"version": "v0",
|
|
||||||
"spec": {
|
|
||||||
"lines": 10,
|
|
||||||
"refId": "Anno",
|
|
||||||
"scenarioId": "annotations"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"enable": true,
|
|
||||||
"hide": false,
|
|
||||||
"iconColor": "red",
|
|
||||||
"name": "Test data annotations",
|
|
||||||
"builtIn": false,
|
|
||||||
"filter": {
|
|
||||||
"exclude": false,
|
|
||||||
"ids": [1]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@@ -67,16 +37,8 @@
|
|||||||
"spec": {
|
"spec": {
|
||||||
"hidden": false,
|
"hidden": false,
|
||||||
"query": {
|
"query": {
|
||||||
"datasource": {
|
"kind": "grafana-testdata-datasource",
|
||||||
"name": "gdev-testdata"
|
"spec": {}
|
||||||
},
|
|
||||||
"group": "grafana-testdata-datasource",
|
|
||||||
"kind": "DataQuery",
|
|
||||||
"spec": {
|
|
||||||
"scenarioId": "random_walk",
|
|
||||||
"seriesCount": 3
|
|
||||||
},
|
|
||||||
"version": "v0"
|
|
||||||
},
|
},
|
||||||
"refId": "A"
|
"refId": "A"
|
||||||
}
|
}
|
||||||
@@ -89,7 +51,7 @@
|
|||||||
"description": "",
|
"description": "",
|
||||||
"id": 1,
|
"id": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"title": "Simple timeseries (WITH DS REF)",
|
"title": "Simle timeseries",
|
||||||
"vizConfig": {
|
"vizConfig": {
|
||||||
"kind": "timeseries",
|
"kind": "timeseries",
|
||||||
"spec": {
|
"spec": {
|
||||||
@@ -131,12 +93,12 @@
|
|||||||
"mode": "off"
|
"mode": "off"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"mappings": [],
|
||||||
"thresholds": {
|
"thresholds": {
|
||||||
"mode": "absolute",
|
"mode": "absolute",
|
||||||
"steps": [
|
"steps": [
|
||||||
{
|
{
|
||||||
"color": "green",
|
"color": "green"
|
||||||
"value": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"color": "red",
|
"color": "red",
|
||||||
@@ -160,7 +122,7 @@
|
|||||||
"sort": "none"
|
"sort": "none"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"pluginVersion": "12.1.0-pre"
|
"pluginVersion": "12.0.0-pre"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -177,13 +139,8 @@
|
|||||||
"spec": {
|
"spec": {
|
||||||
"hidden": false,
|
"hidden": false,
|
||||||
"query": {
|
"query": {
|
||||||
"group": "grafana-testdata-datasource",
|
"kind": "grafana-testdata-datasource",
|
||||||
"kind": "DataQuery",
|
"spec": {}
|
||||||
"spec": {
|
|
||||||
"scenarioId": "random_walk",
|
|
||||||
"seriesCount": 4
|
|
||||||
},
|
|
||||||
"version": "v0"
|
|
||||||
},
|
},
|
||||||
"refId": "A"
|
"refId": "A"
|
||||||
}
|
}
|
||||||
@@ -196,7 +153,7 @@
|
|||||||
"description": "",
|
"description": "",
|
||||||
"id": 2,
|
"id": 2,
|
||||||
"links": [],
|
"links": [],
|
||||||
"title": "Simple stat (NO DS REF)",
|
"title": "Simple stat",
|
||||||
"vizConfig": {
|
"vizConfig": {
|
||||||
"kind": "stat",
|
"kind": "stat",
|
||||||
"spec": {
|
"spec": {
|
||||||
@@ -205,12 +162,12 @@
|
|||||||
"color": {
|
"color": {
|
||||||
"mode": "thresholds"
|
"mode": "thresholds"
|
||||||
},
|
},
|
||||||
|
"mappings": [],
|
||||||
"thresholds": {
|
"thresholds": {
|
||||||
"mode": "absolute",
|
"mode": "absolute",
|
||||||
"steps": [
|
"steps": [
|
||||||
{
|
{
|
||||||
"color": "green",
|
"color": "green"
|
||||||
"value": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"color": "red",
|
"color": "red",
|
||||||
@@ -236,496 +193,7 @@
|
|||||||
"textMode": "auto",
|
"textMode": "auto",
|
||||||
"wideLayout": true
|
"wideLayout": true
|
||||||
},
|
},
|
||||||
"pluginVersion": "12.1.0-pre"
|
"pluginVersion": "12.0.0-pre"
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"panel-3": {
|
|
||||||
"kind": "Panel",
|
|
||||||
"spec": {
|
|
||||||
"data": {
|
|
||||||
"kind": "QueryGroup",
|
|
||||||
"spec": {
|
|
||||||
"queries": [
|
|
||||||
{
|
|
||||||
"kind": "PanelQuery",
|
|
||||||
"spec": {
|
|
||||||
"hidden": false,
|
|
||||||
"query": {
|
|
||||||
"group": "prometheus",
|
|
||||||
"kind": "DataQuery",
|
|
||||||
"spec": {
|
|
||||||
"disableTextWrap": false,
|
|
||||||
"editorMode": "builder",
|
|
||||||
"expr": "rate(counters_requests[$__rate_interval])",
|
|
||||||
"fullMetaSearch": false,
|
|
||||||
"includeNullMetadata": false,
|
|
||||||
"instant": false,
|
|
||||||
"legendFormat": "__auto",
|
|
||||||
"range": true,
|
|
||||||
"useBackend": false
|
|
||||||
},
|
|
||||||
"version": "v0"
|
|
||||||
},
|
|
||||||
"refId": "A"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"queryOptions": {},
|
|
||||||
"transformations": []
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"description": "",
|
|
||||||
"id": 3,
|
|
||||||
"links": [],
|
|
||||||
"title": "Panel with NO REF to gdev-prometheus",
|
|
||||||
"vizConfig": {
|
|
||||||
"kind": "timeseries",
|
|
||||||
"spec": {
|
|
||||||
"fieldConfig": {
|
|
||||||
"defaults": {
|
|
||||||
"color": {
|
|
||||||
"mode": "palette-classic"
|
|
||||||
},
|
|
||||||
"custom": {
|
|
||||||
"axisBorderShow": false,
|
|
||||||
"axisCenteredZero": false,
|
|
||||||
"axisColorMode": "text",
|
|
||||||
"axisLabel": "",
|
|
||||||
"axisPlacement": "auto",
|
|
||||||
"barAlignment": 0,
|
|
||||||
"barWidthFactor": 0.6,
|
|
||||||
"drawStyle": "line",
|
|
||||||
"fillOpacity": 0,
|
|
||||||
"gradientMode": "none",
|
|
||||||
"hideFrom": {
|
|
||||||
"legend": false,
|
|
||||||
"tooltip": false,
|
|
||||||
"viz": false
|
|
||||||
},
|
|
||||||
"insertNulls": false,
|
|
||||||
"lineInterpolation": "linear",
|
|
||||||
"lineWidth": 1,
|
|
||||||
"pointSize": 5,
|
|
||||||
"scaleDistribution": {
|
|
||||||
"type": "linear"
|
|
||||||
},
|
|
||||||
"showPoints": "auto",
|
|
||||||
"spanNulls": false,
|
|
||||||
"stacking": {
|
|
||||||
"group": "A",
|
|
||||||
"mode": "none"
|
|
||||||
},
|
|
||||||
"thresholdsStyle": {
|
|
||||||
"mode": "off"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"thresholds": {
|
|
||||||
"mode": "absolute",
|
|
||||||
"steps": [
|
|
||||||
{
|
|
||||||
"color": "green",
|
|
||||||
"value": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"color": "red",
|
|
||||||
"value": 80
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"overrides": []
|
|
||||||
},
|
|
||||||
"options": {
|
|
||||||
"legend": {
|
|
||||||
"calcs": [],
|
|
||||||
"displayMode": "list",
|
|
||||||
"placement": "bottom",
|
|
||||||
"showLegend": true
|
|
||||||
},
|
|
||||||
"tooltip": {
|
|
||||||
"hideZeros": false,
|
|
||||||
"mode": "single",
|
|
||||||
"sort": "none"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"pluginVersion": "12.1.0-pre"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"panel-4": {
|
|
||||||
"kind": "Panel",
|
|
||||||
"spec": {
|
|
||||||
"data": {
|
|
||||||
"kind": "QueryGroup",
|
|
||||||
"spec": {
|
|
||||||
"queries": [
|
|
||||||
{
|
|
||||||
"kind": "PanelQuery",
|
|
||||||
"spec": {
|
|
||||||
"hidden": false,
|
|
||||||
"query": {
|
|
||||||
"datasource": {
|
|
||||||
"name": "gdev-prometheus"
|
|
||||||
},
|
|
||||||
"group": "prometheus",
|
|
||||||
"kind": "DataQuery",
|
|
||||||
"spec": {
|
|
||||||
"disableTextWrap": false,
|
|
||||||
"editorMode": "builder",
|
|
||||||
"expr": "rate(counters_requests[$__rate_interval])",
|
|
||||||
"fullMetaSearch": false,
|
|
||||||
"includeNullMetadata": false,
|
|
||||||
"instant": false,
|
|
||||||
"legendFormat": "__auto",
|
|
||||||
"range": true,
|
|
||||||
"useBackend": false
|
|
||||||
},
|
|
||||||
"version": "v0"
|
|
||||||
},
|
|
||||||
"refId": "A"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"queryOptions": {},
|
|
||||||
"transformations": []
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"description": "",
|
|
||||||
"id": 4,
|
|
||||||
"links": [],
|
|
||||||
"title": "Panel with ref to gdev-prometheus",
|
|
||||||
"vizConfig": {
|
|
||||||
"kind": "timeseries",
|
|
||||||
"spec": {
|
|
||||||
"fieldConfig": {
|
|
||||||
"defaults": {
|
|
||||||
"color": {
|
|
||||||
"mode": "palette-classic"
|
|
||||||
},
|
|
||||||
"custom": {
|
|
||||||
"axisBorderShow": false,
|
|
||||||
"axisCenteredZero": false,
|
|
||||||
"axisColorMode": "text",
|
|
||||||
"axisLabel": "",
|
|
||||||
"axisPlacement": "auto",
|
|
||||||
"barAlignment": 0,
|
|
||||||
"barWidthFactor": 0.6,
|
|
||||||
"drawStyle": "line",
|
|
||||||
"fillOpacity": 0,
|
|
||||||
"gradientMode": "none",
|
|
||||||
"hideFrom": {
|
|
||||||
"legend": false,
|
|
||||||
"tooltip": false,
|
|
||||||
"viz": false
|
|
||||||
},
|
|
||||||
"insertNulls": false,
|
|
||||||
"lineInterpolation": "linear",
|
|
||||||
"lineWidth": 1,
|
|
||||||
"pointSize": 5,
|
|
||||||
"scaleDistribution": {
|
|
||||||
"type": "linear"
|
|
||||||
},
|
|
||||||
"showPoints": "auto",
|
|
||||||
"spanNulls": false,
|
|
||||||
"stacking": {
|
|
||||||
"group": "A",
|
|
||||||
"mode": "none"
|
|
||||||
},
|
|
||||||
"thresholdsStyle": {
|
|
||||||
"mode": "off"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"thresholds": {
|
|
||||||
"mode": "absolute",
|
|
||||||
"steps": [
|
|
||||||
{
|
|
||||||
"color": "green",
|
|
||||||
"value": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"color": "red",
|
|
||||||
"value": 80
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"overrides": []
|
|
||||||
},
|
|
||||||
"options": {
|
|
||||||
"legend": {
|
|
||||||
"calcs": [],
|
|
||||||
"displayMode": "list",
|
|
||||||
"placement": "bottom",
|
|
||||||
"showLegend": true
|
|
||||||
},
|
|
||||||
"tooltip": {
|
|
||||||
"hideZeros": false,
|
|
||||||
"mode": "single",
|
|
||||||
"sort": "none"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"pluginVersion": "12.1.0-pre"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"panel-5": {
|
|
||||||
"kind": "Panel",
|
|
||||||
"spec": {
|
|
||||||
"data": {
|
|
||||||
"kind": "QueryGroup",
|
|
||||||
"spec": {
|
|
||||||
"queries": [
|
|
||||||
{
|
|
||||||
"kind": "PanelQuery",
|
|
||||||
"spec": {
|
|
||||||
"hidden": false,
|
|
||||||
"query": {
|
|
||||||
"datasource": {
|
|
||||||
"name": "gdev-prometheus"
|
|
||||||
},
|
|
||||||
"group": "prometheus",
|
|
||||||
"kind": "DataQuery",
|
|
||||||
"spec": {
|
|
||||||
"disableTextWrap": false,
|
|
||||||
"editorMode": "builder",
|
|
||||||
"expr": "rate(counters_requests{server=\"backend-01\"}[$__rate_interval])",
|
|
||||||
"fullMetaSearch": false,
|
|
||||||
"includeNullMetadata": false,
|
|
||||||
"legendFormat": "__auto",
|
|
||||||
"range": true,
|
|
||||||
"useBackend": false
|
|
||||||
},
|
|
||||||
"version": "v0"
|
|
||||||
},
|
|
||||||
"refId": "A"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"kind": "PanelQuery",
|
|
||||||
"spec": {
|
|
||||||
"hidden": false,
|
|
||||||
"query": {
|
|
||||||
"datasource": {
|
|
||||||
"name": "gdev-testdata"
|
|
||||||
},
|
|
||||||
"group": "grafana-testdata-datasource",
|
|
||||||
"kind": "DataQuery",
|
|
||||||
"spec": {},
|
|
||||||
"version": "v0"
|
|
||||||
},
|
|
||||||
"refId": "B"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"queryOptions": {},
|
|
||||||
"transformations": []
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"description": "",
|
|
||||||
"id": 5,
|
|
||||||
"links": [],
|
|
||||||
"title": "Mixed DS WITH REFS",
|
|
||||||
"vizConfig": {
|
|
||||||
"kind": "timeseries",
|
|
||||||
"spec": {
|
|
||||||
"fieldConfig": {
|
|
||||||
"defaults": {
|
|
||||||
"color": {
|
|
||||||
"mode": "palette-classic"
|
|
||||||
},
|
|
||||||
"custom": {
|
|
||||||
"axisBorderShow": false,
|
|
||||||
"axisCenteredZero": false,
|
|
||||||
"axisColorMode": "text",
|
|
||||||
"axisLabel": "",
|
|
||||||
"axisPlacement": "auto",
|
|
||||||
"barAlignment": 0,
|
|
||||||
"barWidthFactor": 0.6,
|
|
||||||
"drawStyle": "line",
|
|
||||||
"fillOpacity": 0,
|
|
||||||
"gradientMode": "none",
|
|
||||||
"hideFrom": {
|
|
||||||
"legend": false,
|
|
||||||
"tooltip": false,
|
|
||||||
"viz": false
|
|
||||||
},
|
|
||||||
"insertNulls": false,
|
|
||||||
"lineInterpolation": "linear",
|
|
||||||
"lineWidth": 1,
|
|
||||||
"pointSize": 5,
|
|
||||||
"scaleDistribution": {
|
|
||||||
"type": "linear"
|
|
||||||
},
|
|
||||||
"showPoints": "auto",
|
|
||||||
"spanNulls": false,
|
|
||||||
"stacking": {
|
|
||||||
"group": "A",
|
|
||||||
"mode": "none"
|
|
||||||
},
|
|
||||||
"thresholdsStyle": {
|
|
||||||
"mode": "off"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"thresholds": {
|
|
||||||
"mode": "absolute",
|
|
||||||
"steps": [
|
|
||||||
{
|
|
||||||
"color": "green",
|
|
||||||
"value": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"color": "red",
|
|
||||||
"value": 80
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"overrides": []
|
|
||||||
},
|
|
||||||
"options": {
|
|
||||||
"legend": {
|
|
||||||
"calcs": [],
|
|
||||||
"displayMode": "list",
|
|
||||||
"placement": "bottom",
|
|
||||||
"showLegend": true
|
|
||||||
},
|
|
||||||
"tooltip": {
|
|
||||||
"hideZeros": false,
|
|
||||||
"mode": "single",
|
|
||||||
"sort": "none"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"pluginVersion": "12.1.0-pre"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"panel-6": {
|
|
||||||
"kind": "Panel",
|
|
||||||
"spec": {
|
|
||||||
"data": {
|
|
||||||
"kind": "QueryGroup",
|
|
||||||
"spec": {
|
|
||||||
"queries": [
|
|
||||||
{
|
|
||||||
"kind": "PanelQuery",
|
|
||||||
"spec": {
|
|
||||||
"hidden": false,
|
|
||||||
"query": {
|
|
||||||
"group": "prometheus",
|
|
||||||
"kind": "DataQuery",
|
|
||||||
"spec": {
|
|
||||||
"disableTextWrap": false,
|
|
||||||
"editorMode": "builder",
|
|
||||||
"expr": "rate(counters_requests{server=\"backend-01\"}[$__rate_interval])",
|
|
||||||
"fullMetaSearch": false,
|
|
||||||
"includeNullMetadata": false,
|
|
||||||
"legendFormat": "__auto",
|
|
||||||
"range": true,
|
|
||||||
"useBackend": false
|
|
||||||
},
|
|
||||||
"version": "v0"
|
|
||||||
},
|
|
||||||
"refId": "A"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"kind": "PanelQuery",
|
|
||||||
"spec": {
|
|
||||||
"hidden": false,
|
|
||||||
"query": {
|
|
||||||
"group": "grafana-testdata-datasource",
|
|
||||||
"kind": "DataQuery",
|
|
||||||
"spec": {},
|
|
||||||
"version": "v0"
|
|
||||||
},
|
|
||||||
"refId": "B"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"queryOptions": {},
|
|
||||||
"transformations": []
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"description": "",
|
|
||||||
"id": 6,
|
|
||||||
"links": [],
|
|
||||||
"title": "Mixed DS WITHOUT REFS",
|
|
||||||
"vizConfig": {
|
|
||||||
"kind": "timeseries",
|
|
||||||
"spec": {
|
|
||||||
"fieldConfig": {
|
|
||||||
"defaults": {
|
|
||||||
"color": {
|
|
||||||
"mode": "palette-classic"
|
|
||||||
},
|
|
||||||
"custom": {
|
|
||||||
"axisBorderShow": false,
|
|
||||||
"axisCenteredZero": false,
|
|
||||||
"axisColorMode": "text",
|
|
||||||
"axisLabel": "",
|
|
||||||
"axisPlacement": "auto",
|
|
||||||
"barAlignment": 0,
|
|
||||||
"barWidthFactor": 0.6,
|
|
||||||
"drawStyle": "line",
|
|
||||||
"fillOpacity": 0,
|
|
||||||
"gradientMode": "none",
|
|
||||||
"hideFrom": {
|
|
||||||
"legend": false,
|
|
||||||
"tooltip": false,
|
|
||||||
"viz": false
|
|
||||||
},
|
|
||||||
"insertNulls": false,
|
|
||||||
"lineInterpolation": "linear",
|
|
||||||
"lineWidth": 1,
|
|
||||||
"pointSize": 5,
|
|
||||||
"scaleDistribution": {
|
|
||||||
"type": "linear"
|
|
||||||
},
|
|
||||||
"showPoints": "auto",
|
|
||||||
"spanNulls": false,
|
|
||||||
"stacking": {
|
|
||||||
"group": "A",
|
|
||||||
"mode": "none"
|
|
||||||
},
|
|
||||||
"thresholdsStyle": {
|
|
||||||
"mode": "off"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"thresholds": {
|
|
||||||
"mode": "absolute",
|
|
||||||
"steps": [
|
|
||||||
{
|
|
||||||
"color": "green",
|
|
||||||
"value": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"color": "red",
|
|
||||||
"value": 80
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"overrides": []
|
|
||||||
},
|
|
||||||
"options": {
|
|
||||||
"legend": {
|
|
||||||
"calcs": [],
|
|
||||||
"displayMode": "list",
|
|
||||||
"placement": "bottom",
|
|
||||||
"showLegend": true
|
|
||||||
},
|
|
||||||
"tooltip": {
|
|
||||||
"hideZeros": false,
|
|
||||||
"mode": "single",
|
|
||||||
"sort": "none"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"pluginVersion": "12.1.0-pre"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -736,24 +204,6 @@
|
|||||||
"spec": {
|
"spec": {
|
||||||
"columnWidthMode": "standard",
|
"columnWidthMode": "standard",
|
||||||
"items": [
|
"items": [
|
||||||
{
|
|
||||||
"kind": "AutoGridLayoutItem",
|
|
||||||
"spec": {
|
|
||||||
"element": {
|
|
||||||
"kind": "ElementReference",
|
|
||||||
"name": "panel-3"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"kind": "AutoGridLayoutItem",
|
|
||||||
"spec": {
|
|
||||||
"element": {
|
|
||||||
"kind": "ElementReference",
|
|
||||||
"name": "panel-4"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"kind": "AutoGridLayoutItem",
|
"kind": "AutoGridLayoutItem",
|
||||||
"spec": {
|
"spec": {
|
||||||
@@ -771,24 +221,6 @@
|
|||||||
"name": "panel-1"
|
"name": "panel-1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
|
||||||
{
|
|
||||||
"kind": "AutoGridLayoutItem",
|
|
||||||
"spec": {
|
|
||||||
"element": {
|
|
||||||
"kind": "ElementReference",
|
|
||||||
"name": "panel-5"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"kind": "AutoGridLayoutItem",
|
|
||||||
"spec": {
|
|
||||||
"element": {
|
|
||||||
"kind": "ElementReference",
|
|
||||||
"name": "panel-6"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"maxColumnCount": 3,
|
"maxColumnCount": 3,
|
||||||
@@ -803,7 +235,7 @@
|
|||||||
"autoRefresh": "",
|
"autoRefresh": "",
|
||||||
"autoRefreshIntervals": ["5s", "10s", "30s", "1m", "5m", "15m", "30m", "1h", "2h", "1d"],
|
"autoRefreshIntervals": ["5s", "10s", "30s", "1m", "5m", "15m", "30m", "1h", "2h", "1d"],
|
||||||
"fiscalYearStartMonth": 0,
|
"fiscalYearStartMonth": 0,
|
||||||
"from": "now-5m",
|
"from": "now-6h",
|
||||||
"hideTimepicker": false,
|
"hideTimepicker": false,
|
||||||
"timezone": "browser",
|
"timezone": "browser",
|
||||||
"to": "now"
|
"to": "now"
|
||||||
|
|||||||
@@ -2,11 +2,21 @@
|
|||||||
"apiVersion": "dashboard.grafana.app/v2alpha1",
|
"apiVersion": "dashboard.grafana.app/v2alpha1",
|
||||||
"kind": "Dashboard",
|
"kind": "Dashboard",
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"name": "fa400625-2a44-4add-a369-e6c972eb4bd6",
|
"name": "admjzp8",
|
||||||
|
"namespace": "default",
|
||||||
|
"uid": "hrbekBWXeM7nC7GtouIbcngFyuqt8Xx7KlE4AnTwV7AX",
|
||||||
|
"resourceVersion": "1",
|
||||||
"generation": 1,
|
"generation": 1,
|
||||||
"creationTimestamp": "2025-05-27T11:40:22Z",
|
"creationTimestamp": "2025-05-16T09:41:56Z",
|
||||||
"labels": {},
|
"labels": {
|
||||||
"annotations": {}
|
"grafana.app/deprecatedInternalID": "182"
|
||||||
|
},
|
||||||
|
"annotations": {
|
||||||
|
"grafana.app/createdBy": "user:cejvsh18uudxcf",
|
||||||
|
"grafana.app/updatedBy": "user:cejvsh18uudxcf",
|
||||||
|
"grafana.app/updatedTimestamp": "2025-05-16T09:41:56Z",
|
||||||
|
"grafana.app/folder": ""
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"spec": {
|
"spec": {
|
||||||
"annotations": [
|
"annotations": [
|
||||||
@@ -14,20 +24,19 @@
|
|||||||
"kind": "AnnotationQuery",
|
"kind": "AnnotationQuery",
|
||||||
"spec": {
|
"spec": {
|
||||||
"builtIn": true,
|
"builtIn": true,
|
||||||
|
"datasource": {
|
||||||
|
"type": "grafana",
|
||||||
|
"uid": "-- Grafana --"
|
||||||
|
},
|
||||||
"enable": true,
|
"enable": true,
|
||||||
"hide": true,
|
"hide": true,
|
||||||
"iconColor": "rgba(0, 211, 255, 1)",
|
"iconColor": "rgba(0, 211, 255, 1)",
|
||||||
"name": "Annotations & Alerts",
|
"name": "Annotations & Alerts"
|
||||||
"query": {
|
|
||||||
"group": "grafana",
|
|
||||||
"kind": "DataQuery",
|
|
||||||
"spec": {},
|
|
||||||
"version": "v0"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"cursorSync": "Off",
|
"cursorSync": "Off",
|
||||||
|
"description": "",
|
||||||
"editable": true,
|
"editable": true,
|
||||||
"elements": {
|
"elements": {
|
||||||
"panel-1": {
|
"panel-1": {
|
||||||
@@ -40,12 +49,14 @@
|
|||||||
{
|
{
|
||||||
"kind": "PanelQuery",
|
"kind": "PanelQuery",
|
||||||
"spec": {
|
"spec": {
|
||||||
|
"datasource": {
|
||||||
|
"type": "grafana-testdata-datasource",
|
||||||
|
"uid": "PD8C576611E62080A"
|
||||||
|
},
|
||||||
"hidden": false,
|
"hidden": false,
|
||||||
"query": {
|
"query": {
|
||||||
"group": "grafana-testdata-datasource",
|
"kind": "grafana-testdata-datasource",
|
||||||
"kind": "DataQuery",
|
"spec": {}
|
||||||
"spec": {},
|
|
||||||
"version": "v0"
|
|
||||||
},
|
},
|
||||||
"refId": "A"
|
"refId": "A"
|
||||||
}
|
}
|
||||||
@@ -144,12 +155,14 @@
|
|||||||
{
|
{
|
||||||
"kind": "PanelQuery",
|
"kind": "PanelQuery",
|
||||||
"spec": {
|
"spec": {
|
||||||
|
"datasource": {
|
||||||
|
"type": "grafana-testdata-datasource",
|
||||||
|
"uid": "PD8C576611E62080A"
|
||||||
|
},
|
||||||
"hidden": false,
|
"hidden": false,
|
||||||
"query": {
|
"query": {
|
||||||
"group": "grafana-testdata-datasource",
|
"kind": "grafana-testdata-datasource",
|
||||||
"kind": "DataQuery",
|
"spec": {}
|
||||||
"spec": {},
|
|
||||||
"version": "v0"
|
|
||||||
},
|
},
|
||||||
"refId": "A"
|
"refId": "A"
|
||||||
}
|
}
|
||||||
@@ -248,12 +261,14 @@
|
|||||||
{
|
{
|
||||||
"kind": "PanelQuery",
|
"kind": "PanelQuery",
|
||||||
"spec": {
|
"spec": {
|
||||||
|
"datasource": {
|
||||||
|
"type": "grafana-testdata-datasource",
|
||||||
|
"uid": "PD8C576611E62080A"
|
||||||
|
},
|
||||||
"hidden": false,
|
"hidden": false,
|
||||||
"query": {
|
"query": {
|
||||||
"group": "grafana-testdata-datasource",
|
"kind": "grafana-testdata-datasource",
|
||||||
"kind": "DataQuery",
|
"spec": {}
|
||||||
"spec": {},
|
|
||||||
"version": "v0"
|
|
||||||
},
|
},
|
||||||
"refId": "A"
|
"refId": "A"
|
||||||
}
|
}
|
||||||
@@ -365,7 +380,7 @@
|
|||||||
"spec": {
|
"spec": {
|
||||||
"element": {
|
"element": {
|
||||||
"kind": "ElementReference",
|
"kind": "ElementReference",
|
||||||
"name": "panel-3"
|
"name": "panel-2"
|
||||||
},
|
},
|
||||||
"height": 8,
|
"height": 8,
|
||||||
"width": 12,
|
"width": 12,
|
||||||
@@ -378,7 +393,7 @@
|
|||||||
"spec": {
|
"spec": {
|
||||||
"element": {
|
"element": {
|
||||||
"kind": "ElementReference",
|
"kind": "ElementReference",
|
||||||
"name": "panel-2"
|
"name": "panel-3"
|
||||||
},
|
},
|
||||||
"height": 8,
|
"height": 8,
|
||||||
"width": 12,
|
"width": 12,
|
||||||
@@ -402,7 +417,7 @@
|
|||||||
"timezone": "browser",
|
"timezone": "browser",
|
||||||
"to": "now"
|
"to": "now"
|
||||||
},
|
},
|
||||||
"title": "Test V2 Dashboard",
|
"title": "New Test V2 Dashboard",
|
||||||
"variables": []
|
"variables": []
|
||||||
},
|
},
|
||||||
"status": {}
|
"status": {}
|
||||||
|
|||||||
@@ -17,9 +17,5 @@ export const importV2Dashboard = ({ title }: ImportDashboardConfig) => {
|
|||||||
if (title) {
|
if (title) {
|
||||||
e2e.components.ImportDashboardForm.name().clear().type(title);
|
e2e.components.ImportDashboardForm.name().clear().type(title);
|
||||||
}
|
}
|
||||||
|
|
||||||
e2e.components.DataSourcePicker.inputV2().click();
|
|
||||||
cy.get('div[data-testid="data-source-card"]').first().click();
|
|
||||||
|
|
||||||
e2e.components.ImportDashboardForm.submit().click();
|
e2e.components.ImportDashboardForm.submit().click();
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -97,7 +97,7 @@ require (
|
|||||||
github.com/grafana/grafana-api-golang-client v0.27.0 // @grafana/alerting-backend
|
github.com/grafana/grafana-api-golang-client v0.27.0 // @grafana/alerting-backend
|
||||||
github.com/grafana/grafana-app-sdk v0.39.2 // @grafana/grafana-app-platform-squad
|
github.com/grafana/grafana-app-sdk v0.39.2 // @grafana/grafana-app-platform-squad
|
||||||
github.com/grafana/grafana-app-sdk/logging v0.39.1 // @grafana/grafana-app-platform-squad
|
github.com/grafana/grafana-app-sdk/logging v0.39.1 // @grafana/grafana-app-platform-squad
|
||||||
github.com/grafana/grafana-aws-sdk v1.0.3 // @grafana/aws-datasources
|
github.com/grafana/grafana-aws-sdk v1.0.4 // @grafana/aws-datasources
|
||||||
github.com/grafana/grafana-azure-sdk-go/v2 v2.1.6 // @grafana/partner-datasources
|
github.com/grafana/grafana-azure-sdk-go/v2 v2.1.6 // @grafana/partner-datasources
|
||||||
github.com/grafana/grafana-cloud-migration-snapshot v1.6.0 // @grafana/grafana-operator-experience-squad
|
github.com/grafana/grafana-cloud-migration-snapshot v1.6.0 // @grafana/grafana-operator-experience-squad
|
||||||
github.com/grafana/grafana-google-sdk-go v0.4.1 // @grafana/partner-datasources
|
github.com/grafana/grafana-google-sdk-go v0.4.1 // @grafana/partner-datasources
|
||||||
|
|||||||
@@ -1595,8 +1595,8 @@ github.com/grafana/grafana-app-sdk v0.39.2 h1:ymfr+1318t+JC9U2OYrzVpGmNG/aJONUmF
|
|||||||
github.com/grafana/grafana-app-sdk v0.39.2/go.mod h1:t0m6q561lpoHQCixS9LUHFUhUzDClzNtm7BH60gHVSY=
|
github.com/grafana/grafana-app-sdk v0.39.2/go.mod h1:t0m6q561lpoHQCixS9LUHFUhUzDClzNtm7BH60gHVSY=
|
||||||
github.com/grafana/grafana-app-sdk/logging v0.39.1 h1:lI5rbrheuwVPuyIM6LIuEYOCSpgmXahfKtqeMyhbGPU=
|
github.com/grafana/grafana-app-sdk/logging v0.39.1 h1:lI5rbrheuwVPuyIM6LIuEYOCSpgmXahfKtqeMyhbGPU=
|
||||||
github.com/grafana/grafana-app-sdk/logging v0.39.1/go.mod h1:WhDENSnaGHtyVVwZGVnAR7YLvh2xlLDYR3D7E6h7XVk=
|
github.com/grafana/grafana-app-sdk/logging v0.39.1/go.mod h1:WhDENSnaGHtyVVwZGVnAR7YLvh2xlLDYR3D7E6h7XVk=
|
||||||
github.com/grafana/grafana-aws-sdk v1.0.3 h1:FtGiTrdlPXuQmLqeZdyNjjkNKOOdvQ4sxWw8MtJc6ow=
|
github.com/grafana/grafana-aws-sdk v1.0.4 h1:D14UAehsOqpjliHmHzveRQ1p43KCsMzdmb7GovWj+SY=
|
||||||
github.com/grafana/grafana-aws-sdk v1.0.3/go.mod h1:hO7q7yWV+t6dmiyJjMa3IbuYnYkBua+G/IAlOPVIYKE=
|
github.com/grafana/grafana-aws-sdk v1.0.4/go.mod h1:hO7q7yWV+t6dmiyJjMa3IbuYnYkBua+G/IAlOPVIYKE=
|
||||||
github.com/grafana/grafana-azure-sdk-go/v2 v2.1.6 h1:OfCkitCuomzZKW1WYHrG8MxKwtMhALb7jqoj+487eTg=
|
github.com/grafana/grafana-azure-sdk-go/v2 v2.1.6 h1:OfCkitCuomzZKW1WYHrG8MxKwtMhALb7jqoj+487eTg=
|
||||||
github.com/grafana/grafana-azure-sdk-go/v2 v2.1.6/go.mod h1:V7y2BmsWxS3A9Ohebwn4OiSfJJqi//4JQydQ8fHTduo=
|
github.com/grafana/grafana-azure-sdk-go/v2 v2.1.6/go.mod h1:V7y2BmsWxS3A9Ohebwn4OiSfJJqi//4JQydQ8fHTduo=
|
||||||
github.com/grafana/grafana-cloud-migration-snapshot v1.6.0 h1:S4kHwr//AqhtL9xHBtz1gqVgZQeCRGTxjgsRBAkpjKY=
|
github.com/grafana/grafana-cloud-migration-snapshot v1.6.0 h1:S4kHwr//AqhtL9xHBtz1gqVgZQeCRGTxjgsRBAkpjKY=
|
||||||
|
|||||||
@@ -347,6 +347,7 @@ github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV
|
|||||||
github.com/RaveNoX/go-jsoncommentstrip v1.0.0 h1:t527LHHE3HmiHrq74QMpNPZpGCIJzTx+apLkMKt4HC0=
|
github.com/RaveNoX/go-jsoncommentstrip v1.0.0 h1:t527LHHE3HmiHrq74QMpNPZpGCIJzTx+apLkMKt4HC0=
|
||||||
github.com/RoaringBitmap/gocroaring v0.4.0 h1:5nufXUgWpBEUNEJXw7926YAA58ZAQRpWPrQV1xCoSjc=
|
github.com/RoaringBitmap/gocroaring v0.4.0 h1:5nufXUgWpBEUNEJXw7926YAA58ZAQRpWPrQV1xCoSjc=
|
||||||
github.com/RoaringBitmap/real-roaring-datasets v0.0.0-20190726190000-eb7c87156f76 h1:ZYlhPbqQFU+AHfgtCdHGDTtRW1a8geZyiE8c6Q+Sl1s=
|
github.com/RoaringBitmap/real-roaring-datasets v0.0.0-20190726190000-eb7c87156f76 h1:ZYlhPbqQFU+AHfgtCdHGDTtRW1a8geZyiE8c6Q+Sl1s=
|
||||||
|
github.com/RoaringBitmap/real-roaring-datasets v0.0.0-20190726190000-eb7c87156f76/go.mod h1:oM0MHmQ3nDsq609SS36p+oYbRi16+oVvU2Bw4Ipv0SE=
|
||||||
github.com/Sereal/Sereal/Go/sereal v0.0.0-20231009093132-b9187f1a92c6 h1:5kUcJJAKWWI82Xnp/CaU0eu5hLlHkmm9acjowSkwCd0=
|
github.com/Sereal/Sereal/Go/sereal v0.0.0-20231009093132-b9187f1a92c6 h1:5kUcJJAKWWI82Xnp/CaU0eu5hLlHkmm9acjowSkwCd0=
|
||||||
github.com/Sereal/Sereal/Go/sereal v0.0.0-20231009093132-b9187f1a92c6/go.mod h1:JwrycNnC8+sZPDyzM3MQ86LvaGzSpfxg885KOOwFRW4=
|
github.com/Sereal/Sereal/Go/sereal v0.0.0-20231009093132-b9187f1a92c6/go.mod h1:JwrycNnC8+sZPDyzM3MQ86LvaGzSpfxg885KOOwFRW4=
|
||||||
github.com/Shopify/goreferrer v0.0.0-20220729165902-8cddb4f5de06 h1:KkH3I3sJuOLP3TjA/dfr4NAY8bghDwnXiU7cTKxQqo0=
|
github.com/Shopify/goreferrer v0.0.0-20220729165902-8cddb4f5de06 h1:KkH3I3sJuOLP3TjA/dfr4NAY8bghDwnXiU7cTKxQqo0=
|
||||||
@@ -570,6 +571,7 @@ github.com/envoyproxy/go-control-plane v0.13.1/go.mod h1:X45hY0mufo6Fd0KW3rqsGvQ
|
|||||||
github.com/envoyproxy/go-control-plane/envoy v1.32.3/go.mod h1:F6hWupPfh75TBXGKA++MCT/CZHFq5r9/uwt/kQYkZfE=
|
github.com/envoyproxy/go-control-plane/envoy v1.32.3/go.mod h1:F6hWupPfh75TBXGKA++MCT/CZHFq5r9/uwt/kQYkZfE=
|
||||||
github.com/envoyproxy/protoc-gen-validate v1.0.4/go.mod h1:qys6tmnRsYrQqIhm2bvKZH4Blx/1gTIZ2UKVY1M+Yew=
|
github.com/envoyproxy/protoc-gen-validate v1.0.4/go.mod h1:qys6tmnRsYrQqIhm2bvKZH4Blx/1gTIZ2UKVY1M+Yew=
|
||||||
github.com/envoyproxy/protoc-gen-validate v1.1.0/go.mod h1:sXRDRVmzEbkM7CVcM06s9shE/m23dg3wzjl0UWqJ2q4=
|
github.com/envoyproxy/protoc-gen-validate v1.1.0/go.mod h1:sXRDRVmzEbkM7CVcM06s9shE/m23dg3wzjl0UWqJ2q4=
|
||||||
|
github.com/expr-lang/expr v1.16.9/go.mod h1:8/vRC7+7HBzESEqt5kKpYXxrxkr31SaO8r40VO/1IT4=
|
||||||
github.com/expr-lang/expr v1.17.0/go.mod h1:8/vRC7+7HBzESEqt5kKpYXxrxkr31SaO8r40VO/1IT4=
|
github.com/expr-lang/expr v1.17.0/go.mod h1:8/vRC7+7HBzESEqt5kKpYXxrxkr31SaO8r40VO/1IT4=
|
||||||
github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo=
|
github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo=
|
||||||
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
|
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
|
||||||
@@ -679,6 +681,8 @@ github.com/grafana/alerting v0.0.0-20250403153742-418bc7118d05 h1:hMzOzI/S0nkZt0
|
|||||||
github.com/grafana/alerting v0.0.0-20250403153742-418bc7118d05/go.mod h1:K3YAJumchx5EEZItGv4D3pCv/Ux796hmoOibP/p/eYk=
|
github.com/grafana/alerting v0.0.0-20250403153742-418bc7118d05/go.mod h1:K3YAJumchx5EEZItGv4D3pCv/Ux796hmoOibP/p/eYk=
|
||||||
github.com/grafana/alerting v0.0.0-20250429131604-de176b4a0309 h1:H2p3XKDHnTBGkMXLCgXiqb2dFnHbQ4zPDXOwKK4Ne3Y=
|
github.com/grafana/alerting v0.0.0-20250429131604-de176b4a0309 h1:H2p3XKDHnTBGkMXLCgXiqb2dFnHbQ4zPDXOwKK4Ne3Y=
|
||||||
github.com/grafana/alerting v0.0.0-20250429131604-de176b4a0309/go.mod h1:pMfhRxL2LZ3Pm8iy7VcVsb9CLYuBtjFYbf1oxgx7yFA=
|
github.com/grafana/alerting v0.0.0-20250429131604-de176b4a0309/go.mod h1:pMfhRxL2LZ3Pm8iy7VcVsb9CLYuBtjFYbf1oxgx7yFA=
|
||||||
|
github.com/grafana/alerting v0.0.0-20250701210250-cea2d1683945 h1:3imTbxFpZSVI6IBIB9mn+Xc40lUweWjfMaBSgXR7rLs=
|
||||||
|
github.com/grafana/alerting v0.0.0-20250701210250-cea2d1683945/go.mod h1:gtR7agmxVfJOmNKV/n2ZULgOYTYNL+PDKYB5N48tQ7Q=
|
||||||
github.com/grafana/authlib v0.0.0-20250123104008-e99947858901/go.mod h1:/gYfphsNu9v1qYWXxpv1NSvMEMSwvdf8qb8YlgwIRl8=
|
github.com/grafana/authlib v0.0.0-20250123104008-e99947858901/go.mod h1:/gYfphsNu9v1qYWXxpv1NSvMEMSwvdf8qb8YlgwIRl8=
|
||||||
github.com/grafana/authlib/types v0.0.0-20250120144156-d6737a7dc8f5/go.mod h1:qYjSd1tmJiuVoSICp7Py9/zD54O9uQQA3wuM6Gg4DFM=
|
github.com/grafana/authlib/types v0.0.0-20250120144156-d6737a7dc8f5/go.mod h1:qYjSd1tmJiuVoSICp7Py9/zD54O9uQQA3wuM6Gg4DFM=
|
||||||
github.com/grafana/authlib/types v0.0.0-20250120145936-5f0e28e7a87c/go.mod h1:qYjSd1tmJiuVoSICp7Py9/zD54O9uQQA3wuM6Gg4DFM=
|
github.com/grafana/authlib/types v0.0.0-20250120145936-5f0e28e7a87c/go.mod h1:qYjSd1tmJiuVoSICp7Py9/zD54O9uQQA3wuM6Gg4DFM=
|
||||||
@@ -693,6 +697,8 @@ github.com/grafana/grafana-app-sdk/logging v0.39.0 h1:3GgN5+dUZYqq74Q+GT9/ET+yo+
|
|||||||
github.com/grafana/grafana-app-sdk/logging v0.39.0/go.mod h1:WhDENSnaGHtyVVwZGVnAR7YLvh2xlLDYR3D7E6h7XVk=
|
github.com/grafana/grafana-app-sdk/logging v0.39.0/go.mod h1:WhDENSnaGHtyVVwZGVnAR7YLvh2xlLDYR3D7E6h7XVk=
|
||||||
github.com/grafana/grafana-aws-sdk v0.38.2 h1:TzQD0OpWsNjtldi5G5TLDlBRk8OyDf+B5ujcoAu4Dp0=
|
github.com/grafana/grafana-aws-sdk v0.38.2 h1:TzQD0OpWsNjtldi5G5TLDlBRk8OyDf+B5ujcoAu4Dp0=
|
||||||
github.com/grafana/grafana-aws-sdk v0.38.2/go.mod h1:j3vi+cXYHEFqjhBGrI6/lw1TNM+dl0Y3f0cSnDOPy+s=
|
github.com/grafana/grafana-aws-sdk v0.38.2/go.mod h1:j3vi+cXYHEFqjhBGrI6/lw1TNM+dl0Y3f0cSnDOPy+s=
|
||||||
|
github.com/grafana/grafana-aws-sdk v1.0.2 h1:98eBuHYFmgvH0xO9kKf4RBsEsgQRp8EOA/9yhDIpkss=
|
||||||
|
github.com/grafana/grafana-aws-sdk v1.0.2/go.mod h1:hO7q7yWV+t6dmiyJjMa3IbuYnYkBua+G/IAlOPVIYKE=
|
||||||
github.com/grafana/grafana-plugin-sdk-go v0.263.0/go.mod h1:U43Cnrj/9DNYyvFcNdeUWNjMXTKNB0jcTcQGpWKd2gw=
|
github.com/grafana/grafana-plugin-sdk-go v0.263.0/go.mod h1:U43Cnrj/9DNYyvFcNdeUWNjMXTKNB0jcTcQGpWKd2gw=
|
||||||
github.com/grafana/grafana-plugin-sdk-go v0.267.0/go.mod h1:OuwS4c/JYgn0rr/w5zhJBpLo4gKm/vw15RsfpYAvK9Q=
|
github.com/grafana/grafana-plugin-sdk-go v0.267.0/go.mod h1:OuwS4c/JYgn0rr/w5zhJBpLo4gKm/vw15RsfpYAvK9Q=
|
||||||
github.com/grafana/grafana-plugin-sdk-go v0.269.1/go.mod h1:yv2KbO4mlr9WuDK2f+2gHAMTwwLmLuqaEnrPXTRU+OI=
|
github.com/grafana/grafana-plugin-sdk-go v0.269.1/go.mod h1:yv2KbO4mlr9WuDK2f+2gHAMTwwLmLuqaEnrPXTRU+OI=
|
||||||
@@ -1270,6 +1276,7 @@ golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 h1:VLliZ0d+/avPrXXH+OakdXhp
|
|||||||
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028 h1:4+4C/Iv2U4fMZBiMCc98MG1In4gJY5YRhtpDNeDeHWs=
|
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028 h1:4+4C/Iv2U4fMZBiMCc98MG1In4gJY5YRhtpDNeDeHWs=
|
||||||
golang.org/x/mod v0.6.0-dev.0.20220818022119-ed83ed61efb9/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
golang.org/x/mod v0.6.0-dev.0.20220818022119-ed83ed61efb9/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||||
golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
|
golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
|
||||||
|
golang.org/x/mod v0.23.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
|
||||||
golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
|
golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
|
||||||
golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||||
golang.org/x/net v0.0.0-20211123203042-d83791d6bcd9/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20211123203042-d83791d6bcd9/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
@@ -1297,6 +1304,7 @@ golang.org/x/time v0.8.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
|||||||
golang.org/x/time v0.10.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
golang.org/x/time v0.10.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||||
golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0=
|
golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0=
|
||||||
golang.org/x/tools v0.28.0/go.mod h1:dcIOrVd3mfQKTgrDVQHqCPMWy6lnhfhtX3hLXYVLfRw=
|
golang.org/x/tools v0.28.0/go.mod h1:dcIOrVd3mfQKTgrDVQHqCPMWy6lnhfhtX3hLXYVLfRw=
|
||||||
|
golang.org/x/tools v0.30.0/go.mod h1:c347cR/OJfw5TI+GfX7RUPNMdDRRbjvYTS0jPyvsVtY=
|
||||||
gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0 h1:OE9mWmgKkjJyEmDAAtGMPjXu+YNeGvK9VTSHY6+Qihc=
|
gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0 h1:OE9mWmgKkjJyEmDAAtGMPjXu+YNeGvK9VTSHY6+Qihc=
|
||||||
gonum.org/v1/plot v0.15.2 h1:Tlfh/jBk2tqjLZ4/P8ZIwGrLEWQSPDLRm/SNWKNXiGI=
|
gonum.org/v1/plot v0.15.2 h1:Tlfh/jBk2tqjLZ4/P8ZIwGrLEWQSPDLRm/SNWKNXiGI=
|
||||||
gonum.org/v1/plot v0.15.2/go.mod h1:DX+x+DWso3LTha+AdkJEv5Txvi+Tql3KAGkehP0/Ubg=
|
gonum.org/v1/plot v0.15.2/go.mod h1:DX+x+DWso3LTha+AdkJEv5Txvi+Tql3KAGkehP0/Ubg=
|
||||||
@@ -1382,6 +1390,7 @@ k8s.io/gengo/v2 v2.0.0-20250207200755-1244d31929d7 h1:2OX19X59HxDprNCVrWi6jb7LW1
|
|||||||
k8s.io/gengo/v2 v2.0.0-20250207200755-1244d31929d7/go.mod h1:EJykeLsmFC60UQbYJezXkEsG2FLrt0GPNkU5iK5GWxU=
|
k8s.io/gengo/v2 v2.0.0-20250207200755-1244d31929d7/go.mod h1:EJykeLsmFC60UQbYJezXkEsG2FLrt0GPNkU5iK5GWxU=
|
||||||
k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8=
|
k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8=
|
||||||
k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I=
|
k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I=
|
||||||
|
k8s.io/kms v0.33.2/go.mod h1:C1I8mjFFBNzfUZXYt9FZVJ8MJl7ynFbGgZFbBzkBJ3E=
|
||||||
lukechampine.com/uint128 v1.2.0 h1:mBi/5l91vocEN8otkC5bDLhi2KdCticRiwbdB0O+rjI=
|
lukechampine.com/uint128 v1.2.0 h1:mBi/5l91vocEN8otkC5bDLhi2KdCticRiwbdB0O+rjI=
|
||||||
modernc.org/cc/v3 v3.36.3 h1:uISP3F66UlixxWEcKuIWERa4TwrZENHSL8tWxZz8bHg=
|
modernc.org/cc/v3 v3.36.3 h1:uISP3F66UlixxWEcKuIWERa4TwrZENHSL8tWxZz8bHg=
|
||||||
modernc.org/ccgo/v3 v3.16.9 h1:AXquSwg7GuMk11pIdw7fmO1Y/ybgazVkMhsZWCV0mHM=
|
modernc.org/ccgo/v3 v3.16.9 h1:AXquSwg7GuMk11pIdw7fmO1Y/ybgazVkMhsZWCV0mHM=
|
||||||
|
|||||||
@@ -355,6 +355,7 @@
|
|||||||
"leven": "^4.0.0",
|
"leven": "^4.0.0",
|
||||||
"lodash": "4.17.21",
|
"lodash": "4.17.21",
|
||||||
"logfmt": "^1.3.2",
|
"logfmt": "^1.3.2",
|
||||||
|
"lossless-json": "^4.1.1",
|
||||||
"lru-cache": "11.1.0",
|
"lru-cache": "11.1.0",
|
||||||
"lru-memoize": "^1.1.0",
|
"lru-memoize": "^1.1.0",
|
||||||
"lucene": "^2.1.1",
|
"lucene": "^2.1.1",
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { defaultDataQueryKind, Spec } from './v2alpha1/types.spec.gen';
|
import { Spec } from './v2alpha1/types.spec.gen';
|
||||||
|
|
||||||
export const handyTestingSchema: Spec = {
|
export const handyTestingSchema: Spec = {
|
||||||
title: 'Default Dashboard',
|
title: 'Default Dashboard',
|
||||||
@@ -37,16 +37,15 @@ export const handyTestingSchema: Spec = {
|
|||||||
spec: {
|
spec: {
|
||||||
builtIn: false,
|
builtIn: false,
|
||||||
query: {
|
query: {
|
||||||
kind: 'DataQuery',
|
kind: 'prometheus',
|
||||||
version: defaultDataQueryKind().version,
|
|
||||||
group: 'prometheus',
|
|
||||||
datasource: {
|
|
||||||
name: 'uid',
|
|
||||||
},
|
|
||||||
spec: {
|
spec: {
|
||||||
expr: 'test-query',
|
expr: 'test-query',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
datasource: {
|
||||||
|
type: 'prometheus',
|
||||||
|
uid: 'uid',
|
||||||
|
},
|
||||||
filter: { ids: [1] },
|
filter: { ids: [1] },
|
||||||
enable: true,
|
enable: true,
|
||||||
hide: false,
|
hide: false,
|
||||||
@@ -58,16 +57,15 @@ export const handyTestingSchema: Spec = {
|
|||||||
kind: 'AnnotationQuery',
|
kind: 'AnnotationQuery',
|
||||||
spec: {
|
spec: {
|
||||||
builtIn: false,
|
builtIn: false,
|
||||||
|
datasource: {
|
||||||
|
type: 'grafana-testdata-datasource',
|
||||||
|
uid: 'uid',
|
||||||
|
},
|
||||||
enable: true,
|
enable: true,
|
||||||
iconColor: 'red',
|
iconColor: 'red',
|
||||||
name: 'Enabled',
|
name: 'Enabled',
|
||||||
query: {
|
query: {
|
||||||
kind: 'DataQuery',
|
kind: 'grafana-testdata-datasource',
|
||||||
version: defaultDataQueryKind().version,
|
|
||||||
group: 'grafana-testdata-datasource',
|
|
||||||
datasource: {
|
|
||||||
name: 'uid',
|
|
||||||
},
|
|
||||||
spec: {
|
spec: {
|
||||||
lines: 4,
|
lines: 4,
|
||||||
refId: 'Anno',
|
refId: 'Anno',
|
||||||
@@ -81,16 +79,15 @@ export const handyTestingSchema: Spec = {
|
|||||||
kind: 'AnnotationQuery',
|
kind: 'AnnotationQuery',
|
||||||
spec: {
|
spec: {
|
||||||
builtIn: false,
|
builtIn: false,
|
||||||
|
datasource: {
|
||||||
|
type: 'grafana-testdata-datasource',
|
||||||
|
uid: 'uid',
|
||||||
|
},
|
||||||
enable: false,
|
enable: false,
|
||||||
iconColor: 'yellow',
|
iconColor: 'yellow',
|
||||||
name: 'Disabled',
|
name: 'Disabled',
|
||||||
query: {
|
query: {
|
||||||
kind: 'DataQuery',
|
kind: 'grafana-testdata-datasource',
|
||||||
version: defaultDataQueryKind().version,
|
|
||||||
group: 'grafana-testdata-datasource',
|
|
||||||
datasource: {
|
|
||||||
name: 'uid',
|
|
||||||
},
|
|
||||||
spec: { lines: 5, refId: 'Anno', scenarioId: 'annotations' },
|
spec: { lines: 5, refId: 'Anno', scenarioId: 'annotations' },
|
||||||
},
|
},
|
||||||
hide: false,
|
hide: false,
|
||||||
@@ -100,17 +97,16 @@ export const handyTestingSchema: Spec = {
|
|||||||
kind: 'AnnotationQuery',
|
kind: 'AnnotationQuery',
|
||||||
spec: {
|
spec: {
|
||||||
builtIn: false,
|
builtIn: false,
|
||||||
|
datasource: {
|
||||||
|
type: 'grafana-testdata-datasource',
|
||||||
|
uid: 'uid',
|
||||||
|
},
|
||||||
enable: true,
|
enable: true,
|
||||||
hide: true,
|
hide: true,
|
||||||
iconColor: 'dark-purple',
|
iconColor: 'dark-purple',
|
||||||
name: 'Hidden',
|
name: 'Hidden',
|
||||||
query: {
|
query: {
|
||||||
kind: 'DataQuery',
|
kind: 'grafana-testdata-datasource',
|
||||||
version: defaultDataQueryKind().version,
|
|
||||||
group: 'grafana-testdata-datasource',
|
|
||||||
datasource: {
|
|
||||||
name: 'uid',
|
|
||||||
},
|
|
||||||
spec: {
|
spec: {
|
||||||
lines: 6,
|
lines: 6,
|
||||||
refId: 'Anno',
|
refId: 'Anno',
|
||||||
@@ -132,13 +128,12 @@ export const handyTestingSchema: Spec = {
|
|||||||
kind: 'PanelQuery',
|
kind: 'PanelQuery',
|
||||||
spec: {
|
spec: {
|
||||||
refId: 'A',
|
refId: 'A',
|
||||||
|
datasource: {
|
||||||
|
type: 'prometheus',
|
||||||
|
uid: 'datasource1',
|
||||||
|
},
|
||||||
query: {
|
query: {
|
||||||
kind: 'DataQuery',
|
kind: 'prometheus',
|
||||||
version: defaultDataQueryKind().version,
|
|
||||||
group: 'prometheus',
|
|
||||||
datasource: {
|
|
||||||
name: 'datasource1',
|
|
||||||
},
|
|
||||||
spec: {
|
spec: {
|
||||||
expr: 'test-query',
|
expr: 'test-query',
|
||||||
},
|
},
|
||||||
@@ -270,6 +265,10 @@ export const handyTestingSchema: Spec = {
|
|||||||
text: 'text1',
|
text: 'text1',
|
||||||
value: 'value1',
|
value: 'value1',
|
||||||
},
|
},
|
||||||
|
datasource: {
|
||||||
|
type: 'prometheus',
|
||||||
|
uid: 'datasource1',
|
||||||
|
},
|
||||||
definition: 'definition1',
|
definition: 'definition1',
|
||||||
description: 'A query variable',
|
description: 'A query variable',
|
||||||
hide: 'dontHide',
|
hide: 'dontHide',
|
||||||
@@ -279,12 +278,7 @@ export const handyTestingSchema: Spec = {
|
|||||||
name: 'queryVar',
|
name: 'queryVar',
|
||||||
options: [],
|
options: [],
|
||||||
query: {
|
query: {
|
||||||
kind: 'DataQuery',
|
kind: 'prometheus',
|
||||||
version: defaultDataQueryKind().version,
|
|
||||||
group: 'prometheus',
|
|
||||||
datasource: {
|
|
||||||
name: 'datasource1',
|
|
||||||
},
|
|
||||||
spec: {
|
spec: {
|
||||||
expr: 'test-query',
|
expr: 'test-query',
|
||||||
refId: 'A',
|
refId: 'A',
|
||||||
|
|||||||
@@ -11,19 +11,19 @@ export const defaultAnnotationQueryKind = (): AnnotationQueryKind => ({
|
|||||||
});
|
});
|
||||||
|
|
||||||
export interface AnnotationQuerySpec {
|
export interface AnnotationQuerySpec {
|
||||||
query: DataQueryKind;
|
datasource?: DataSourceRef;
|
||||||
|
query?: DataQueryKind;
|
||||||
enable: boolean;
|
enable: boolean;
|
||||||
hide: boolean;
|
hide: boolean;
|
||||||
iconColor: string;
|
iconColor: string;
|
||||||
name: string;
|
name: string;
|
||||||
builtIn?: boolean;
|
builtIn?: boolean;
|
||||||
filter?: AnnotationPanelFilter;
|
filter?: AnnotationPanelFilter;
|
||||||
// Catch-all field for datasource-specific properties. Should not be available in as code tooling.
|
// Catch-all field for datasource-specific properties
|
||||||
legacyOptions?: Record<string, any>;
|
legacyOptions?: Record<string, any>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const defaultAnnotationQuerySpec = (): AnnotationQuerySpec => ({
|
export const defaultAnnotationQuerySpec = (): AnnotationQuerySpec => ({
|
||||||
query: defaultDataQueryKind(),
|
|
||||||
enable: false,
|
enable: false,
|
||||||
hide: false,
|
hide: false,
|
||||||
iconColor: "",
|
iconColor: "",
|
||||||
@@ -31,22 +31,24 @@ export const defaultAnnotationQuerySpec = (): AnnotationQuerySpec => ({
|
|||||||
builtIn: false,
|
builtIn: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export interface DataSourceRef {
|
||||||
|
// The plugin type-id
|
||||||
|
type?: string;
|
||||||
|
// Specific datasource instance
|
||||||
|
uid?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const defaultDataSourceRef = (): DataSourceRef => ({
|
||||||
|
});
|
||||||
|
|
||||||
export interface DataQueryKind {
|
export interface DataQueryKind {
|
||||||
kind: "DataQuery";
|
// The kind of a DataQueryKind is the datasource type
|
||||||
group: string;
|
kind: string;
|
||||||
version: string;
|
|
||||||
// New type for datasource reference
|
|
||||||
// Not creating a new type until we figure out how to handle DS refs for group by, adhoc, and every place that uses DataSourceRef in TS.
|
|
||||||
datasource?: {
|
|
||||||
name?: string;
|
|
||||||
};
|
|
||||||
spec: Record<string, any>;
|
spec: Record<string, any>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const defaultDataQueryKind = (): DataQueryKind => ({
|
export const defaultDataQueryKind = (): DataQueryKind => ({
|
||||||
kind: "DataQuery",
|
kind: "",
|
||||||
group: "",
|
|
||||||
version: "v0",
|
|
||||||
spec: {},
|
spec: {},
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -149,6 +151,7 @@ export const defaultPanelQueryKind = (): PanelQueryKind => ({
|
|||||||
|
|
||||||
export interface PanelQuerySpec {
|
export interface PanelQuerySpec {
|
||||||
query: DataQueryKind;
|
query: DataQueryKind;
|
||||||
|
datasource?: DataSourceRef;
|
||||||
refId: string;
|
refId: string;
|
||||||
hidden: boolean;
|
hidden: boolean;
|
||||||
}
|
}
|
||||||
@@ -991,6 +994,7 @@ export interface QueryVariableSpec {
|
|||||||
refresh: VariableRefresh;
|
refresh: VariableRefresh;
|
||||||
skipUrlSync: boolean;
|
skipUrlSync: boolean;
|
||||||
description?: string;
|
description?: string;
|
||||||
|
datasource?: DataSourceRef;
|
||||||
query: DataQueryKind;
|
query: DataQueryKind;
|
||||||
regex: string;
|
regex: string;
|
||||||
sort: VariableSort;
|
sort: VariableSort;
|
||||||
@@ -1279,18 +1283,6 @@ export const defaultGroupByVariableSpec = (): GroupByVariableSpec => ({
|
|||||||
skipUrlSync: false,
|
skipUrlSync: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Keeping this for backwards compatibility for GroupByVariableSpec and AdhocVariableSpec
|
|
||||||
// This type is widely used in the codebase and changing it will have a big impact
|
|
||||||
export interface DataSourceRef {
|
|
||||||
// The plugin type-id
|
|
||||||
type?: string;
|
|
||||||
// Specific datasource instance
|
|
||||||
uid?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const defaultDataSourceRef = (): DataSourceRef => ({
|
|
||||||
});
|
|
||||||
|
|
||||||
// Adhoc variable kind
|
// Adhoc variable kind
|
||||||
export interface AdhocVariableKind {
|
export interface AdhocVariableKind {
|
||||||
kind: "AdhocVariable";
|
kind: "AdhocVariable";
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ func convertToK8sResource(v *folder.Folder, namespacer request.NamespaceMapper)
|
|||||||
},
|
},
|
||||||
Spec: folders.FolderSpec{
|
Spec: folders.FolderSpec{
|
||||||
Title: v.Title,
|
Title: v.Title,
|
||||||
Description: descr(v.Description),
|
Description: &v.Description,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -94,10 +94,3 @@ func convertToK8sResource(v *folder.Folder, namespacer request.NamespaceMapper)
|
|||||||
f.UID = gapiutil.CalculateClusterWideUID(f)
|
f.UID = gapiutil.CalculateClusterWideUID(f)
|
||||||
return f, nil
|
return f, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func descr(str string) *string {
|
|
||||||
if str == "" {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return &str
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -45,6 +45,10 @@ func TestIntegrationFoldersApp(t *testing.T) {
|
|||||||
if testing.Short() {
|
if testing.Short() {
|
||||||
t.Skip("skipping integration test")
|
t.Skip("skipping integration test")
|
||||||
}
|
}
|
||||||
|
if !db.IsTestDbSQLite() {
|
||||||
|
t.Skip("test only on sqlite for now")
|
||||||
|
}
|
||||||
|
|
||||||
helper := apis.NewK8sTestHelper(t, testinfra.GrafanaOpts{
|
helper := apis.NewK8sTestHelper(t, testinfra.GrafanaOpts{
|
||||||
AppModeProduction: true,
|
AppModeProduction: true,
|
||||||
EnableFeatureToggles: []string{
|
EnableFeatureToggles: []string{
|
||||||
@@ -120,71 +124,94 @@ func TestIntegrationFoldersApp(t *testing.T) {
|
|||||||
}`, string(v1Disco))
|
}`, string(v1Disco))
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("with dual write (unified storage, mode 0)", func(t *testing.T) {
|
// test on all dualwriter modes
|
||||||
doFolderTests(t, apis.NewK8sTestHelper(t, testinfra.GrafanaOpts{
|
for mode := 0; mode <= 4; mode++ {
|
||||||
AppModeProduction: true,
|
modeDw := grafanarest.DualWriterMode(mode)
|
||||||
DisableAnonymous: true,
|
|
||||||
APIServerStorageType: "unified",
|
|
||||||
UnifiedStorageConfig: map[string]setting.UnifiedStorageConfig{
|
|
||||||
folders.RESOURCEGROUP: {
|
|
||||||
DualWriterMode: grafanarest.Mode0,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
EnableFeatureToggles: []string{
|
|
||||||
featuremgmt.FlagKubernetesClientDashboardsFolders,
|
|
||||||
},
|
|
||||||
}))
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("with dual write (unified storage, mode 1)", func(t *testing.T) {
|
t.Run(fmt.Sprintf("with dual write (unified storage, mode %v)", modeDw), func(t *testing.T) {
|
||||||
doFolderTests(t, apis.NewK8sTestHelper(t, testinfra.GrafanaOpts{
|
doFolderTests(t, apis.NewK8sTestHelper(t, testinfra.GrafanaOpts{
|
||||||
AppModeProduction: true,
|
AppModeProduction: true,
|
||||||
DisableAnonymous: true,
|
DisableAnonymous: true,
|
||||||
APIServerStorageType: "unified",
|
APIServerStorageType: "unified",
|
||||||
UnifiedStorageConfig: map[string]setting.UnifiedStorageConfig{
|
UnifiedStorageConfig: map[string]setting.UnifiedStorageConfig{
|
||||||
folders.RESOURCEGROUP: {
|
folders.RESOURCEGROUP: {
|
||||||
DualWriterMode: grafanarest.Mode1,
|
DualWriterMode: modeDw,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
EnableFeatureToggles: []string{
|
||||||
EnableFeatureToggles: []string{
|
featuremgmt.FlagKubernetesClientDashboardsFolders,
|
||||||
featuremgmt.FlagKubernetesClientDashboardsFolders,
|
},
|
||||||
},
|
}))
|
||||||
}))
|
})
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("with dual write (unified storage, mode 1, create nested folders)", func(t *testing.T) {
|
t.Run(fmt.Sprintf("with dual write (unified storage, mode %v, create nested folders)", modeDw), func(t *testing.T) {
|
||||||
doNestedCreateTest(t, apis.NewK8sTestHelper(t, testinfra.GrafanaOpts{
|
doNestedCreateTest(t, apis.NewK8sTestHelper(t, testinfra.GrafanaOpts{
|
||||||
AppModeProduction: true,
|
AppModeProduction: true,
|
||||||
DisableAnonymous: true,
|
DisableAnonymous: true,
|
||||||
APIServerStorageType: "unified",
|
APIServerStorageType: "unified",
|
||||||
UnifiedStorageConfig: map[string]setting.UnifiedStorageConfig{
|
UnifiedStorageConfig: map[string]setting.UnifiedStorageConfig{
|
||||||
folders.RESOURCEGROUP: {
|
folders.RESOURCEGROUP: {
|
||||||
DualWriterMode: grafanarest.Mode1,
|
DualWriterMode: modeDw,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
EnableFeatureToggles: []string{
|
||||||
EnableFeatureToggles: []string{
|
featuremgmt.FlagKubernetesClientDashboardsFolders,
|
||||||
featuremgmt.FlagKubernetesClientDashboardsFolders,
|
featuremgmt.FlagNestedFolders,
|
||||||
featuremgmt.FlagNestedFolders,
|
},
|
||||||
},
|
}))
|
||||||
}))
|
})
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("with dual write (unified storage, mode 1, create existing folder)", func(t *testing.T) {
|
t.Run(fmt.Sprintf("with dual write (unified storage, mode %v, create existing folder)", modeDw), func(t *testing.T) {
|
||||||
doCreateDuplicateFolderTest(t, apis.NewK8sTestHelper(t, testinfra.GrafanaOpts{
|
doCreateDuplicateFolderTest(t, apis.NewK8sTestHelper(t, testinfra.GrafanaOpts{
|
||||||
AppModeProduction: true,
|
AppModeProduction: true,
|
||||||
DisableAnonymous: true,
|
DisableAnonymous: true,
|
||||||
APIServerStorageType: "unified",
|
APIServerStorageType: "unified",
|
||||||
UnifiedStorageConfig: map[string]setting.UnifiedStorageConfig{
|
UnifiedStorageConfig: map[string]setting.UnifiedStorageConfig{
|
||||||
folders.RESOURCEGROUP: {
|
folders.RESOURCEGROUP: {
|
||||||
DualWriterMode: grafanarest.Mode1,
|
DualWriterMode: modeDw,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
EnableFeatureToggles: []string{
|
||||||
EnableFeatureToggles: []string{
|
featuremgmt.FlagKubernetesClientDashboardsFolders,
|
||||||
featuremgmt.FlagKubernetesClientDashboardsFolders,
|
featuremgmt.FlagNestedFolders,
|
||||||
featuremgmt.FlagNestedFolders,
|
},
|
||||||
},
|
}))
|
||||||
}))
|
})
|
||||||
})
|
|
||||||
|
t.Run(fmt.Sprintf("when creating a folder, mode %v, it should trim leading and trailing spaces", modeDw), func(t *testing.T) {
|
||||||
|
doCreateEnsureTitleIsTrimmedTest(t, apis.NewK8sTestHelper(t, testinfra.GrafanaOpts{
|
||||||
|
AppModeProduction: true,
|
||||||
|
DisableAnonymous: true,
|
||||||
|
APIServerStorageType: "unified",
|
||||||
|
UnifiedStorageConfig: map[string]setting.UnifiedStorageConfig{
|
||||||
|
folders.RESOURCEGROUP: {
|
||||||
|
DualWriterMode: modeDw,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
EnableFeatureToggles: []string{
|
||||||
|
featuremgmt.FlagKubernetesClientDashboardsFolders,
|
||||||
|
featuremgmt.FlagNestedFolders,
|
||||||
|
},
|
||||||
|
}))
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run(fmt.Sprintf("with dual write (unified storage, mode %v, create circular reference folder)", modeDw), func(t *testing.T) {
|
||||||
|
doCreateCircularReferenceFolderTest(t, apis.NewK8sTestHelper(t, testinfra.GrafanaOpts{
|
||||||
|
AppModeProduction: true,
|
||||||
|
DisableAnonymous: true,
|
||||||
|
APIServerStorageType: "unified",
|
||||||
|
UnifiedStorageConfig: map[string]setting.UnifiedStorageConfig{
|
||||||
|
folders.RESOURCEGROUP: {
|
||||||
|
DualWriterMode: modeDw,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
EnableFeatureToggles: []string{
|
||||||
|
featuremgmt.FlagKubernetesClientDashboardsFolders,
|
||||||
|
featuremgmt.FlagNestedFolders,
|
||||||
|
},
|
||||||
|
}))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// This is a general test for the unified storage list operation. We don't have a common test
|
// This is a general test for the unified storage list operation. We don't have a common test
|
||||||
// directory for now, so we (search and storage) keep it here as we own this part of the tests.
|
// directory for now, so we (search and storage) keep it here as we own this part of the tests.
|
||||||
@@ -217,40 +244,6 @@ func TestIntegrationFoldersApp(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("when creating a folder it should trim leading and trailing spaces", func(t *testing.T) {
|
|
||||||
doCreateEnsureTitleIsTrimmedTest(t, apis.NewK8sTestHelper(t, testinfra.GrafanaOpts{
|
|
||||||
AppModeProduction: true,
|
|
||||||
DisableAnonymous: true,
|
|
||||||
APIServerStorageType: "unified",
|
|
||||||
UnifiedStorageConfig: map[string]setting.UnifiedStorageConfig{
|
|
||||||
folders.RESOURCEGROUP: {
|
|
||||||
DualWriterMode: grafanarest.Mode1,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
EnableFeatureToggles: []string{
|
|
||||||
featuremgmt.FlagKubernetesClientDashboardsFolders,
|
|
||||||
featuremgmt.FlagNestedFolders,
|
|
||||||
},
|
|
||||||
}))
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("with dual write (unified storage, mode 1, create circular reference folder)", func(t *testing.T) {
|
|
||||||
doCreateCircularReferenceFolderTest(t, apis.NewK8sTestHelper(t, testinfra.GrafanaOpts{
|
|
||||||
AppModeProduction: true,
|
|
||||||
DisableAnonymous: true,
|
|
||||||
APIServerStorageType: "unified",
|
|
||||||
UnifiedStorageConfig: map[string]setting.UnifiedStorageConfig{
|
|
||||||
folders.RESOURCEGROUP: {
|
|
||||||
DualWriterMode: grafanarest.Mode1,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
EnableFeatureToggles: []string{
|
|
||||||
featuremgmt.FlagKubernetesClientDashboardsFolders,
|
|
||||||
featuremgmt.FlagNestedFolders,
|
|
||||||
},
|
|
||||||
}))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func doFolderTests(t *testing.T, helper *apis.K8sTestHelper) *apis.K8sTestHelper {
|
func doFolderTests(t *testing.T, helper *apis.K8sTestHelper) *apis.K8sTestHelper {
|
||||||
@@ -276,20 +269,25 @@ func doFolderTests(t *testing.T, helper *apis.K8sTestHelper) *apis.K8sTestHelper
|
|||||||
require.NotNil(t, legacyCreate.Result)
|
require.NotNil(t, legacyCreate.Result)
|
||||||
uid := legacyCreate.Result.UID
|
uid := legacyCreate.Result.UID
|
||||||
require.NotEmpty(t, uid)
|
require.NotEmpty(t, uid)
|
||||||
|
//nolint:staticcheck
|
||||||
|
id := legacyCreate.Result.ID
|
||||||
|
require.NotEmpty(t, id)
|
||||||
|
idStr := fmt.Sprintf("%d", id)
|
||||||
|
|
||||||
expectedResult := `{
|
expectedResult := `{
|
||||||
"apiVersion": "folder.grafana.app/v1beta1",
|
"apiVersion": "folder.grafana.app/v1beta1",
|
||||||
"kind": "Folder",
|
"kind": "Folder",
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"creationTimestamp": "${creationTimestamp}",
|
"creationTimestamp": "${creationTimestamp}",
|
||||||
"labels": {"grafana.app/deprecatedInternalID":"1"},
|
"labels": {"grafana.app/deprecatedInternalID":"` + idStr + `"},
|
||||||
"name": "` + uid + `",
|
"name": "` + uid + `",
|
||||||
"namespace": "default",
|
"namespace": "default",
|
||||||
"resourceVersion": "${resourceVersion}",
|
"resourceVersion": "${resourceVersion}",
|
||||||
"uid": "${uid}"
|
"uid": "${uid}"
|
||||||
},
|
},
|
||||||
"spec": {
|
"spec": {
|
||||||
"title": "Test"
|
"title": "Test",
|
||||||
|
"description": ""
|
||||||
},
|
},
|
||||||
"status": {}
|
"status": {}
|
||||||
}`
|
}`
|
||||||
@@ -592,6 +590,9 @@ func TestIntegrationFolderCreatePermissions(t *testing.T) {
|
|||||||
if testing.Short() {
|
if testing.Short() {
|
||||||
t.Skip("skipping integration test")
|
t.Skip("skipping integration test")
|
||||||
}
|
}
|
||||||
|
if !db.IsTestDbSQLite() {
|
||||||
|
t.Skip("test only on sqlite for now")
|
||||||
|
}
|
||||||
|
|
||||||
folderWithoutParentInput := "{ \"uid\": \"uid\", \"title\": \"Folder\"}"
|
folderWithoutParentInput := "{ \"uid\": \"uid\", \"title\": \"Folder\"}"
|
||||||
folderWithParentInput := "{ \"uid\": \"uid\", \"title\": \"Folder\", \"parentUid\": \"parentuid\"}"
|
folderWithParentInput := "{ \"uid\": \"uid\", \"title\": \"Folder\", \"parentUid\": \"parentuid\"}"
|
||||||
@@ -716,6 +717,9 @@ func TestIntegrationFolderGetPermissions(t *testing.T) {
|
|||||||
if testing.Short() {
|
if testing.Short() {
|
||||||
t.Skip("skipping integration test")
|
t.Skip("skipping integration test")
|
||||||
}
|
}
|
||||||
|
if !db.IsTestDbSQLite() {
|
||||||
|
t.Skip("test only on sqlite for now")
|
||||||
|
}
|
||||||
|
|
||||||
type testCase struct {
|
type testCase struct {
|
||||||
description string
|
description string
|
||||||
@@ -866,6 +870,9 @@ func TestIntegrationFoldersCreateAPIEndpointK8S(t *testing.T) {
|
|||||||
if testing.Short() {
|
if testing.Short() {
|
||||||
t.Skip("skipping integration test")
|
t.Skip("skipping integration test")
|
||||||
}
|
}
|
||||||
|
if !db.IsTestDbSQLite() {
|
||||||
|
t.Skip("test only on sqlite for now")
|
||||||
|
}
|
||||||
|
|
||||||
folderWithoutParentInput := "{ \"uid\": \"uid\", \"title\": \"Folder\"}"
|
folderWithoutParentInput := "{ \"uid\": \"uid\", \"title\": \"Folder\"}"
|
||||||
folderWithTitleEmpty := "{ \"title\": \"\"}"
|
folderWithTitleEmpty := "{ \"title\": \"\"}"
|
||||||
@@ -1027,7 +1034,6 @@ func TestIntegrationFoldersGetAPIEndpointK8S(t *testing.T) {
|
|||||||
if testing.Short() {
|
if testing.Short() {
|
||||||
t.Skip("skipping integration test")
|
t.Skip("skipping integration test")
|
||||||
}
|
}
|
||||||
|
|
||||||
if !db.IsTestDbSQLite() {
|
if !db.IsTestDbSQLite() {
|
||||||
t.Skip("test only on sqlite for now")
|
t.Skip("test only on sqlite for now")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1250,7 +1250,6 @@
|
|||||||
"com.github.grafana.grafana.apps.dashboard.pkg.apis.dashboard.v2alpha1.DashboardAnnotationQuerySpec": {
|
"com.github.grafana.grafana.apps.dashboard.pkg.apis.dashboard.v2alpha1.DashboardAnnotationQuerySpec": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
"required": [
|
||||||
"query",
|
|
||||||
"enable",
|
"enable",
|
||||||
"hide",
|
"hide",
|
||||||
"iconColor",
|
"iconColor",
|
||||||
@@ -1260,6 +1259,9 @@
|
|||||||
"builtIn": {
|
"builtIn": {
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
},
|
},
|
||||||
|
"datasource": {
|
||||||
|
"$ref": "#/components/schemas/com.github.grafana.grafana.apps.dashboard.pkg.apis.dashboard.v2alpha1.DashboardDataSourceRef"
|
||||||
|
},
|
||||||
"enable": {
|
"enable": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": false
|
"default": false
|
||||||
@@ -1276,7 +1278,7 @@
|
|||||||
"default": ""
|
"default": ""
|
||||||
},
|
},
|
||||||
"legacyOptions": {
|
"legacyOptions": {
|
||||||
"description": "Catch-all field for datasource-specific properties. Should not be available in as code tooling.",
|
"description": "Catch-all field for datasource-specific properties",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"additionalProperties": {
|
"additionalProperties": {
|
||||||
"type": "object"
|
"type": "object"
|
||||||
@@ -1287,12 +1289,7 @@
|
|||||||
"default": ""
|
"default": ""
|
||||||
},
|
},
|
||||||
"query": {
|
"query": {
|
||||||
"default": {},
|
"$ref": "#/components/schemas/com.github.grafana.grafana.apps.dashboard.pkg.apis.dashboard.v2alpha1.DashboardDataQueryKind"
|
||||||
"allOf": [
|
|
||||||
{
|
|
||||||
"$ref": "#/components/schemas/com.github.grafana.grafana.apps.dashboard.pkg.apis.dashboard.v2alpha1.DashboardDataQueryKind"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -1868,24 +1865,11 @@
|
|||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
"required": [
|
||||||
"kind",
|
"kind",
|
||||||
"group",
|
|
||||||
"version",
|
|
||||||
"spec"
|
"spec"
|
||||||
],
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
"datasource": {
|
|
||||||
"description": "New type for datasource reference Not creating a new type until we figure out how to handle DS refs for group by, adhoc, and every place that uses DataSourceRef in TS.",
|
|
||||||
"allOf": [
|
|
||||||
{
|
|
||||||
"$ref": "#/components/schemas/com.github.grafana.grafana.apps.dashboard.pkg.apis.dashboard.v2alpha1.DashboardV2alpha1DataQueryKindDatasource"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"group": {
|
|
||||||
"type": "string",
|
|
||||||
"default": ""
|
|
||||||
},
|
|
||||||
"kind": {
|
"kind": {
|
||||||
|
"description": "The kind of a DataQueryKind is the datasource type",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"default": ""
|
"default": ""
|
||||||
},
|
},
|
||||||
@@ -1894,15 +1878,10 @@
|
|||||||
"additionalProperties": {
|
"additionalProperties": {
|
||||||
"type": "object"
|
"type": "object"
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"version": {
|
|
||||||
"type": "string",
|
|
||||||
"default": ""
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"com.github.grafana.grafana.apps.dashboard.pkg.apis.dashboard.v2alpha1.DashboardDataSourceRef": {
|
"com.github.grafana.grafana.apps.dashboard.pkg.apis.dashboard.v2alpha1.DashboardDataSourceRef": {
|
||||||
"description": "Keeping this for backwards compatibility for GroupByVariableSpec and AdhocVariableSpec This type is widely used in the codebase and changing it will have a big impact",
|
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"type": {
|
"type": {
|
||||||
@@ -2764,6 +2743,9 @@
|
|||||||
"hidden"
|
"hidden"
|
||||||
],
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
|
"datasource": {
|
||||||
|
"$ref": "#/components/schemas/com.github.grafana.grafana.apps.dashboard.pkg.apis.dashboard.v2alpha1.DashboardDataSourceRef"
|
||||||
|
},
|
||||||
"hidden": {
|
"hidden": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": false
|
"default": false
|
||||||
@@ -3011,6 +2993,9 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"datasource": {
|
||||||
|
"$ref": "#/components/schemas/com.github.grafana.grafana.apps.dashboard.pkg.apis.dashboard.v2alpha1.DashboardDataSourceRef"
|
||||||
|
},
|
||||||
"definition": {
|
"definition": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
@@ -3740,14 +3725,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"com.github.grafana.grafana.apps.dashboard.pkg.apis.dashboard.v2alpha1.DashboardV2alpha1DataQueryKindDatasource": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"name": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"com.github.grafana.grafana.apps.dashboard.pkg.apis.dashboard.v2alpha1.DashboardV2alpha1FieldConfigSourceOverrides": {
|
"com.github.grafana.grafana.apps.dashboard.pkg.apis.dashboard.v2alpha1.DashboardV2alpha1FieldConfigSourceOverrides": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
"required": [
|
||||||
|
|||||||
@@ -15,6 +15,17 @@ jest.mock('@grafana/runtime', () => ({
|
|||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
Object.assign(navigator, {
|
||||||
|
clipboard: {
|
||||||
|
write: jest.fn().mockResolvedValue(undefined),
|
||||||
|
writeText: jest.fn().mockResolvedValue(undefined),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
document.execCommand = jest.fn();
|
||||||
|
});
|
||||||
|
|
||||||
describe('createShortLink', () => {
|
describe('createShortLink', () => {
|
||||||
it('creates short link', async () => {
|
it('creates short link', async () => {
|
||||||
const shortUrl = await createShortLink('www.verylonglinkwehavehere.com');
|
const shortUrl = await createShortLink('www.verylonglinkwehavehere.com');
|
||||||
@@ -23,11 +34,34 @@ describe('createShortLink', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('createAndCopyShortLink', () => {
|
describe('createAndCopyShortLink', () => {
|
||||||
it('copies short link to clipboard', async () => {
|
it('copies short link to clipboard via document.execCommand when navigator.clipboard is undefined', async () => {
|
||||||
|
Object.assign(navigator, {
|
||||||
|
clipboard: {
|
||||||
|
write: undefined,
|
||||||
|
},
|
||||||
|
});
|
||||||
document.execCommand = jest.fn();
|
document.execCommand = jest.fn();
|
||||||
await createAndCopyShortLink('www.verylonglinkwehavehere.com');
|
await createAndCopyShortLink('www.verylonglinkwehavehere.com');
|
||||||
expect(document.execCommand).toHaveBeenCalledWith('copy');
|
expect(document.execCommand).toHaveBeenCalledWith('copy');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('copies short link to clipboard via navigator.clipboard.writeText when ClipboardItem is undefined', async () => {
|
||||||
|
window.isSecureContext = true;
|
||||||
|
await createAndCopyShortLink('www.verylonglinkwehavehere.com');
|
||||||
|
expect(navigator.clipboard.writeText).toHaveBeenCalledWith('www.short.com');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('copies short link to clipboard via navigator.clipboard.write and ClipboardItem when it is defined', async () => {
|
||||||
|
global.ClipboardItem = jest.fn().mockImplementation(() => ({
|
||||||
|
type: 'text/plain',
|
||||||
|
size: 0,
|
||||||
|
slice: jest.fn(),
|
||||||
|
supports: jest.fn().mockReturnValue(true),
|
||||||
|
// eslint-disable-next-line
|
||||||
|
})) as any;
|
||||||
|
await createAndCopyShortLink('www.verylonglinkwehavehere.com');
|
||||||
|
expect(navigator.clipboard.write).toHaveBeenCalled();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('getLogsPermalinkRange', () => {
|
describe('getLogsPermalinkRange', () => {
|
||||||
|
|||||||
@@ -35,13 +35,30 @@ export const createShortLink = memoizeOne(async function (path: string) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a ClipboardItem for the shortened link. This is used due to clipboard issues in Safari after making async calls.
|
||||||
|
* See https://github.com/grafana/grafana/issues/106889
|
||||||
|
* @param path - The long path to share.
|
||||||
|
* @returns A ClipboardItem for the shortened link.
|
||||||
|
*/
|
||||||
|
const createShortLinkClipboardItem = (path: string) => {
|
||||||
|
return new ClipboardItem({
|
||||||
|
'text/plain': createShortLink(path),
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
export const createAndCopyShortLink = async (path: string) => {
|
export const createAndCopyShortLink = async (path: string) => {
|
||||||
const shortLink = await createShortLink(path);
|
if (typeof ClipboardItem !== 'undefined' && navigator.clipboard.write) {
|
||||||
if (shortLink) {
|
navigator.clipboard.write([createShortLinkClipboardItem(path)]);
|
||||||
copyStringToClipboard(shortLink);
|
|
||||||
dispatch(notifyApp(createSuccessNotification('Shortened link copied to clipboard')));
|
dispatch(notifyApp(createSuccessNotification('Shortened link copied to clipboard')));
|
||||||
} else {
|
} else {
|
||||||
dispatch(notifyApp(createErrorNotification('Error generating shortened link')));
|
const shortLink = await createShortLink(path);
|
||||||
|
if (shortLink) {
|
||||||
|
copyStringToClipboard(shortLink);
|
||||||
|
dispatch(notifyApp(createSuccessNotification('Shortened link copied to clipboard')));
|
||||||
|
} else {
|
||||||
|
dispatch(notifyApp(createErrorNotification('Error generating shortened link')));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -37,39 +37,6 @@ jest.mock('@grafana/runtime', () => {
|
|||||||
...original.config.featureToggles,
|
...original.config.featureToggles,
|
||||||
dashboardNewLayouts: false, // Default value
|
dashboardNewLayouts: false, // Default value
|
||||||
},
|
},
|
||||||
|
|
||||||
bootData: {
|
|
||||||
...original.config.bootData,
|
|
||||||
settings: {
|
|
||||||
...original.config.bootData.settings,
|
|
||||||
datasources: {
|
|
||||||
'gdev-testdata': {
|
|
||||||
id: 7,
|
|
||||||
uid: 'abc',
|
|
||||||
type: 'grafana-testdata-datasource',
|
|
||||||
name: 'gdev-testdata',
|
|
||||||
meta: {
|
|
||||||
id: 'grafana-testdata-datasource',
|
|
||||||
type: 'datasource',
|
|
||||||
name: 'TestData',
|
|
||||||
aliasIDs: ['testdata'],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
'-- Grafana --': {
|
|
||||||
id: -1,
|
|
||||||
uid: 'grafana',
|
|
||||||
type: 'datasource',
|
|
||||||
name: '-- Grafana --',
|
|
||||||
meta: {
|
|
||||||
id: 'grafana',
|
|
||||||
type: 'datasource',
|
|
||||||
name: '-- Grafana --',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
defaultDatasource: 'gdev-testdata',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
@@ -1621,11 +1588,9 @@ const v2ProvisionedDashboardResource = {
|
|||||||
kind: 'AnnotationQuery',
|
kind: 'AnnotationQuery',
|
||||||
spec: {
|
spec: {
|
||||||
builtIn: true,
|
builtIn: true,
|
||||||
query: {
|
datasource: {
|
||||||
kind: 'DataQuery',
|
type: 'grafana',
|
||||||
group: 'grafana',
|
uid: '-- Grafana --',
|
||||||
spec: {},
|
|
||||||
version: 'v0',
|
|
||||||
},
|
},
|
||||||
enable: true,
|
enable: true,
|
||||||
hide: true,
|
hide: true,
|
||||||
@@ -1648,14 +1613,13 @@ const v2ProvisionedDashboardResource = {
|
|||||||
{
|
{
|
||||||
kind: 'PanelQuery',
|
kind: 'PanelQuery',
|
||||||
spec: {
|
spec: {
|
||||||
|
datasource: {
|
||||||
|
type: 'grafana-testdata-datasource',
|
||||||
|
uid: 'PD8C576611E62080A',
|
||||||
|
},
|
||||||
hidden: false,
|
hidden: false,
|
||||||
query: {
|
query: {
|
||||||
kind: 'DataQuery',
|
kind: 'grafana-testdata-datasource',
|
||||||
group: 'grafana-testdata-datasource',
|
|
||||||
version: 'v0',
|
|
||||||
datasource: {
|
|
||||||
name: 'PD8C576611E62080A',
|
|
||||||
},
|
|
||||||
spec: {
|
spec: {
|
||||||
scenarioId: 'random_walk',
|
scenarioId: 'random_walk',
|
||||||
seriesCount: 2,
|
seriesCount: 2,
|
||||||
|
|||||||
@@ -549,12 +549,13 @@ describe('dashboard exporter v2', () => {
|
|||||||
{
|
{
|
||||||
kind: 'PanelQuery',
|
kind: 'PanelQuery',
|
||||||
spec: {
|
spec: {
|
||||||
|
datasource: {
|
||||||
|
type: 'prometheus',
|
||||||
|
uid: '${datasourceVar}',
|
||||||
|
},
|
||||||
hidden: false,
|
hidden: false,
|
||||||
query: {
|
query: {
|
||||||
datasource: {
|
kind: 'prometheus',
|
||||||
name: '${datasourceVar}',
|
|
||||||
},
|
|
||||||
group: 'prometheus',
|
|
||||||
spec: {
|
spec: {
|
||||||
editorMode: 'builder',
|
editorMode: 'builder',
|
||||||
expr: 'go_goroutines{job="prometheus"}',
|
expr: 'go_goroutines{job="prometheus"}',
|
||||||
@@ -582,7 +583,7 @@ describe('dashboard exporter v2', () => {
|
|||||||
it('should replace datasource in a query variable', async () => {
|
it('should replace datasource in a query variable', async () => {
|
||||||
const { dashboard } = await setup();
|
const { dashboard } = await setup();
|
||||||
const variable = dashboard.variables[0] as QueryVariableKind;
|
const variable = dashboard.variables[0] as QueryVariableKind;
|
||||||
expect(variable.spec.query.datasource?.name).toBeUndefined();
|
expect(variable.spec.datasource?.uid).toBeUndefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('do not expose datasource name and id in datasource variable', async () => {
|
it('do not expose datasource name and id in datasource variable', async () => {
|
||||||
@@ -596,7 +597,7 @@ describe('dashboard exporter v2', () => {
|
|||||||
const { dashboard } = await setup();
|
const { dashboard } = await setup();
|
||||||
const annotationQuery = dashboard.annotations[0];
|
const annotationQuery = dashboard.annotations[0];
|
||||||
|
|
||||||
expect(annotationQuery.spec.query?.datasource?.name).toBeUndefined();
|
expect(annotationQuery.spec.datasource?.uid).toBeUndefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should remove library panels from layout', async () => {
|
it('should remove library panels from layout', async () => {
|
||||||
@@ -615,8 +616,11 @@ describe('dashboard exporter v2', () => {
|
|||||||
if (panel.kind !== 'Panel') {
|
if (panel.kind !== 'Panel') {
|
||||||
throw new Error('Panel should be a Panel');
|
throw new Error('Panel should be a Panel');
|
||||||
}
|
}
|
||||||
expect(panel.spec.data.spec.queries[0].spec.query.datasource?.name).toBe('${datasourceVar}');
|
|
||||||
expect(panel.spec.data.spec.queries[0].spec.query.group).toBe('prometheus');
|
expect(panel.spec.data.spec.queries[0].spec.datasource).toEqual({
|
||||||
|
type: 'prometheus',
|
||||||
|
uid: '${datasourceVar}',
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -344,8 +344,7 @@ export async function makeExportableV2(dashboard: DashboardV2Spec) {
|
|||||||
const removeDataSourceRefs = (
|
const removeDataSourceRefs = (
|
||||||
obj: AnnotationQueryKind['spec'] | QueryVariableKind['spec'] | PanelQueryKind['spec']
|
obj: AnnotationQueryKind['spec'] | QueryVariableKind['spec'] | PanelQueryKind['spec']
|
||||||
) => {
|
) => {
|
||||||
const datasourceUid = obj.query?.datasource?.name;
|
const datasourceUid = obj.datasource?.uid;
|
||||||
|
|
||||||
if (datasourceUid?.startsWith('${') && datasourceUid?.endsWith('}')) {
|
if (datasourceUid?.startsWith('${') && datasourceUid?.endsWith('}')) {
|
||||||
const varName = datasourceUid.slice(2, -1);
|
const varName = datasourceUid.slice(2, -1);
|
||||||
// if there's a match we don't want to remove the datasource ref
|
// if there's a match we don't want to remove the datasource ref
|
||||||
@@ -355,7 +354,7 @@ export async function makeExportableV2(dashboard: DashboardV2Spec) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
obj.query && (obj.query.datasource = undefined);
|
obj.datasource = undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
const processPanel = (panel: PanelKind) => {
|
const processPanel = (panel: PanelKind) => {
|
||||||
|
|||||||
+1
-1
@@ -15,7 +15,7 @@ const newShareButtonSelector = e2eSelectors.pages.Dashboard.DashNav.newShareButt
|
|||||||
export const ShareDashboardButton = ({ dashboard }: ToolbarActionProps) => {
|
export const ShareDashboardButton = ({ dashboard }: ToolbarActionProps) => {
|
||||||
const [_, buildUrl] = useAsyncFn(async () => {
|
const [_, buildUrl] = useAsyncFn(async () => {
|
||||||
DashboardInteractions.toolbarShareClick();
|
DashboardInteractions.toolbarShareClick();
|
||||||
return await buildShareUrl(dashboard);
|
await buildShareUrl(dashboard);
|
||||||
}, [dashboard]);
|
}, [dashboard]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
+8
-245
@@ -10,13 +10,10 @@ import { Dashboard, VariableModel } from '@grafana/schema';
|
|||||||
import {
|
import {
|
||||||
Spec as DashboardV2Spec,
|
Spec as DashboardV2Spec,
|
||||||
defaultSpec as defaultDashboardV2Spec,
|
defaultSpec as defaultDashboardV2Spec,
|
||||||
defaultDataQueryKind,
|
|
||||||
defaultPanelSpec,
|
defaultPanelSpec,
|
||||||
defaultTimeSettingsSpec,
|
defaultTimeSettingsSpec,
|
||||||
GridLayoutKind,
|
GridLayoutKind,
|
||||||
PanelKind,
|
|
||||||
PanelSpec,
|
PanelSpec,
|
||||||
QueryVariableKind,
|
|
||||||
} from '@grafana/schema/dist/esm/schema/dashboard/v2alpha1/types.spec.gen';
|
} from '@grafana/schema/dist/esm/schema/dashboard/v2alpha1/types.spec.gen';
|
||||||
import { DEFAULT_ANNOTATION_COLOR } from '@grafana/ui';
|
import { DEFAULT_ANNOTATION_COLOR } from '@grafana/ui';
|
||||||
import { AnnoKeyDashboardSnapshotOriginalUrl } from 'app/features/apiserver/types';
|
import { AnnoKeyDashboardSnapshotOriginalUrl } from 'app/features/apiserver/types';
|
||||||
@@ -50,13 +47,11 @@ jest.mock('@grafana/runtime', () => ({
|
|||||||
name: 'Grafana',
|
name: 'Grafana',
|
||||||
meta: { id: 'grafana' },
|
meta: { id: 'grafana' },
|
||||||
type: 'datasource',
|
type: 'datasource',
|
||||||
uid: 'grafana',
|
|
||||||
},
|
},
|
||||||
prometheus: {
|
prometheus: {
|
||||||
name: 'prometheus',
|
name: 'prometheus',
|
||||||
meta: { id: 'prometheus' },
|
meta: { id: 'prometheus' },
|
||||||
type: 'datasource',
|
type: 'datasource',
|
||||||
uid: 'prometheus-uid',
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -728,14 +723,9 @@ describe('DashboardSceneSerializer', () => {
|
|||||||
spec: {
|
spec: {
|
||||||
builtIn: true,
|
builtIn: true,
|
||||||
name: 'Annotations & Alerts',
|
name: 'Annotations & Alerts',
|
||||||
query: {
|
datasource: {
|
||||||
kind: 'DataQuery',
|
uid: '-- Grafana --',
|
||||||
version: defaultDataQueryKind().version,
|
type: 'grafana',
|
||||||
group: 'grafana',
|
|
||||||
datasource: {
|
|
||||||
name: '-- Grafana --',
|
|
||||||
},
|
|
||||||
spec: {},
|
|
||||||
},
|
},
|
||||||
enable: true,
|
enable: true,
|
||||||
hide: true,
|
hide: true,
|
||||||
@@ -894,226 +884,6 @@ describe('DashboardSceneSerializer', () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('data source references persistence', () => {
|
|
||||||
it('should not fill data source references for annotations when input did not contain it', () => {
|
|
||||||
const dashboard = setupV2({
|
|
||||||
annotations: [
|
|
||||||
{
|
|
||||||
kind: 'AnnotationQuery',
|
|
||||||
spec: {
|
|
||||||
builtIn: false,
|
|
||||||
enable: true,
|
|
||||||
hide: false,
|
|
||||||
iconColor: 'blue',
|
|
||||||
name: 'prom-annotations',
|
|
||||||
query: {
|
|
||||||
group: 'prometheus',
|
|
||||||
kind: 'DataQuery',
|
|
||||||
spec: {
|
|
||||||
refId: 'Anno',
|
|
||||||
},
|
|
||||||
version: 'v0',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
|
||||||
const saveAsModel = serializer.getSaveAsModel(dashboard, baseOptions);
|
|
||||||
// referencing index 1 as transformation adds built in annotation query
|
|
||||||
expect(saveAsModel.annotations[1].spec.query.datasource).toBeUndefined();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should fill data source references for annotations when input did contain it', () => {
|
|
||||||
const dashboard = setupV2({
|
|
||||||
annotations: [
|
|
||||||
{
|
|
||||||
kind: 'AnnotationQuery',
|
|
||||||
spec: {
|
|
||||||
builtIn: false,
|
|
||||||
enable: true,
|
|
||||||
hide: false,
|
|
||||||
iconColor: 'blue',
|
|
||||||
name: 'prom-annotations',
|
|
||||||
query: {
|
|
||||||
group: 'prometheus',
|
|
||||||
kind: 'DataQuery',
|
|
||||||
datasource: {
|
|
||||||
name: 'prometheus-uid',
|
|
||||||
},
|
|
||||||
spec: {
|
|
||||||
refId: 'Anno',
|
|
||||||
},
|
|
||||||
version: 'v0',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
|
||||||
const saveAsModel = serializer.getSaveAsModel(dashboard, baseOptions);
|
|
||||||
// referencing index 1 as transformation adds built in annotation query
|
|
||||||
expect(saveAsModel.annotations[1].spec.query.datasource).toEqual({
|
|
||||||
name: 'prometheus-uid',
|
|
||||||
});
|
|
||||||
});
|
|
||||||
it('should not fill data source references for panel queries when input did not contain it', () => {
|
|
||||||
const dashboard = setupV2({
|
|
||||||
elements: {
|
|
||||||
'panel-1': {
|
|
||||||
kind: 'Panel',
|
|
||||||
spec: {
|
|
||||||
...defaultPanelSpec(),
|
|
||||||
data: {
|
|
||||||
kind: 'QueryGroup',
|
|
||||||
spec: {
|
|
||||||
transformations: [],
|
|
||||||
queryOptions: {},
|
|
||||||
queries: [
|
|
||||||
{
|
|
||||||
kind: 'PanelQuery',
|
|
||||||
spec: {
|
|
||||||
refId: 'A',
|
|
||||||
hidden: false,
|
|
||||||
query: {
|
|
||||||
kind: 'DataQuery',
|
|
||||||
group: 'prometheus',
|
|
||||||
version: 'v0',
|
|
||||||
spec: {},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
const saveAsModel = serializer.getSaveAsModel(dashboard, baseOptions);
|
|
||||||
expect(
|
|
||||||
(saveAsModel.elements['panel-1'] as PanelKind).spec.data.spec.queries[0].spec.query.datasource
|
|
||||||
).toBeUndefined();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should fill data source references for panel queries when input did contain it', () => {
|
|
||||||
const dashboard = setupV2({
|
|
||||||
elements: {
|
|
||||||
'panel-1': {
|
|
||||||
kind: 'Panel',
|
|
||||||
spec: {
|
|
||||||
...defaultPanelSpec(),
|
|
||||||
data: {
|
|
||||||
kind: 'QueryGroup',
|
|
||||||
spec: {
|
|
||||||
transformations: [],
|
|
||||||
queryOptions: {},
|
|
||||||
queries: [
|
|
||||||
{
|
|
||||||
kind: 'PanelQuery',
|
|
||||||
spec: {
|
|
||||||
refId: 'A',
|
|
||||||
hidden: false,
|
|
||||||
query: {
|
|
||||||
kind: 'DataQuery',
|
|
||||||
group: 'prometheus',
|
|
||||||
version: 'v0',
|
|
||||||
datasource: {
|
|
||||||
name: 'prometheus-uid',
|
|
||||||
},
|
|
||||||
spec: {},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
const saveAsModel = serializer.getSaveAsModel(dashboard, baseOptions);
|
|
||||||
expect(
|
|
||||||
(saveAsModel.elements['panel-1'] as PanelKind).spec.data.spec.queries[0].spec.query.datasource
|
|
||||||
).toEqual({
|
|
||||||
name: 'prometheus-uid',
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should not fill data source references for query variables when input did contain it', () => {
|
|
||||||
const queryVariable: QueryVariableKind = {
|
|
||||||
kind: 'QueryVariable',
|
|
||||||
spec: {
|
|
||||||
name: 'app',
|
|
||||||
current: {
|
|
||||||
text: 'app1',
|
|
||||||
value: 'app1',
|
|
||||||
},
|
|
||||||
hide: 'dontHide',
|
|
||||||
includeAll: false,
|
|
||||||
label: 'Query Variable',
|
|
||||||
skipUrlSync: false,
|
|
||||||
regex: '',
|
|
||||||
definition: '',
|
|
||||||
options: [],
|
|
||||||
refresh: 'never',
|
|
||||||
sort: 'alphabeticalAsc',
|
|
||||||
multi: false,
|
|
||||||
allowCustomValue: true,
|
|
||||||
query: {
|
|
||||||
kind: 'DataQuery',
|
|
||||||
group: 'prometheus',
|
|
||||||
version: 'v0',
|
|
||||||
spec: {},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
const dashboard = setupV2({
|
|
||||||
variables: [queryVariable],
|
|
||||||
});
|
|
||||||
const saveAsModel = serializer.getSaveAsModel(dashboard, baseOptions);
|
|
||||||
expect((saveAsModel.variables[0] as QueryVariableKind).spec.query.datasource).toBeUndefined();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should fill data source references for query variables when input did contain it', () => {
|
|
||||||
const queryVariable: QueryVariableKind = {
|
|
||||||
kind: 'QueryVariable',
|
|
||||||
spec: {
|
|
||||||
name: 'app',
|
|
||||||
current: {
|
|
||||||
text: 'app1',
|
|
||||||
value: 'app1',
|
|
||||||
},
|
|
||||||
hide: 'dontHide',
|
|
||||||
includeAll: false,
|
|
||||||
label: 'Query Variable',
|
|
||||||
skipUrlSync: false,
|
|
||||||
regex: '',
|
|
||||||
definition: '',
|
|
||||||
options: [],
|
|
||||||
refresh: 'never',
|
|
||||||
sort: 'alphabeticalAsc',
|
|
||||||
multi: false,
|
|
||||||
allowCustomValue: true,
|
|
||||||
query: {
|
|
||||||
kind: 'DataQuery',
|
|
||||||
group: 'prometheus',
|
|
||||||
version: 'v0',
|
|
||||||
datasource: {
|
|
||||||
name: 'prometheus-uid',
|
|
||||||
},
|
|
||||||
spec: {},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
const dashboard = setupV2({
|
|
||||||
variables: [queryVariable],
|
|
||||||
});
|
|
||||||
const saveAsModel = serializer.getSaveAsModel(dashboard, baseOptions);
|
|
||||||
expect((saveAsModel.variables[0] as QueryVariableKind).spec.query.datasource).toEqual({
|
|
||||||
name: 'prometheus-uid',
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('panel mapping methods', () => {
|
describe('panel mapping methods', () => {
|
||||||
@@ -1244,7 +1014,7 @@ describe('DashboardSceneSerializer', () => {
|
|||||||
refId: 'A',
|
refId: 'A',
|
||||||
hidden: false,
|
hidden: false,
|
||||||
// No datasource defined
|
// No datasource defined
|
||||||
query: { kind: 'DataQuery', version: defaultDataQueryKind().version, group: 'sql', spec: {} },
|
query: { kind: 'sql', spec: {} },
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -1252,15 +1022,8 @@ describe('DashboardSceneSerializer', () => {
|
|||||||
spec: {
|
spec: {
|
||||||
refId: 'B',
|
refId: 'B',
|
||||||
hidden: false,
|
hidden: false,
|
||||||
query: {
|
datasource: { uid: 'datasource-1', type: 'prometheus' },
|
||||||
kind: 'DataQuery',
|
query: { kind: 'prometheus', spec: {} },
|
||||||
version: defaultDataQueryKind().version,
|
|
||||||
group: 'prometheus',
|
|
||||||
datasource: {
|
|
||||||
name: 'datasource-1',
|
|
||||||
},
|
|
||||||
spec: {},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@@ -1295,7 +1058,7 @@ describe('DashboardSceneSerializer', () => {
|
|||||||
refId: 'C',
|
refId: 'C',
|
||||||
hidden: false,
|
hidden: false,
|
||||||
// No datasource defined
|
// No datasource defined
|
||||||
query: { kind: 'DataQuery', version: defaultDataQueryKind().version, group: 'sql', spec: {} },
|
query: { kind: 'sql', spec: {} },
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@@ -1343,7 +1106,7 @@ describe('DashboardSceneSerializer', () => {
|
|||||||
kind: 'AnnotationQuery',
|
kind: 'AnnotationQuery',
|
||||||
spec: {
|
spec: {
|
||||||
name: 'Annotation 1',
|
name: 'Annotation 1',
|
||||||
query: { kind: 'DataQuery', version: defaultDataQueryKind().version, group: 'prometheus', spec: {} },
|
query: { kind: 'prometheus', spec: {} },
|
||||||
enable: true,
|
enable: true,
|
||||||
hide: false,
|
hide: false,
|
||||||
iconColor: 'red',
|
iconColor: 'red',
|
||||||
|
|||||||
@@ -288,7 +288,7 @@ export class V2DashboardSerializer
|
|||||||
const panelQueries = elementPanel.spec.data.spec.queries;
|
const panelQueries = elementPanel.spec.data.spec.queries;
|
||||||
|
|
||||||
for (const query of panelQueries) {
|
for (const query of panelQueries) {
|
||||||
if (!query.spec.query.datasource?.name) {
|
if (!query.spec.datasource) {
|
||||||
const elementId = this.getElementIdForPanel(elementPanel.spec.id);
|
const elementId = this.getElementIdForPanel(elementPanel.spec.id);
|
||||||
if (!this.defaultDsReferencesMap.panels.has(elementId)) {
|
if (!this.defaultDsReferencesMap.panels.has(elementId)) {
|
||||||
this.defaultDsReferencesMap.panels.set(elementId, new Set());
|
this.defaultDsReferencesMap.panels.set(elementId, new Set());
|
||||||
@@ -306,7 +306,7 @@ export class V2DashboardSerializer
|
|||||||
if (saveModel?.variables) {
|
if (saveModel?.variables) {
|
||||||
for (const variable of saveModel.variables) {
|
for (const variable of saveModel.variables) {
|
||||||
// for query variables that dont have a ds defined add them to the list
|
// for query variables that dont have a ds defined add them to the list
|
||||||
if (variable.kind === 'QueryVariable' && !variable.spec.query.datasource?.name) {
|
if (variable.kind === 'QueryVariable' && !variable.spec.datasource) {
|
||||||
this.defaultDsReferencesMap.variables.add(variable.spec.name);
|
this.defaultDsReferencesMap.variables.add(variable.spec.name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -315,7 +315,7 @@ export class V2DashboardSerializer
|
|||||||
// initialize annotations ds references map
|
// initialize annotations ds references map
|
||||||
if (saveModel?.annotations) {
|
if (saveModel?.annotations) {
|
||||||
for (const annotation of saveModel.annotations) {
|
for (const annotation of saveModel.annotations) {
|
||||||
if (!annotation.spec.query?.datasource?.name) {
|
if (!annotation.spec.datasource) {
|
||||||
this.defaultDsReferencesMap.annotations.add(annotation.spec.name);
|
this.defaultDsReferencesMap.annotations.add(annotation.spec.name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+24
-25
@@ -7,19 +7,28 @@ exports[`transformSceneToSaveModelSchemaV2 should transform scene to save model
|
|||||||
"kind": "AnnotationQuery",
|
"kind": "AnnotationQuery",
|
||||||
"spec": {
|
"spec": {
|
||||||
"builtIn": false,
|
"builtIn": false,
|
||||||
|
"datasource": {
|
||||||
|
"type": "grafana",
|
||||||
|
"uid": "-- Grafana --",
|
||||||
|
},
|
||||||
"enable": true,
|
"enable": true,
|
||||||
"hide": false,
|
"hide": false,
|
||||||
"iconColor": "red",
|
"iconColor": "red",
|
||||||
"name": "query1",
|
"name": "query1",
|
||||||
"query": {
|
},
|
||||||
"datasource": {
|
},
|
||||||
"name": "-- Grafana --",
|
{
|
||||||
},
|
"kind": "AnnotationQuery",
|
||||||
"group": "grafana",
|
"spec": {
|
||||||
"kind": "DataQuery",
|
"builtIn": false,
|
||||||
"spec": {},
|
"datasource": {
|
||||||
"version": "v0",
|
"type": "prometheus",
|
||||||
|
"uid": "abcdef",
|
||||||
},
|
},
|
||||||
|
"enable": true,
|
||||||
|
"hide": true,
|
||||||
|
"iconColor": "blue",
|
||||||
|
"name": "query2",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -28,17 +37,8 @@ exports[`transformSceneToSaveModelSchemaV2 should transform scene to save model
|
|||||||
"builtIn": false,
|
"builtIn": false,
|
||||||
"enable": true,
|
"enable": true,
|
||||||
"hide": true,
|
"hide": true,
|
||||||
"iconColor": "blue",
|
"iconColor": "green",
|
||||||
"name": "query2",
|
"name": "query3",
|
||||||
"query": {
|
|
||||||
"datasource": {
|
|
||||||
"name": "abcdef",
|
|
||||||
},
|
|
||||||
"group": "prometheus",
|
|
||||||
"kind": "DataQuery",
|
|
||||||
"spec": {},
|
|
||||||
"version": "v0",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@@ -152,6 +152,10 @@ exports[`transformSceneToSaveModelSchemaV2 should transform scene to save model
|
|||||||
"text": "text1",
|
"text": "text1",
|
||||||
"value": "value1",
|
"value": "value1",
|
||||||
},
|
},
|
||||||
|
"datasource": {
|
||||||
|
"type": "prometheus",
|
||||||
|
"uid": "datasource1",
|
||||||
|
},
|
||||||
"definition": "definition1",
|
"definition": "definition1",
|
||||||
"description": "A query variable",
|
"description": "A query variable",
|
||||||
"hide": "hideLabel",
|
"hide": "hideLabel",
|
||||||
@@ -161,16 +165,11 @@ exports[`transformSceneToSaveModelSchemaV2 should transform scene to save model
|
|||||||
"name": "queryVar",
|
"name": "queryVar",
|
||||||
"options": [],
|
"options": [],
|
||||||
"query": {
|
"query": {
|
||||||
"datasource": {
|
"kind": "prometheus",
|
||||||
"name": "datasource1",
|
|
||||||
},
|
|
||||||
"group": "prometheus",
|
|
||||||
"kind": "DataQuery",
|
|
||||||
"spec": {
|
"spec": {
|
||||||
"expr": "label_values(node_boot_time_seconds)",
|
"expr": "label_values(node_boot_time_seconds)",
|
||||||
"refId": "A",
|
"refId": "A",
|
||||||
},
|
},
|
||||||
"version": "v0",
|
|
||||||
},
|
},
|
||||||
"refresh": "onDashboardLoad",
|
"refresh": "onDashboardLoad",
|
||||||
"regex": "regex1",
|
"regex": "regex1",
|
||||||
|
|||||||
@@ -1,226 +0,0 @@
|
|||||||
import { AnnotationQuery } from '@grafana/data';
|
|
||||||
import { AnnotationQueryKind } from '@grafana/schema/dist/esm/schema/dashboard/v2alpha1/types.spec.gen';
|
|
||||||
|
|
||||||
import { transformV1ToV2AnnotationQuery, transformV2ToV1AnnotationQuery } from './annotations';
|
|
||||||
|
|
||||||
describe('V1<->V2 annotation convertions', () => {
|
|
||||||
test('given grafana-built in annotations', () => {
|
|
||||||
// test case
|
|
||||||
const annotationDefinition: AnnotationQuery = {
|
|
||||||
builtIn: 1,
|
|
||||||
datasource: {
|
|
||||||
type: 'grafana',
|
|
||||||
uid: 'grafana',
|
|
||||||
},
|
|
||||||
enable: true,
|
|
||||||
hide: false,
|
|
||||||
iconColor: 'yellow',
|
|
||||||
name: 'Annotations \u0026 Alerts',
|
|
||||||
target: {
|
|
||||||
// @ts-expect-error
|
|
||||||
limit: 100,
|
|
||||||
matchAny: false,
|
|
||||||
tags: [],
|
|
||||||
type: 'dashboard',
|
|
||||||
},
|
|
||||||
type: 'dashboard',
|
|
||||||
};
|
|
||||||
|
|
||||||
const expectedV2: AnnotationQueryKind = {
|
|
||||||
kind: 'AnnotationQuery',
|
|
||||||
spec: {
|
|
||||||
builtIn: true,
|
|
||||||
enable: true,
|
|
||||||
hide: false,
|
|
||||||
iconColor: 'yellow',
|
|
||||||
name: 'Annotations \u0026 Alerts',
|
|
||||||
query: {
|
|
||||||
kind: 'DataQuery',
|
|
||||||
group: 'grafana',
|
|
||||||
version: 'v0',
|
|
||||||
datasource: {
|
|
||||||
name: 'grafana',
|
|
||||||
},
|
|
||||||
spec: {
|
|
||||||
limit: 100,
|
|
||||||
matchAny: false,
|
|
||||||
tags: [],
|
|
||||||
type: 'dashboard',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const resultV2: AnnotationQueryKind = transformV1ToV2AnnotationQuery(annotationDefinition, 'grafana', 'grafana');
|
|
||||||
|
|
||||||
expect(resultV2).toEqual(expectedV2);
|
|
||||||
|
|
||||||
const resultV1: AnnotationQuery = transformV2ToV1AnnotationQuery(expectedV2);
|
|
||||||
expect(resultV1).toEqual(annotationDefinition);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('given annotations with datasource', () => {
|
|
||||||
const annotationDefinition = {
|
|
||||||
datasource: {
|
|
||||||
type: 'grafana-testdata-datasource',
|
|
||||||
uid: 'uid',
|
|
||||||
},
|
|
||||||
enable: true,
|
|
||||||
hide: false,
|
|
||||||
iconColor: 'blue',
|
|
||||||
name: 'testdata-annos',
|
|
||||||
target: {
|
|
||||||
lines: 10,
|
|
||||||
refId: 'Anno',
|
|
||||||
scenarioId: 'annotations',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const expectedV2: AnnotationQueryKind = {
|
|
||||||
kind: 'AnnotationQuery',
|
|
||||||
spec: {
|
|
||||||
enable: true,
|
|
||||||
hide: false,
|
|
||||||
iconColor: 'blue',
|
|
||||||
name: 'testdata-annos',
|
|
||||||
builtIn: false,
|
|
||||||
query: {
|
|
||||||
kind: 'DataQuery',
|
|
||||||
group: 'grafana-testdata-datasource',
|
|
||||||
version: 'v0',
|
|
||||||
datasource: {
|
|
||||||
name: 'uid',
|
|
||||||
},
|
|
||||||
spec: {
|
|
||||||
lines: 10,
|
|
||||||
refId: 'Anno',
|
|
||||||
scenarioId: 'annotations',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const resultV2: AnnotationQueryKind = transformV1ToV2AnnotationQuery(
|
|
||||||
annotationDefinition,
|
|
||||||
'grafana-testdata-datasource',
|
|
||||||
'uid'
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(resultV2).toEqual(expectedV2);
|
|
||||||
|
|
||||||
const resultV1: AnnotationQuery = transformV2ToV1AnnotationQuery(expectedV2);
|
|
||||||
expect(resultV1).toEqual(annotationDefinition);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('given annotations with target', () => {
|
|
||||||
const annotationDefinition = {
|
|
||||||
datasource: {
|
|
||||||
type: 'prometheus',
|
|
||||||
uid: 'uid',
|
|
||||||
},
|
|
||||||
enable: true,
|
|
||||||
hide: false,
|
|
||||||
iconColor: 'yellow',
|
|
||||||
name: 'prom-annos',
|
|
||||||
target: {
|
|
||||||
expr: '{action="add_client"}',
|
|
||||||
interval: '',
|
|
||||||
lines: 10,
|
|
||||||
refId: 'Anno',
|
|
||||||
scenarioId: 'annotations',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const expectedV2: AnnotationQueryKind = {
|
|
||||||
kind: 'AnnotationQuery',
|
|
||||||
spec: {
|
|
||||||
enable: true,
|
|
||||||
hide: false,
|
|
||||||
iconColor: 'yellow',
|
|
||||||
name: 'prom-annos',
|
|
||||||
builtIn: false,
|
|
||||||
query: {
|
|
||||||
kind: 'DataQuery',
|
|
||||||
group: 'prometheus',
|
|
||||||
version: 'v0',
|
|
||||||
datasource: {
|
|
||||||
name: 'uid',
|
|
||||||
},
|
|
||||||
spec: {
|
|
||||||
expr: '{action="add_client"}',
|
|
||||||
interval: '',
|
|
||||||
lines: 10,
|
|
||||||
refId: 'Anno',
|
|
||||||
scenarioId: 'annotations',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const resultV2: AnnotationQueryKind = transformV1ToV2AnnotationQuery(annotationDefinition, 'prometheus', 'uid');
|
|
||||||
expect(resultV2).toEqual(expectedV2);
|
|
||||||
|
|
||||||
const resultV1: AnnotationQuery = transformV2ToV1AnnotationQuery(expectedV2);
|
|
||||||
expect(resultV1).toEqual(annotationDefinition);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('given annotations with non-schematised options / legacyOptions', () => {
|
|
||||||
const annotationDefinition = {
|
|
||||||
datasource: {
|
|
||||||
type: 'elasticsearch',
|
|
||||||
uid: 'uid',
|
|
||||||
},
|
|
||||||
enable: true,
|
|
||||||
hide: false,
|
|
||||||
iconColor: 'red',
|
|
||||||
name: 'elastic - annos',
|
|
||||||
tagsField: 'asd',
|
|
||||||
target: {
|
|
||||||
lines: 10,
|
|
||||||
query: 'test query',
|
|
||||||
refId: 'Anno',
|
|
||||||
scenarioId: 'annotations',
|
|
||||||
},
|
|
||||||
textField: 'asd',
|
|
||||||
timeEndField: 'asdas',
|
|
||||||
timeField: 'asd',
|
|
||||||
};
|
|
||||||
|
|
||||||
const expectedV2: AnnotationQueryKind = {
|
|
||||||
kind: 'AnnotationQuery',
|
|
||||||
spec: {
|
|
||||||
enable: true,
|
|
||||||
hide: false,
|
|
||||||
iconColor: 'red',
|
|
||||||
name: 'elastic - annos',
|
|
||||||
builtIn: false,
|
|
||||||
query: {
|
|
||||||
kind: 'DataQuery',
|
|
||||||
group: 'elasticsearch',
|
|
||||||
version: 'v0',
|
|
||||||
datasource: {
|
|
||||||
name: 'uid',
|
|
||||||
},
|
|
||||||
spec: {
|
|
||||||
lines: 10,
|
|
||||||
query: 'test query',
|
|
||||||
refId: 'Anno',
|
|
||||||
scenarioId: 'annotations',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
legacyOptions: {
|
|
||||||
tagsField: 'asd',
|
|
||||||
textField: 'asd',
|
|
||||||
timeEndField: 'asdas',
|
|
||||||
timeField: 'asd',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const resultV2: AnnotationQueryKind = transformV1ToV2AnnotationQuery(annotationDefinition, 'elasticsearch', 'uid');
|
|
||||||
expect(resultV2).toEqual(expectedV2);
|
|
||||||
|
|
||||||
const resultV1: AnnotationQuery = transformV2ToV1AnnotationQuery(expectedV2);
|
|
||||||
expect(resultV1).toEqual(annotationDefinition);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,118 +0,0 @@
|
|||||||
import { AnnotationQuery } from '@grafana/data';
|
|
||||||
import {
|
|
||||||
AnnotationQueryKind,
|
|
||||||
defaultDataQueryKind,
|
|
||||||
} from '@grafana/schema/dist/esm/schema/dashboard/v2alpha1/types.spec.gen';
|
|
||||||
|
|
||||||
import { getRuntimePanelDataSource } from './layoutSerializers/utils';
|
|
||||||
|
|
||||||
export function transformV1ToV2AnnotationQuery(
|
|
||||||
annotation: AnnotationQuery,
|
|
||||||
|
|
||||||
dsType: string,
|
|
||||||
dsUID?: string,
|
|
||||||
// Overrides are used to provide properties based on scene's annotations data layer object state
|
|
||||||
override?: Partial<AnnotationQuery>
|
|
||||||
): AnnotationQueryKind {
|
|
||||||
const group = annotation.builtIn ? 'grafana' : dsType;
|
|
||||||
|
|
||||||
const {
|
|
||||||
// known properties documented in v1 schema
|
|
||||||
enable,
|
|
||||||
hide,
|
|
||||||
iconColor,
|
|
||||||
name,
|
|
||||||
builtIn,
|
|
||||||
filter,
|
|
||||||
mappings,
|
|
||||||
datasource,
|
|
||||||
target,
|
|
||||||
snapshotData,
|
|
||||||
type,
|
|
||||||
|
|
||||||
// unknown properties that are still available for configuration through API
|
|
||||||
...legacyOptions
|
|
||||||
} = annotation;
|
|
||||||
|
|
||||||
const result: AnnotationQueryKind = {
|
|
||||||
kind: 'AnnotationQuery',
|
|
||||||
spec: {
|
|
||||||
builtIn: Boolean(annotation.builtIn),
|
|
||||||
name: annotation.name,
|
|
||||||
enable: Boolean(override?.enable) || Boolean(annotation.enable),
|
|
||||||
hide: Boolean(override?.hide) || Boolean(annotation.hide),
|
|
||||||
iconColor: annotation.iconColor,
|
|
||||||
|
|
||||||
query: {
|
|
||||||
kind: 'DataQuery',
|
|
||||||
version: defaultDataQueryKind().version,
|
|
||||||
group, // Annotation layer has a datasource type provided in runtime.
|
|
||||||
spec: target || {},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
if (dsUID) {
|
|
||||||
result.spec.query.datasource = {
|
|
||||||
name: dsUID,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// if legacy options is not an empty object, add it to the result
|
|
||||||
if (Object.keys(legacyOptions).length > 0) {
|
|
||||||
result.spec.legacyOptions = legacyOptions;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (annotation.filter?.ids?.length) {
|
|
||||||
result.spec.filter = annotation.filter;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: add mappings
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function transformV2ToV1AnnotationQuery(annotation: AnnotationQueryKind): AnnotationQuery {
|
|
||||||
let { query: dataQuery, ...annotationQuery } = annotation.spec;
|
|
||||||
|
|
||||||
// Mapping from AnnotationQueryKind to AnnotationQuery used by scenes.
|
|
||||||
let annoQuerySpec: AnnotationQuery = {
|
|
||||||
enable: annotation.spec.enable,
|
|
||||||
hide: annotation.spec.hide,
|
|
||||||
iconColor: annotation.spec.iconColor,
|
|
||||||
name: annotation.spec.name,
|
|
||||||
// TOOO: mappings
|
|
||||||
};
|
|
||||||
|
|
||||||
if (Object.keys(dataQuery.spec).length > 0) {
|
|
||||||
// @ts-expect-error DataQueryKind spec should be typed as DataQuery interface
|
|
||||||
annoQuerySpec.target = {
|
|
||||||
...dataQuery?.spec,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (annotation.spec.builtIn) {
|
|
||||||
annoQuerySpec.type = 'dashboard';
|
|
||||||
annoQuerySpec.builtIn = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (annotation.spec.filter) {
|
|
||||||
annoQuerySpec.filter = annotation.spec.filter;
|
|
||||||
}
|
|
||||||
|
|
||||||
// some annotations will contain in the legacyOptions properties that need to be
|
|
||||||
// added to the root level AnnotationQuery
|
|
||||||
if (annotationQuery.legacyOptions) {
|
|
||||||
annoQuerySpec = {
|
|
||||||
...annoQuerySpec,
|
|
||||||
...annotationQuery.legacyOptions,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// get data source from annotation query
|
|
||||||
const datasource = getRuntimePanelDataSource(dataQuery);
|
|
||||||
|
|
||||||
annoQuerySpec.datasource = datasource;
|
|
||||||
|
|
||||||
return annoQuerySpec;
|
|
||||||
}
|
|
||||||
@@ -1,7 +1,4 @@
|
|||||||
import {
|
import { PanelQueryKind } from '@grafana/schema/dist/esm/schema/dashboard/v2alpha1/types.spec.gen';
|
||||||
defaultDataQueryKind,
|
|
||||||
PanelQueryKind,
|
|
||||||
} from '@grafana/schema/dist/esm/schema/dashboard/v2alpha1/types.spec.gen';
|
|
||||||
|
|
||||||
import { getRuntimePanelDataSource } from './utils';
|
import { getRuntimePanelDataSource } from './utils';
|
||||||
|
|
||||||
@@ -32,12 +29,6 @@ jest.mock('@grafana/runtime', () => ({
|
|||||||
meta: { id: 'loki' },
|
meta: { id: 'loki' },
|
||||||
type: 'datasource',
|
type: 'datasource',
|
||||||
},
|
},
|
||||||
'-- Grafana --': {
|
|
||||||
uid: 'grafana',
|
|
||||||
name: 'Grafana',
|
|
||||||
meta: { id: 'grafana' },
|
|
||||||
type: 'datasource',
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -51,23 +42,22 @@ describe('getRuntimePanelDataSource', () => {
|
|||||||
spec: {
|
spec: {
|
||||||
refId: 'A',
|
refId: 'A',
|
||||||
hidden: false,
|
hidden: false,
|
||||||
|
datasource: {
|
||||||
|
uid: 'test-ds-uid',
|
||||||
|
type: 'test-ds-type',
|
||||||
|
},
|
||||||
query: {
|
query: {
|
||||||
kind: 'DataQuery',
|
kind: 'prometheus',
|
||||||
version: defaultDataQueryKind().version,
|
|
||||||
group: 'prometheus',
|
|
||||||
datasource: {
|
|
||||||
name: 'prometheus-uid',
|
|
||||||
},
|
|
||||||
spec: {},
|
spec: {},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const result = getRuntimePanelDataSource(query.spec.query);
|
const result = getRuntimePanelDataSource(query);
|
||||||
|
|
||||||
expect(result).toEqual({
|
expect(result).toEqual({
|
||||||
uid: 'prometheus-uid',
|
uid: 'test-ds-uid',
|
||||||
type: 'prometheus',
|
type: 'test-ds-type',
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -77,16 +67,15 @@ describe('getRuntimePanelDataSource', () => {
|
|||||||
spec: {
|
spec: {
|
||||||
refId: 'A',
|
refId: 'A',
|
||||||
hidden: false,
|
hidden: false,
|
||||||
|
datasource: undefined,
|
||||||
query: {
|
query: {
|
||||||
kind: 'DataQuery',
|
kind: 'prometheus',
|
||||||
version: defaultDataQueryKind().version,
|
|
||||||
group: 'prometheus',
|
|
||||||
spec: {},
|
spec: {},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const result = getRuntimePanelDataSource(query.spec.query);
|
const result = getRuntimePanelDataSource(query);
|
||||||
|
|
||||||
expect(result).toEqual({
|
expect(result).toEqual({
|
||||||
uid: 'default-prometheus-uid',
|
uid: 'default-prometheus-uid',
|
||||||
@@ -100,16 +89,15 @@ describe('getRuntimePanelDataSource', () => {
|
|||||||
spec: {
|
spec: {
|
||||||
refId: 'A',
|
refId: 'A',
|
||||||
hidden: false,
|
hidden: false,
|
||||||
|
datasource: undefined,
|
||||||
query: {
|
query: {
|
||||||
kind: 'DataQuery',
|
kind: 'loki',
|
||||||
version: defaultDataQueryKind().version,
|
|
||||||
group: 'loki',
|
|
||||||
spec: {},
|
spec: {},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const result = getRuntimePanelDataSource(query.spec.query);
|
const result = getRuntimePanelDataSource(query);
|
||||||
|
|
||||||
expect(result).toEqual({
|
expect(result).toEqual({
|
||||||
uid: 'loki-uid',
|
uid: 'loki-uid',
|
||||||
@@ -124,16 +112,15 @@ describe('getRuntimePanelDataSource', () => {
|
|||||||
spec: {
|
spec: {
|
||||||
refId: 'A',
|
refId: 'A',
|
||||||
hidden: false,
|
hidden: false,
|
||||||
|
datasource: undefined,
|
||||||
query: {
|
query: {
|
||||||
kind: 'DataQuery',
|
kind: 'unknown-type',
|
||||||
version: defaultDataQueryKind().version,
|
|
||||||
group: 'unknown-type',
|
|
||||||
spec: {},
|
spec: {},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const result = getRuntimePanelDataSource(query.spec.query);
|
const result = getRuntimePanelDataSource(query);
|
||||||
|
|
||||||
expect(result).toEqual({
|
expect(result).toEqual({
|
||||||
uid: 'default-prometheus-uid',
|
uid: 'default-prometheus-uid',
|
||||||
@@ -151,19 +138,18 @@ describe('getRuntimePanelDataSource', () => {
|
|||||||
spec: {
|
spec: {
|
||||||
refId: 'A',
|
refId: 'A',
|
||||||
hidden: false,
|
hidden: false,
|
||||||
|
datasource: {
|
||||||
|
uid: '',
|
||||||
|
type: 'test-ds-type',
|
||||||
|
},
|
||||||
query: {
|
query: {
|
||||||
kind: 'DataQuery',
|
kind: 'prometheus',
|
||||||
version: defaultDataQueryKind().version,
|
|
||||||
group: 'prometheus',
|
|
||||||
datasource: {
|
|
||||||
name: '',
|
|
||||||
},
|
|
||||||
spec: {},
|
spec: {},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const result = getRuntimePanelDataSource(query.spec.query);
|
const result = getRuntimePanelDataSource(query);
|
||||||
|
|
||||||
expect(result).toEqual({
|
expect(result).toEqual({
|
||||||
uid: 'default-prometheus-uid',
|
uid: 'default-prometheus-uid',
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ import {
|
|||||||
PanelQueryKind,
|
PanelQueryKind,
|
||||||
QueryVariableKind,
|
QueryVariableKind,
|
||||||
TabsLayoutTabKind,
|
TabsLayoutTabKind,
|
||||||
DataQueryKind,
|
|
||||||
} from '@grafana/schema/dist/esm/schema/dashboard/v2alpha1/types.spec.gen';
|
} from '@grafana/schema/dist/esm/schema/dashboard/v2alpha1/types.spec.gen';
|
||||||
import { MIXED_DATASOURCE_NAME } from 'app/plugins/datasource/mixed/MixedDataSource';
|
import { MIXED_DATASOURCE_NAME } from 'app/plugins/datasource/mixed/MixedDataSource';
|
||||||
|
|
||||||
@@ -186,15 +185,12 @@ function getPanelDataSource(panel: PanelKind): DataSourceRef | undefined {
|
|||||||
|
|
||||||
panel.spec.data.spec.queries.forEach((query) => {
|
panel.spec.data.spec.queries.forEach((query) => {
|
||||||
if (!datasource) {
|
if (!datasource) {
|
||||||
if (!query.spec.query.datasource?.name) {
|
if (!query.spec.datasource?.uid) {
|
||||||
datasource = getRuntimePanelDataSource(query.spec.query);
|
datasource = getRuntimePanelDataSource(query);
|
||||||
} else {
|
} else {
|
||||||
datasource = {
|
datasource = query.spec.datasource;
|
||||||
uid: query.spec.query.datasource?.name,
|
|
||||||
type: query.spec.query.group,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
} else if (datasource.uid !== query.spec.query.datasource?.name || datasource.type !== query.spec.query.group) {
|
} else if (datasource.uid !== query.spec.datasource?.uid || datasource.type !== query.spec.datasource?.type) {
|
||||||
isMixedDatasource = true;
|
isMixedDatasource = true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -203,19 +199,11 @@ function getPanelDataSource(panel: PanelKind): DataSourceRef | undefined {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function getRuntimeVariableDataSource(variable: QueryVariableKind): DataSourceRef | undefined {
|
export function getRuntimeVariableDataSource(variable: QueryVariableKind): DataSourceRef | undefined {
|
||||||
const ds: DataSourceRef = {
|
return getDataSourceForQuery(variable.spec.datasource, variable.spec.query.kind);
|
||||||
uid: variable.spec.query.datasource?.name,
|
|
||||||
type: variable.spec.query.group,
|
|
||||||
};
|
|
||||||
return getDataSourceForQuery(ds, variable.spec.query.group);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getRuntimePanelDataSource(query: DataQueryKind): DataSourceRef {
|
export function getRuntimePanelDataSource(query: PanelQueryKind): DataSourceRef | undefined {
|
||||||
const ds: DataSourceRef = {
|
return getDataSourceForQuery(query.spec.datasource, query.spec.query.kind);
|
||||||
uid: query.datasource?.name,
|
|
||||||
type: query.group,
|
|
||||||
};
|
|
||||||
return getDataSourceForQuery(ds, query.group);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -223,7 +211,10 @@ export function getRuntimePanelDataSource(query: DataQueryKind): DataSourceRef {
|
|||||||
* @param queryKind - The kind of query being performed
|
* @param queryKind - The kind of query being performed
|
||||||
* @returns The resolved DataSourceRef
|
* @returns The resolved DataSourceRef
|
||||||
*/
|
*/
|
||||||
function getDataSourceForQuery(querySpecDS: DataSourceRef | undefined | null, queryKind: string): DataSourceRef {
|
function getDataSourceForQuery(
|
||||||
|
querySpecDS: DataSourceRef | undefined | null,
|
||||||
|
queryKind: string
|
||||||
|
): DataSourceRef | undefined {
|
||||||
// If datasource is specified and has a uid, use it
|
// If datasource is specified and has a uid, use it
|
||||||
if (querySpecDS?.uid) {
|
if (querySpecDS?.uid) {
|
||||||
return querySpecDS;
|
return querySpecDS;
|
||||||
@@ -262,22 +253,14 @@ function getDataSourceForQuery(querySpecDS: DataSourceRef | undefined | null, qu
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dsList && !dsList[defaultDatasource]) {
|
// If we don't find a default datasource, return undefined
|
||||||
throw new Error(`Default datasource ${defaultDatasource} not found in datasource list`);
|
return undefined;
|
||||||
}
|
|
||||||
|
|
||||||
// In the datasource list from bootData "id" is the type and the uid could be uid or the name
|
|
||||||
// in cases like grafana, dashboard or mixed datasource
|
|
||||||
return {
|
|
||||||
uid: dsList[defaultDatasource].uid || dsList[defaultDatasource].name,
|
|
||||||
type: dsList[defaultDatasource].meta.id,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function panelQueryKindToSceneQuery(query: PanelQueryKind): SceneDataQuery {
|
function panelQueryKindToSceneQuery(query: PanelQueryKind): SceneDataQuery {
|
||||||
return {
|
return {
|
||||||
refId: query.spec.refId,
|
refId: query.spec.refId,
|
||||||
datasource: getRuntimePanelDataSource(query.spec.query),
|
datasource: getRuntimePanelDataSource(query),
|
||||||
hide: query.spec.hidden,
|
hide: query.spec.hidden,
|
||||||
...query.spec.query.spec,
|
...query.spec.query.spec,
|
||||||
};
|
};
|
||||||
|
|||||||
+68
-69
@@ -45,8 +45,8 @@ const getDataSourceMock = jest.fn();
|
|||||||
|
|
||||||
const fakeDsMock: DataSourceApi = {
|
const fakeDsMock: DataSourceApi = {
|
||||||
name: 'fake-std',
|
name: 'fake-std',
|
||||||
type: 'fake-type',
|
type: 'fake-std',
|
||||||
getRef: () => ({ type: 'fake-type', uid: 'fake-uid' }),
|
getRef: () => ({ type: 'fake-std', uid: 'fake-std' }),
|
||||||
query: () =>
|
query: () =>
|
||||||
Promise.resolve({
|
Promise.resolve({
|
||||||
data: [],
|
data: [],
|
||||||
@@ -74,7 +74,7 @@ const fakeDsMock: DataSourceApi = {
|
|||||||
toDataQuery: (q) => ({ ...q, refId: 'FakeDataSource-refId' }),
|
toDataQuery: (q) => ({ ...q, refId: 'FakeDataSource-refId' }),
|
||||||
},
|
},
|
||||||
id: 1,
|
id: 1,
|
||||||
uid: 'fake-uid',
|
uid: 'fake-std',
|
||||||
};
|
};
|
||||||
|
|
||||||
jest.mock('@grafana/runtime', () => ({
|
jest.mock('@grafana/runtime', () => ({
|
||||||
@@ -95,7 +95,7 @@ describe('sceneVariablesSetToVariables', () => {
|
|||||||
description: 'test-desc',
|
description: 'test-desc',
|
||||||
value: ['selected-value'],
|
value: ['selected-value'],
|
||||||
text: ['selected-value-text'],
|
text: ['selected-value-text'],
|
||||||
datasource: { uid: 'fake-uid', type: 'fake-type' },
|
datasource: { uid: 'fake-std', type: 'fake-std' },
|
||||||
query: 'query',
|
query: 'query',
|
||||||
includeAll: true,
|
includeAll: true,
|
||||||
allowCustomValue: true,
|
allowCustomValue: true,
|
||||||
@@ -123,8 +123,8 @@ describe('sceneVariablesSetToVariables', () => {
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
"datasource": {
|
"datasource": {
|
||||||
"type": "fake-type",
|
"type": "fake-std",
|
||||||
"uid": "fake-uid",
|
"uid": "fake-std",
|
||||||
},
|
},
|
||||||
"definition": undefined,
|
"definition": undefined,
|
||||||
"description": "test-desc",
|
"description": "test-desc",
|
||||||
@@ -148,7 +148,7 @@ describe('sceneVariablesSetToVariables', () => {
|
|||||||
description: 'test-desc',
|
description: 'test-desc',
|
||||||
value: ['selected-value'],
|
value: ['selected-value'],
|
||||||
text: ['selected-value-text'],
|
text: ['selected-value-text'],
|
||||||
datasource: { uid: 'fake-uid', type: 'fake-type' },
|
datasource: { uid: 'fake-std', type: 'fake-std' },
|
||||||
query: 'query',
|
query: 'query',
|
||||||
definition: 'query',
|
definition: 'query',
|
||||||
includeAll: true,
|
includeAll: true,
|
||||||
@@ -176,8 +176,8 @@ describe('sceneVariablesSetToVariables', () => {
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
"datasource": {
|
"datasource": {
|
||||||
"type": "fake-type",
|
"type": "fake-std",
|
||||||
"uid": "fake-uid",
|
"uid": "fake-std",
|
||||||
},
|
},
|
||||||
"definition": "query",
|
"definition": "query",
|
||||||
"description": "test-desc",
|
"description": "test-desc",
|
||||||
@@ -201,7 +201,7 @@ describe('sceneVariablesSetToVariables', () => {
|
|||||||
description: 'test-desc',
|
description: 'test-desc',
|
||||||
value: ['selected-value'],
|
value: ['selected-value'],
|
||||||
text: ['selected-value-text'],
|
text: ['selected-value-text'],
|
||||||
datasource: { uid: 'fake-uid', type: 'fake-type' },
|
datasource: { uid: 'fake-std', type: 'fake-std' },
|
||||||
query: 'query',
|
query: 'query',
|
||||||
options: [
|
options: [
|
||||||
{ label: 'test', value: 'test' },
|
{ label: 'test', value: 'test' },
|
||||||
@@ -228,7 +228,7 @@ describe('sceneVariablesSetToVariables', () => {
|
|||||||
description: 'test-desc',
|
description: 'test-desc',
|
||||||
value: ['test'],
|
value: ['test'],
|
||||||
text: ['test'],
|
text: ['test'],
|
||||||
datasource: { uid: 'fake-uid', type: 'fake-type' },
|
datasource: { uid: 'fake-std', type: 'fake-std' },
|
||||||
query: 'query',
|
query: 'query',
|
||||||
options: [
|
options: [
|
||||||
{ label: 'test', value: 'test' },
|
{ label: 'test', value: 'test' },
|
||||||
@@ -499,7 +499,7 @@ describe('sceneVariablesSetToVariables', () => {
|
|||||||
allowCustomValue: true,
|
allowCustomValue: true,
|
||||||
label: 'test-label',
|
label: 'test-label',
|
||||||
description: 'test-desc',
|
description: 'test-desc',
|
||||||
datasource: { uid: 'fake-uid', type: 'fake-type' },
|
datasource: { uid: 'fake-std', type: 'fake-std' },
|
||||||
filters: [
|
filters: [
|
||||||
{
|
{
|
||||||
key: 'filterTest',
|
key: 'filterTest',
|
||||||
@@ -533,8 +533,8 @@ describe('sceneVariablesSetToVariables', () => {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
"datasource": {
|
"datasource": {
|
||||||
"type": "fake-type",
|
"type": "fake-std",
|
||||||
"uid": "fake-uid",
|
"uid": "fake-std",
|
||||||
},
|
},
|
||||||
"defaultKeys": undefined,
|
"defaultKeys": undefined,
|
||||||
"description": "test-desc",
|
"description": "test-desc",
|
||||||
@@ -662,7 +662,7 @@ describe('sceneVariablesSetToVariables', () => {
|
|||||||
allowCustomValue: true,
|
allowCustomValue: true,
|
||||||
label: 'test-label',
|
label: 'test-label',
|
||||||
description: 'test-desc',
|
description: 'test-desc',
|
||||||
datasource: { uid: 'fake-uid', type: 'fake-type' },
|
datasource: { uid: 'fake-std', type: 'fake-std' },
|
||||||
defaultKeys: [
|
defaultKeys: [
|
||||||
{
|
{
|
||||||
text: 'some',
|
text: 'some',
|
||||||
@@ -710,8 +710,8 @@ describe('sceneVariablesSetToVariables', () => {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
"datasource": {
|
"datasource": {
|
||||||
"type": "fake-type",
|
"type": "fake-std",
|
||||||
"uid": "fake-uid",
|
"uid": "fake-std",
|
||||||
},
|
},
|
||||||
"defaultKeys": [
|
"defaultKeys": [
|
||||||
{
|
{
|
||||||
@@ -757,7 +757,7 @@ describe('sceneVariablesSetToVariables', () => {
|
|||||||
label: 'test-label',
|
label: 'test-label',
|
||||||
description: 'test-desc',
|
description: 'test-desc',
|
||||||
allowCustomValue: true,
|
allowCustomValue: true,
|
||||||
datasource: { uid: 'fake-uid', type: 'fake-type' },
|
datasource: { uid: 'fake-std', type: 'fake-std' },
|
||||||
defaultOptions: [
|
defaultOptions: [
|
||||||
{
|
{
|
||||||
text: 'Foo',
|
text: 'Foo',
|
||||||
@@ -784,8 +784,8 @@ describe('sceneVariablesSetToVariables', () => {
|
|||||||
"value": [],
|
"value": [],
|
||||||
},
|
},
|
||||||
"datasource": {
|
"datasource": {
|
||||||
"type": "fake-type",
|
"type": "fake-std",
|
||||||
"uid": "fake-uid",
|
"uid": "fake-std",
|
||||||
},
|
},
|
||||||
"defaultValue": undefined,
|
"defaultValue": undefined,
|
||||||
"description": "test-desc",
|
"description": "test-desc",
|
||||||
@@ -813,7 +813,7 @@ describe('sceneVariablesSetToVariables', () => {
|
|||||||
name: 'test',
|
name: 'test',
|
||||||
label: 'test-label',
|
label: 'test-label',
|
||||||
description: 'test-desc',
|
description: 'test-desc',
|
||||||
datasource: { uid: 'fake-uid', type: 'fake-type' },
|
datasource: { uid: 'fake-std', type: 'fake-std' },
|
||||||
defaultOptions: [
|
defaultOptions: [
|
||||||
{
|
{
|
||||||
text: 'Foo',
|
text: 'Foo',
|
||||||
@@ -841,7 +841,7 @@ describe('sceneVariablesSetToVariables', () => {
|
|||||||
description: 'test-desc',
|
description: 'test-desc',
|
||||||
value: ['selected-value'],
|
value: ['selected-value'],
|
||||||
text: ['selected-value-text'],
|
text: ['selected-value-text'],
|
||||||
datasource: { uid: 'fake-uid', type: 'fake-type' },
|
datasource: { uid: 'fake-std', type: 'fake-std' },
|
||||||
query: 'query',
|
query: 'query',
|
||||||
includeAll: true,
|
includeAll: true,
|
||||||
allValue: 'test-all',
|
allValue: 'test-all',
|
||||||
@@ -856,45 +856,44 @@ describe('sceneVariablesSetToVariables', () => {
|
|||||||
|
|
||||||
expect(result).toHaveLength(1);
|
expect(result).toHaveLength(1);
|
||||||
expect(result[0]).toMatchInlineSnapshot(`
|
expect(result[0]).toMatchInlineSnapshot(`
|
||||||
{
|
{
|
||||||
"kind": "QueryVariable",
|
"kind": "QueryVariable",
|
||||||
|
"spec": {
|
||||||
|
"allValue": "test-all",
|
||||||
|
"allowCustomValue": true,
|
||||||
|
"current": {
|
||||||
|
"text": [
|
||||||
|
"selected-value-text",
|
||||||
|
],
|
||||||
|
"value": [
|
||||||
|
"selected-value",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
"datasource": {
|
||||||
|
"type": "fake-std",
|
||||||
|
"uid": "fake-std",
|
||||||
|
},
|
||||||
|
"definition": undefined,
|
||||||
|
"description": "test-desc",
|
||||||
|
"hide": "dontHide",
|
||||||
|
"includeAll": true,
|
||||||
|
"label": "test-label",
|
||||||
|
"multi": true,
|
||||||
|
"name": "test",
|
||||||
|
"options": [],
|
||||||
|
"query": {
|
||||||
|
"kind": "fake-std",
|
||||||
"spec": {
|
"spec": {
|
||||||
"allValue": "test-all",
|
"__legacyStringValue": "query",
|
||||||
"allowCustomValue": true,
|
|
||||||
"current": {
|
|
||||||
"text": [
|
|
||||||
"selected-value-text",
|
|
||||||
],
|
|
||||||
"value": [
|
|
||||||
"selected-value",
|
|
||||||
],
|
|
||||||
},
|
|
||||||
"definition": undefined,
|
|
||||||
"description": "test-desc",
|
|
||||||
"hide": "dontHide",
|
|
||||||
"includeAll": true,
|
|
||||||
"label": "test-label",
|
|
||||||
"multi": true,
|
|
||||||
"name": "test",
|
|
||||||
"options": [],
|
|
||||||
"query": {
|
|
||||||
"datasource": {
|
|
||||||
"name": "fake-uid",
|
|
||||||
},
|
|
||||||
"group": "fake-type",
|
|
||||||
"kind": "DataQuery",
|
|
||||||
"spec": {
|
|
||||||
"__legacyStringValue": "query",
|
|
||||||
},
|
|
||||||
"version": "v0",
|
|
||||||
},
|
|
||||||
"refresh": "onDashboardLoad",
|
|
||||||
"regex": "",
|
|
||||||
"skipUrlSync": false,
|
|
||||||
"sort": "disabled",
|
|
||||||
},
|
},
|
||||||
}
|
},
|
||||||
`);
|
"refresh": "onDashboardLoad",
|
||||||
|
"regex": "",
|
||||||
|
"skipUrlSync": false,
|
||||||
|
"sort": "disabled",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
`);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should handle CustomVariable', () => {
|
it('should handle CustomVariable', () => {
|
||||||
@@ -1153,7 +1152,7 @@ describe('sceneVariablesSetToVariables', () => {
|
|||||||
name: 'test',
|
name: 'test',
|
||||||
label: 'test-label',
|
label: 'test-label',
|
||||||
description: 'test-desc',
|
description: 'test-desc',
|
||||||
datasource: { uid: 'fake-uid', type: 'fake-type' },
|
datasource: { uid: 'fake-std', type: 'fake-std' },
|
||||||
filters: [
|
filters: [
|
||||||
{
|
{
|
||||||
key: 'filterTest',
|
key: 'filterTest',
|
||||||
@@ -1189,8 +1188,8 @@ describe('sceneVariablesSetToVariables', () => {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
"datasource": {
|
"datasource": {
|
||||||
"type": "fake-type",
|
"type": "fake-std",
|
||||||
"uid": "fake-uid",
|
"uid": "fake-std",
|
||||||
},
|
},
|
||||||
"defaultKeys": [],
|
"defaultKeys": [],
|
||||||
"description": "test-desc",
|
"description": "test-desc",
|
||||||
@@ -1215,7 +1214,7 @@ describe('sceneVariablesSetToVariables', () => {
|
|||||||
name: 'test',
|
name: 'test',
|
||||||
label: 'test-label',
|
label: 'test-label',
|
||||||
description: 'test-desc',
|
description: 'test-desc',
|
||||||
datasource: { uid: 'fake-uid', type: 'fake-type' },
|
datasource: { uid: 'fake-std', type: 'fake-std' },
|
||||||
defaultKeys: [
|
defaultKeys: [
|
||||||
{
|
{
|
||||||
text: 'some',
|
text: 'some',
|
||||||
@@ -1265,8 +1264,8 @@ describe('sceneVariablesSetToVariables', () => {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
"datasource": {
|
"datasource": {
|
||||||
"type": "fake-type",
|
"type": "fake-std",
|
||||||
"uid": "fake-uid",
|
"uid": "fake-std",
|
||||||
},
|
},
|
||||||
"defaultKeys": [
|
"defaultKeys": [
|
||||||
{
|
{
|
||||||
@@ -1313,7 +1312,7 @@ describe('sceneVariablesSetToVariables', () => {
|
|||||||
name: 'test',
|
name: 'test',
|
||||||
label: 'test-label',
|
label: 'test-label',
|
||||||
description: 'test-desc',
|
description: 'test-desc',
|
||||||
datasource: { uid: 'fake-uid', type: 'fake-type' },
|
datasource: { uid: 'fake-std', type: 'fake-std' },
|
||||||
defaultOptions: [
|
defaultOptions: [
|
||||||
{
|
{
|
||||||
text: 'Foo',
|
text: 'Foo',
|
||||||
@@ -1341,8 +1340,8 @@ describe('sceneVariablesSetToVariables', () => {
|
|||||||
"value": [],
|
"value": [],
|
||||||
},
|
},
|
||||||
"datasource": {
|
"datasource": {
|
||||||
"type": "fake-type",
|
"type": "fake-std",
|
||||||
"uid": "fake-uid",
|
"uid": "fake-std",
|
||||||
},
|
},
|
||||||
"defaultValue": undefined,
|
"defaultValue": undefined,
|
||||||
"description": "test-desc",
|
"description": "test-desc",
|
||||||
@@ -1373,7 +1372,7 @@ describe('sceneVariablesSetToVariables', () => {
|
|||||||
name: 'test',
|
name: 'test',
|
||||||
label: 'test-label',
|
label: 'test-label',
|
||||||
description: 'test-desc',
|
description: 'test-desc',
|
||||||
datasource: { uid: 'fake-uid', type: 'fake-type' },
|
datasource: { uid: 'fake-std', type: 'fake-std' },
|
||||||
defaultOptions: [
|
defaultOptions: [
|
||||||
{
|
{
|
||||||
text: 'Foo',
|
text: 'Foo',
|
||||||
|
|||||||
@@ -24,7 +24,6 @@ import {
|
|||||||
GroupByVariableKind,
|
GroupByVariableKind,
|
||||||
defaultVariableHide,
|
defaultVariableHide,
|
||||||
VariableOption,
|
VariableOption,
|
||||||
defaultDataQueryKind,
|
|
||||||
AdHocFilterWithLabels,
|
AdHocFilterWithLabels,
|
||||||
} from '@grafana/schema/dist/esm/schema/dashboard/v2alpha1/types.spec.gen';
|
} from '@grafana/schema/dist/esm/schema/dashboard/v2alpha1/types.spec.gen';
|
||||||
|
|
||||||
@@ -295,30 +294,14 @@ export function sceneVariablesSetToSchemaV2Variables(
|
|||||||
}
|
}
|
||||||
const query = variable.state.query;
|
const query = variable.state.query;
|
||||||
let dataQuery: DataQueryKind | string;
|
let dataQuery: DataQueryKind | string;
|
||||||
const datasource = getElementDatasource(set, variable, 'variable', undefined, dsReferencesMapping);
|
|
||||||
|
|
||||||
if (typeof query !== 'string') {
|
if (typeof query !== 'string') {
|
||||||
dataQuery = {
|
dataQuery = {
|
||||||
kind: 'DataQuery',
|
kind: variable.state.datasource?.type ?? getDataQueryKind(query),
|
||||||
version: defaultDataQueryKind().version,
|
|
||||||
group: datasource?.type ?? getDataQueryKind(query),
|
|
||||||
...(datasource?.uid && {
|
|
||||||
datasource: {
|
|
||||||
name: datasource.uid,
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
spec: getDataQuerySpec(query),
|
spec: getDataQuerySpec(query),
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
dataQuery = {
|
dataQuery = {
|
||||||
kind: 'DataQuery',
|
kind: variable.state.datasource?.type ?? getDataQueryKind(query),
|
||||||
version: defaultDataQueryKind().version,
|
|
||||||
group: datasource?.type ?? getDataQueryKind(query),
|
|
||||||
...(datasource?.uid && {
|
|
||||||
datasource: {
|
|
||||||
name: datasource.uid,
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
spec: {
|
spec: {
|
||||||
[LEGACY_STRING_VALUE_KEY]: query,
|
[LEGACY_STRING_VALUE_KEY]: query,
|
||||||
},
|
},
|
||||||
@@ -332,6 +315,7 @@ export function sceneVariablesSetToSchemaV2Variables(
|
|||||||
options,
|
options,
|
||||||
query: dataQuery,
|
query: dataQuery,
|
||||||
definition: variable.state.definition,
|
definition: variable.state.definition,
|
||||||
|
datasource: getElementDatasource(set, variable, 'variable', undefined, dsReferencesMapping),
|
||||||
sort: transformSortVariableToEnum(variable.state.sort),
|
sort: transformSortVariableToEnum(variable.state.sort),
|
||||||
refresh: transformVariableRefreshToEnum(variable.state.refresh),
|
refresh: transformVariableRefreshToEnum(variable.state.refresh),
|
||||||
regex: variable.state.regex,
|
regex: variable.state.regex,
|
||||||
|
|||||||
+40
-56
@@ -22,7 +22,6 @@ import {
|
|||||||
CustomVariableKind,
|
CustomVariableKind,
|
||||||
Spec as DashboardV2Spec,
|
Spec as DashboardV2Spec,
|
||||||
DatasourceVariableKind,
|
DatasourceVariableKind,
|
||||||
defaultDataQueryKind,
|
|
||||||
GridLayoutItemSpec,
|
GridLayoutItemSpec,
|
||||||
GridLayoutSpec,
|
GridLayoutSpec,
|
||||||
GroupByVariableKind,
|
GroupByVariableKind,
|
||||||
@@ -139,7 +138,6 @@ describe('transformSaveModelSchemaV2ToScene', () => {
|
|||||||
// Variables
|
// Variables
|
||||||
const variables = scene.state?.$variables;
|
const variables = scene.state?.$variables;
|
||||||
expect(variables?.state.variables).toHaveLength(dash.variables.length);
|
expect(variables?.state.variables).toHaveLength(dash.variables.length);
|
||||||
|
|
||||||
validateVariable({
|
validateVariable({
|
||||||
sceneVariable: variables?.state.variables[0],
|
sceneVariable: variables?.state.variables[0],
|
||||||
variableKind: dash.variables[0] as QueryVariableKind,
|
variableKind: dash.variables[0] as QueryVariableKind,
|
||||||
@@ -208,26 +206,36 @@ describe('transformSaveModelSchemaV2ToScene', () => {
|
|||||||
// Annotations
|
// Annotations
|
||||||
expect(scene.state.$data).toBeInstanceOf(DashboardDataLayerSet);
|
expect(scene.state.$data).toBeInstanceOf(DashboardDataLayerSet);
|
||||||
const dataLayers = scene.state.$data as DashboardDataLayerSet;
|
const dataLayers = scene.state.$data as DashboardDataLayerSet;
|
||||||
|
// we should get two annotations, Grafana built-in and the custom ones
|
||||||
expect(dataLayers.state.annotationLayers).toHaveLength(dash.annotations.length);
|
expect(dataLayers.state.annotationLayers).toHaveLength(dash.annotations.length);
|
||||||
expect(dataLayers.state.annotationLayers[0].state.name).toBe(dash.annotations[0].spec.name);
|
expect(dataLayers.state.annotationLayers).toHaveLength(5);
|
||||||
expect(dataLayers.state.annotationLayers[0].state.isEnabled).toBe(dash.annotations[0].spec.enable);
|
|
||||||
expect(dataLayers.state.annotationLayers[0].state.isHidden).toBe(dash.annotations[0].spec.hide);
|
// Built-in
|
||||||
|
const builtInAnnotation = dataLayers.state.annotationLayers[0] as unknown as DashboardAnnotationsDataLayer;
|
||||||
|
expect(builtInAnnotation.state.name).toBe('Annotations & Alerts');
|
||||||
|
expect(builtInAnnotation.state.isEnabled).toBe(true);
|
||||||
|
expect(builtInAnnotation.state.isHidden).toBe(true);
|
||||||
|
expect(builtInAnnotation.state?.query.builtIn).toBe(1);
|
||||||
|
|
||||||
// Enabled
|
// Enabled
|
||||||
expect(dataLayers.state.annotationLayers[1].state.name).toBe(dash.annotations[1].spec.name);
|
expect(dataLayers.state.annotationLayers[1].state.name).toBe(dash.annotations[1].spec.name);
|
||||||
expect(dataLayers.state.annotationLayers[1].state.isEnabled).toBe(dash.annotations[1].spec.enable);
|
expect(dataLayers.state.annotationLayers[1].state.isEnabled).toBe(dash.annotations[1].spec.enable);
|
||||||
expect(dataLayers.state.annotationLayers[1].state.isHidden).toBe(dash.annotations[1].spec.hide);
|
expect(dataLayers.state.annotationLayers[1].state.isHidden).toBe(dash.annotations[1].spec.hide);
|
||||||
|
|
||||||
// Disabled
|
|
||||||
expect(dataLayers.state.annotationLayers[2].state.name).toBe(dash.annotations[2].spec.name);
|
expect(dataLayers.state.annotationLayers[2].state.name).toBe(dash.annotations[2].spec.name);
|
||||||
expect(dataLayers.state.annotationLayers[2].state.isEnabled).toBe(dash.annotations[2].spec.enable);
|
expect(dataLayers.state.annotationLayers[2].state.isEnabled).toBe(dash.annotations[2].spec.enable);
|
||||||
expect(dataLayers.state.annotationLayers[2].state.isHidden).toBe(dash.annotations[2].spec.hide);
|
expect(dataLayers.state.annotationLayers[2].state.isHidden).toBe(dash.annotations[2].spec.hide);
|
||||||
|
|
||||||
// Hidden
|
// Disabled
|
||||||
expect(dataLayers.state.annotationLayers[3].state.name).toBe(dash.annotations[3].spec.name);
|
expect(dataLayers.state.annotationLayers[3].state.name).toBe(dash.annotations[3].spec.name);
|
||||||
expect(dataLayers.state.annotationLayers[3].state.isEnabled).toBe(dash.annotations[3].spec.enable);
|
expect(dataLayers.state.annotationLayers[3].state.isEnabled).toBe(dash.annotations[3].spec.enable);
|
||||||
expect(dataLayers.state.annotationLayers[3].state.isHidden).toBe(dash.annotations[3].spec.hide);
|
expect(dataLayers.state.annotationLayers[3].state.isHidden).toBe(dash.annotations[3].spec.hide);
|
||||||
|
|
||||||
|
// Hidden
|
||||||
|
expect(dataLayers.state.annotationLayers[4].state.name).toBe(dash.annotations[4].spec.name);
|
||||||
|
expect(dataLayers.state.annotationLayers[4].state.isEnabled).toBe(dash.annotations[4].spec.enable);
|
||||||
|
expect(dataLayers.state.annotationLayers[4].state.isHidden).toBe(dash.annotations[4].spec.hide);
|
||||||
|
|
||||||
// VizPanel
|
// VizPanel
|
||||||
const vizPanels = (scene.state.body as DashboardLayoutManager).getVizPanels();
|
const vizPanels = (scene.state.body as DashboardLayoutManager).getVizPanels();
|
||||||
expect(vizPanels).toHaveLength(2);
|
expect(vizPanels).toHaveLength(2);
|
||||||
@@ -271,14 +279,13 @@ describe('transformSaveModelSchemaV2ToScene', () => {
|
|||||||
kind: 'PanelQuery',
|
kind: 'PanelQuery',
|
||||||
spec: {
|
spec: {
|
||||||
refId: 'A',
|
refId: 'A',
|
||||||
|
datasource: {
|
||||||
|
type: 'graphite',
|
||||||
|
uid: 'datasource1',
|
||||||
|
},
|
||||||
hidden: false,
|
hidden: false,
|
||||||
query: {
|
query: {
|
||||||
kind: 'DataQuery',
|
kind: 'prometheus',
|
||||||
version: defaultDataQueryKind().version,
|
|
||||||
group: 'graphite',
|
|
||||||
datasource: {
|
|
||||||
name: 'datasource1',
|
|
||||||
},
|
|
||||||
spec: {
|
spec: {
|
||||||
expr: 'test-query',
|
expr: 'test-query',
|
||||||
},
|
},
|
||||||
@@ -300,14 +307,13 @@ describe('transformSaveModelSchemaV2ToScene', () => {
|
|||||||
kind: 'PanelQuery',
|
kind: 'PanelQuery',
|
||||||
spec: {
|
spec: {
|
||||||
refId: 'A',
|
refId: 'A',
|
||||||
|
datasource: {
|
||||||
|
type: 'prometheus',
|
||||||
|
uid: 'datasource1',
|
||||||
|
},
|
||||||
hidden: false,
|
hidden: false,
|
||||||
query: {
|
query: {
|
||||||
kind: 'DataQuery',
|
kind: 'prometheus',
|
||||||
version: defaultDataQueryKind().version,
|
|
||||||
group: 'prometheus',
|
|
||||||
datasource: {
|
|
||||||
name: 'datasource1',
|
|
||||||
},
|
|
||||||
spec: {
|
spec: {
|
||||||
expr: 'test-query',
|
expr: 'test-query',
|
||||||
},
|
},
|
||||||
@@ -334,12 +340,7 @@ describe('transformSaveModelSchemaV2ToScene', () => {
|
|||||||
refId: 'A',
|
refId: 'A',
|
||||||
hidden: false,
|
hidden: false,
|
||||||
query: {
|
query: {
|
||||||
kind: 'DataQuery',
|
kind: 'prometheus',
|
||||||
version: defaultDataQueryKind().version,
|
|
||||||
group: 'prometheus',
|
|
||||||
datasource: {
|
|
||||||
name: 'abc123',
|
|
||||||
},
|
|
||||||
spec: {
|
spec: {
|
||||||
expr: 'test-query',
|
expr: 'test-query',
|
||||||
},
|
},
|
||||||
@@ -721,6 +722,10 @@ describe('transformSaveModelSchemaV2ToScene', () => {
|
|||||||
enable: true,
|
enable: true,
|
||||||
hide: false,
|
hide: false,
|
||||||
iconColor: 'purple',
|
iconColor: 'purple',
|
||||||
|
datasource: {
|
||||||
|
type: 'prometheus',
|
||||||
|
uid: 'abc123',
|
||||||
|
},
|
||||||
legacyOptions: {
|
legacyOptions: {
|
||||||
expr: 'rate(http_requests_total[5m])',
|
expr: 'rate(http_requests_total[5m])',
|
||||||
queryType: 'range',
|
queryType: 'range',
|
||||||
@@ -728,15 +733,6 @@ describe('transformSaveModelSchemaV2ToScene', () => {
|
|||||||
useValueAsTime: true,
|
useValueAsTime: true,
|
||||||
step: '1m',
|
step: '1m',
|
||||||
},
|
},
|
||||||
query: {
|
|
||||||
kind: 'DataQuery',
|
|
||||||
version: defaultDataQueryKind().version,
|
|
||||||
group: 'prometheus',
|
|
||||||
datasource: {
|
|
||||||
name: 'abc123',
|
|
||||||
},
|
|
||||||
spec: {},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@@ -768,35 +764,23 @@ describe('transformSaveModelSchemaV2ToScene', () => {
|
|||||||
// Get the annotation layers
|
// Get the annotation layers
|
||||||
const dataLayerSet = scene.state.$data as DashboardDataLayerSet;
|
const dataLayerSet = scene.state.$data as DashboardDataLayerSet;
|
||||||
expect(dataLayerSet).toBeDefined();
|
expect(dataLayerSet).toBeDefined();
|
||||||
|
// it should have two annotation layers, built-in and custom
|
||||||
expect(dataLayerSet.state.annotationLayers.length).toBe(2);
|
expect(dataLayerSet.state.annotationLayers.length).toBe(2);
|
||||||
const defaultAnnotationLayer = dataLayerSet.state.annotationLayers[0] as DashboardAnnotationsDataLayer;
|
|
||||||
|
|
||||||
// Verify that the default annotation layer has been correctly initialized
|
|
||||||
expect(defaultAnnotationLayer.state.query).toEqual({
|
|
||||||
datasource: {
|
|
||||||
uid: '-- Grafana --',
|
|
||||||
type: 'grafana',
|
|
||||||
},
|
|
||||||
builtIn: 1,
|
|
||||||
enable: true,
|
|
||||||
iconColor: 'rgba(0, 211, 255, 1)',
|
|
||||||
name: 'Annotations & Alerts',
|
|
||||||
hide: true,
|
|
||||||
type: 'dashboard',
|
|
||||||
});
|
|
||||||
|
|
||||||
const annotationLayer = dataLayerSet.state.annotationLayers[1] as DashboardAnnotationsDataLayer;
|
const annotationLayer = dataLayerSet.state.annotationLayers[1] as DashboardAnnotationsDataLayer;
|
||||||
|
|
||||||
// Verify that the legacyOptions have been merged into the query object
|
// Verify that the legacyOptions have been merged into the query object
|
||||||
expect(annotationLayer.state.query).toMatchObject({
|
expect(annotationLayer.state.query).toMatchObject({
|
||||||
datasource: {
|
|
||||||
uid: 'abc123',
|
|
||||||
type: 'prometheus',
|
|
||||||
},
|
|
||||||
name: 'Annotation with legacy options',
|
name: 'Annotation with legacy options',
|
||||||
enable: true,
|
expr: 'rate(http_requests_total[5m])',
|
||||||
hide: false,
|
queryType: 'range',
|
||||||
iconColor: 'purple',
|
legendFormat: '{{method}} {{endpoint}}',
|
||||||
|
useValueAsTime: true,
|
||||||
|
step: '1m',
|
||||||
|
});
|
||||||
|
|
||||||
|
// Verify the original legacyOptions object is also preserved
|
||||||
|
expect(annotationLayer.state.query.legacyOptions).toMatchObject({
|
||||||
expr: 'rate(http_requests_total[5m])',
|
expr: 'rate(http_requests_total[5m])',
|
||||||
queryType: 'range',
|
queryType: 'range',
|
||||||
legendFormat: '{{method}} {{endpoint}}',
|
legendFormat: '{{method}} {{endpoint}}',
|
||||||
|
|||||||
+17
-18
@@ -28,7 +28,6 @@ import {
|
|||||||
defaultAdhocVariableKind,
|
defaultAdhocVariableKind,
|
||||||
defaultConstantVariableKind,
|
defaultConstantVariableKind,
|
||||||
defaultCustomVariableKind,
|
defaultCustomVariableKind,
|
||||||
defaultDataQueryKind,
|
|
||||||
defaultDatasourceVariableKind,
|
defaultDatasourceVariableKind,
|
||||||
defaultGroupByVariableKind,
|
defaultGroupByVariableKind,
|
||||||
defaultIntervalVariableKind,
|
defaultIntervalVariableKind,
|
||||||
@@ -63,7 +62,6 @@ import { DashboardScene } from '../scene/DashboardScene';
|
|||||||
import { DashboardLayoutManager } from '../scene/types/DashboardLayoutManager';
|
import { DashboardLayoutManager } from '../scene/types/DashboardLayoutManager';
|
||||||
import { getIntervalsFromQueryString } from '../utils/utils';
|
import { getIntervalsFromQueryString } from '../utils/utils';
|
||||||
|
|
||||||
import { transformV2ToV1AnnotationQuery } from './annotations';
|
|
||||||
import { SnapshotVariable } from './custom-variables/SnapshotVariable';
|
import { SnapshotVariable } from './custom-variables/SnapshotVariable';
|
||||||
import { layoutDeserializerRegistry } from './layoutSerializers/layoutSerializerRegistry';
|
import { layoutDeserializerRegistry } from './layoutSerializers/layoutSerializerRegistry';
|
||||||
import { getRuntimeVariableDataSource } from './layoutSerializers/utils';
|
import { getRuntimeVariableDataSource } from './layoutSerializers/utils';
|
||||||
@@ -92,23 +90,32 @@ export function transformSaveModelSchemaV2ToScene(dto: DashboardWithAccessInfo<D
|
|||||||
const { spec: dashboard, metadata, apiVersion } = dto;
|
const { spec: dashboard, metadata, apiVersion } = dto;
|
||||||
|
|
||||||
// annotations might not come with the builtIn Grafana annotation, we need to add it
|
// annotations might not come with the builtIn Grafana annotation, we need to add it
|
||||||
|
|
||||||
const grafanaBuiltAnnotation = getGrafanaBuiltInAnnotationDataLayer(dashboard);
|
const grafanaBuiltAnnotation = getGrafanaBuiltInAnnotationDataLayer(dashboard);
|
||||||
if (grafanaBuiltAnnotation) {
|
if (grafanaBuiltAnnotation) {
|
||||||
dashboard.annotations.unshift(grafanaBuiltAnnotation);
|
dashboard.annotations.unshift(grafanaBuiltAnnotation);
|
||||||
}
|
}
|
||||||
|
|
||||||
const annotationLayers = dashboard.annotations.map((annotation) => {
|
const annotationLayers = dashboard.annotations.map((annotation) => {
|
||||||
const annotationQuerySpec = transformV2ToV1AnnotationQuery(annotation);
|
let annoQuerySpec = annotation.spec;
|
||||||
|
// some annotations will contain in the legacyOptions properties that need to be
|
||||||
const layerState = {
|
// added to the root level annotation spec
|
||||||
|
if (annoQuerySpec?.legacyOptions) {
|
||||||
|
annoQuerySpec = {
|
||||||
|
...annoQuerySpec,
|
||||||
|
...annoQuerySpec.legacyOptions,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return new DashboardAnnotationsDataLayer({
|
||||||
key: uniqueId('annotations-'),
|
key: uniqueId('annotations-'),
|
||||||
query: annotationQuerySpec,
|
query: {
|
||||||
|
...annoQuerySpec,
|
||||||
|
builtIn: annotation.spec.builtIn ? 1 : 0,
|
||||||
|
},
|
||||||
name: annotation.spec.name,
|
name: annotation.spec.name,
|
||||||
isEnabled: Boolean(annotation.spec.enable),
|
isEnabled: Boolean(annotation.spec.enable),
|
||||||
isHidden: Boolean(annotation.spec.hide),
|
isHidden: Boolean(annotation.spec.hide),
|
||||||
};
|
});
|
||||||
|
|
||||||
return new DashboardAnnotationsDataLayer(layerState);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const isDashboardEditable = Boolean(dashboard.editable);
|
const isDashboardEditable = Boolean(dashboard.editable);
|
||||||
@@ -507,15 +514,7 @@ function getGrafanaBuiltInAnnotationDataLayer(dashboard: DashboardV2Spec) {
|
|||||||
const grafanaBuiltAnnotation: AnnotationQueryKind = {
|
const grafanaBuiltAnnotation: AnnotationQueryKind = {
|
||||||
kind: 'AnnotationQuery',
|
kind: 'AnnotationQuery',
|
||||||
spec: {
|
spec: {
|
||||||
query: {
|
datasource: { uid: '-- Grafana --', type: 'grafana' },
|
||||||
kind: 'DataQuery',
|
|
||||||
version: defaultDataQueryKind().version,
|
|
||||||
group: 'grafana',
|
|
||||||
datasource: {
|
|
||||||
name: '-- Grafana --',
|
|
||||||
},
|
|
||||||
spec: {},
|
|
||||||
},
|
|
||||||
name: 'Annotations & Alerts',
|
name: 'Annotations & Alerts',
|
||||||
iconColor: DEFAULT_ANNOTATION_COLOR,
|
iconColor: DEFAULT_ANNOTATION_COLOR,
|
||||||
enable: true,
|
enable: true,
|
||||||
|
|||||||
+35
-50
@@ -57,7 +57,6 @@ import {
|
|||||||
validateDashboardSchemaV2,
|
validateDashboardSchemaV2,
|
||||||
getDataQueryKind,
|
getDataQueryKind,
|
||||||
getAutoAssignedDSRef,
|
getAutoAssignedDSRef,
|
||||||
getVizPanelQueries,
|
|
||||||
} from './transformSceneToSaveModelSchemaV2';
|
} from './transformSceneToSaveModelSchemaV2';
|
||||||
|
|
||||||
// Mock dependencies
|
// Mock dependencies
|
||||||
@@ -411,7 +410,9 @@ describe('transformSceneToSaveModelSchemaV2', () => {
|
|||||||
expect(result).toMatchSnapshot();
|
expect(result).toMatchSnapshot();
|
||||||
|
|
||||||
// Check that the annotation layers are correctly transformed
|
// Check that the annotation layers are correctly transformed
|
||||||
expect(result.annotations).toHaveLength(2);
|
expect(result.annotations).toHaveLength(3);
|
||||||
|
// Check annotation layer 3 without initial data source isn't updated with runtime default
|
||||||
|
expect(result.annotations?.[2].spec.datasource?.type).toBe(undefined);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should transform the minimum scene to save model schema v2', () => {
|
it('should transform the minimum scene to save model schema v2', () => {
|
||||||
@@ -561,8 +562,16 @@ describe('transformSceneToSaveModelSchemaV2', () => {
|
|||||||
name: 'annotation-with-options',
|
name: 'annotation-with-options',
|
||||||
enable: true,
|
enable: true,
|
||||||
iconColor: 'red',
|
iconColor: 'red',
|
||||||
customProp1: true,
|
legacyOptions: {
|
||||||
customProp2: 'test',
|
expr: 'rate(http_requests_total[5m])',
|
||||||
|
queryType: 'range',
|
||||||
|
legendFormat: '{{method}} {{endpoint}}',
|
||||||
|
useValueAsTime: true,
|
||||||
|
},
|
||||||
|
// Some other properties that aren't in the annotation spec
|
||||||
|
// and should be moved to options
|
||||||
|
customProp1: 'value1',
|
||||||
|
customProp2: 'value2',
|
||||||
},
|
},
|
||||||
name: 'layerWithOptions',
|
name: 'layerWithOptions',
|
||||||
isEnabled: true,
|
isEnabled: true,
|
||||||
@@ -584,11 +593,19 @@ describe('transformSceneToSaveModelSchemaV2', () => {
|
|||||||
expect(result.annotations.length).toBe(1);
|
expect(result.annotations.length).toBe(1);
|
||||||
expect(result.annotations[0].spec.legacyOptions).toBeDefined();
|
expect(result.annotations[0].spec.legacyOptions).toBeDefined();
|
||||||
expect(result.annotations[0].spec.legacyOptions).toEqual({
|
expect(result.annotations[0].spec.legacyOptions).toEqual({
|
||||||
customProp1: true,
|
expr: 'rate(http_requests_total[5m])',
|
||||||
customProp2: 'test',
|
queryType: 'range',
|
||||||
|
legendFormat: '{{method}} {{endpoint}}',
|
||||||
|
useValueAsTime: true,
|
||||||
|
customProp1: 'value1',
|
||||||
|
customProp2: 'value2',
|
||||||
});
|
});
|
||||||
|
|
||||||
// Ensure these properties are not at the root level
|
// Ensure these properties are not at the root level
|
||||||
|
expect(result).not.toHaveProperty('annotations[0].spec.expr');
|
||||||
|
expect(result).not.toHaveProperty('annotations[0].spec.queryType');
|
||||||
|
expect(result).not.toHaveProperty('annotations[0].spec.legendFormat');
|
||||||
|
expect(result).not.toHaveProperty('annotations[0].spec.useValueAsTime');
|
||||||
expect(result).not.toHaveProperty('annotations[0].spec.customProp1');
|
expect(result).not.toHaveProperty('annotations[0].spec.customProp1');
|
||||||
expect(result).not.toHaveProperty('annotations[0].spec.customProp2');
|
expect(result).not.toHaveProperty('annotations[0].spec.customProp2');
|
||||||
});
|
});
|
||||||
@@ -817,50 +834,6 @@ describe('getElementDatasource', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('getVizPanelQueries', () => {
|
|
||||||
it('should handle panel query datasources correctly', () => {
|
|
||||||
const queryWithDS: SceneDataQuery = {
|
|
||||||
refId: 'B',
|
|
||||||
datasource: { uid: 'prometheus-uid', type: 'prometheus' },
|
|
||||||
};
|
|
||||||
|
|
||||||
const queryWithoutDS: SceneDataQuery = {
|
|
||||||
refId: 'A',
|
|
||||||
};
|
|
||||||
|
|
||||||
// Mock query runner
|
|
||||||
const queryRunner = new SceneQueryRunner({
|
|
||||||
queries: [queryWithoutDS, queryWithDS],
|
|
||||||
datasource: { uid: 'default-ds', type: 'default' },
|
|
||||||
});
|
|
||||||
// Create test elements
|
|
||||||
const vizPanel = new VizPanel({
|
|
||||||
key: 'panel-1',
|
|
||||||
pluginId: 'timeseries',
|
|
||||||
$data: queryRunner,
|
|
||||||
});
|
|
||||||
|
|
||||||
// Mock dsReferencesMapping
|
|
||||||
const dsReferencesMapping = {
|
|
||||||
panels: new Map(new Set([['panel-1', new Set<string>(['A'])]])),
|
|
||||||
variables: new Set<string>(),
|
|
||||||
annotations: new Set<string>(),
|
|
||||||
};
|
|
||||||
|
|
||||||
const result = getVizPanelQueries(vizPanel, dsReferencesMapping);
|
|
||||||
expect(result.length).toBe(2);
|
|
||||||
expect(result[0].spec.query.kind).toBe('DataQuery');
|
|
||||||
expect(result[0].spec.query.datasource).toBeUndefined(); // ignore datasource if it wasn't provided
|
|
||||||
expect(result[0].spec.query.group).toBe('default');
|
|
||||||
expect(result[0].spec.query.version).toBe('v0');
|
|
||||||
|
|
||||||
expect(result[1].spec.query.kind).toBe('DataQuery');
|
|
||||||
expect(result[1].spec.query.datasource?.name).toBe('prometheus-uid');
|
|
||||||
expect(result[1].spec.query.group).toBe('prometheus');
|
|
||||||
expect(result[1].spec.query.version).toBe('v0');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
function getMinimalSceneState(body: DashboardLayoutManager): Partial<DashboardSceneState> {
|
function getMinimalSceneState(body: DashboardLayoutManager): Partial<DashboardSceneState> {
|
||||||
return {
|
return {
|
||||||
id: 1,
|
id: 1,
|
||||||
@@ -1092,6 +1065,18 @@ function createAnnotationLayers() {
|
|||||||
isEnabled: true,
|
isEnabled: true,
|
||||||
isHidden: true,
|
isHidden: true,
|
||||||
}),
|
}),
|
||||||
|
// this could happen if a dahboard was created from code and the datasource was not defined
|
||||||
|
new DashboardAnnotationsDataLayer({
|
||||||
|
key: 'layer3',
|
||||||
|
query: {
|
||||||
|
name: 'query3',
|
||||||
|
enable: true,
|
||||||
|
iconColor: 'green',
|
||||||
|
},
|
||||||
|
name: 'layer3',
|
||||||
|
isEnabled: true,
|
||||||
|
isHidden: true,
|
||||||
|
}),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+66
-46
@@ -43,7 +43,6 @@ import {
|
|||||||
DashboardCursorSync,
|
DashboardCursorSync,
|
||||||
FieldConfig,
|
FieldConfig,
|
||||||
FieldColor,
|
FieldColor,
|
||||||
defaultDataQueryKind,
|
|
||||||
} from '../../../../../packages/grafana-schema/src/schema/dashboard/v2alpha1/types.spec.gen';
|
} from '../../../../../packages/grafana-schema/src/schema/dashboard/v2alpha1/types.spec.gen';
|
||||||
import { DashboardDataLayerSet } from '../scene/DashboardDataLayerSet';
|
import { DashboardDataLayerSet } from '../scene/DashboardDataLayerSet';
|
||||||
import { DashboardScene, DashboardSceneState } from '../scene/DashboardScene';
|
import { DashboardScene, DashboardSceneState } from '../scene/DashboardScene';
|
||||||
@@ -52,7 +51,6 @@ import { dashboardSceneGraph } from '../utils/dashboardSceneGraph';
|
|||||||
import { getLibraryPanelBehavior, getPanelIdForVizPanel, getQueryRunnerFor, isLibraryPanel } from '../utils/utils';
|
import { getLibraryPanelBehavior, getPanelIdForVizPanel, getQueryRunnerFor, isLibraryPanel } from '../utils/utils';
|
||||||
|
|
||||||
import { DSReferencesMapping } from './DashboardSceneSerializer';
|
import { DSReferencesMapping } from './DashboardSceneSerializer';
|
||||||
import { transformV1ToV2AnnotationQuery } from './annotations';
|
|
||||||
import { sceneVariablesSetToSchemaV2Variables } from './sceneVariablesSetToVariables';
|
import { sceneVariablesSetToSchemaV2Variables } from './sceneVariablesSetToVariables';
|
||||||
import { colorIdEnumToColorIdV2, transformCursorSynctoEnum } from './transformToV2TypesUtils';
|
import { colorIdEnumToColorIdV2, transformCursorSynctoEnum } from './transformToV2TypesUtils';
|
||||||
|
|
||||||
@@ -252,7 +250,7 @@ function getPanelLinks(panel: VizPanel): DataLink[] {
|
|||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getVizPanelQueries(vizPanel: VizPanel, dsReferencesMapping?: DSReferencesMapping): PanelQueryKind[] {
|
function getVizPanelQueries(vizPanel: VizPanel, dsReferencesMapping?: DSReferencesMapping): PanelQueryKind[] {
|
||||||
const queries: PanelQueryKind[] = [];
|
const queries: PanelQueryKind[] = [];
|
||||||
const queryRunner = getQueryRunnerFor(vizPanel);
|
const queryRunner = getQueryRunnerFor(vizPanel);
|
||||||
const vizPanelQueries = queryRunner?.state.queries;
|
const vizPanelQueries = queryRunner?.state.queries;
|
||||||
@@ -260,22 +258,12 @@ export function getVizPanelQueries(vizPanel: VizPanel, dsReferencesMapping?: DSR
|
|||||||
if (vizPanelQueries) {
|
if (vizPanelQueries) {
|
||||||
vizPanelQueries.forEach((query) => {
|
vizPanelQueries.forEach((query) => {
|
||||||
const queryDatasource = getElementDatasource(vizPanel, query, 'panel', queryRunner, dsReferencesMapping);
|
const queryDatasource = getElementDatasource(vizPanel, query, 'panel', queryRunner, dsReferencesMapping);
|
||||||
|
|
||||||
const dataQuery: DataQueryKind = {
|
const dataQuery: DataQueryKind = {
|
||||||
kind: 'DataQuery',
|
kind: getDataQueryKind(query, queryRunner),
|
||||||
version: defaultDataQueryKind().version,
|
|
||||||
group: getDataQueryKind(query, queryRunner),
|
|
||||||
datasource: {
|
|
||||||
name: queryDatasource?.uid,
|
|
||||||
},
|
|
||||||
spec: omit(query, 'datasource', 'refId', 'hide'),
|
spec: omit(query, 'datasource', 'refId', 'hide'),
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!dataQuery.datasource?.name) {
|
|
||||||
delete dataQuery.datasource;
|
|
||||||
}
|
|
||||||
|
|
||||||
const querySpec: PanelQuerySpec = {
|
const querySpec: PanelQuerySpec = {
|
||||||
|
datasource: queryDatasource,
|
||||||
query: dataQuery,
|
query: dataQuery,
|
||||||
refId: query.refId,
|
refId: query.refId,
|
||||||
hidden: Boolean(query.hide),
|
hidden: Boolean(query.hide),
|
||||||
@@ -419,46 +407,78 @@ function getAnnotations(state: DashboardSceneState, dsReferencesMapping?: DSRefe
|
|||||||
if (!(layer instanceof dataLayers.AnnotationsDataLayer)) {
|
if (!(layer instanceof dataLayers.AnnotationsDataLayer)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
const result: AnnotationQueryKind = {
|
||||||
|
kind: 'AnnotationQuery',
|
||||||
|
spec: {
|
||||||
|
builtIn: Boolean(layer.state.query.builtIn),
|
||||||
|
name: layer.state.query.name,
|
||||||
|
datasource: getElementDatasource(layer, layer.state.query, 'annotation', undefined, dsReferencesMapping),
|
||||||
|
enable: Boolean(layer.state.isEnabled),
|
||||||
|
hide: Boolean(layer.state.isHidden),
|
||||||
|
iconColor: layer.state.query.iconColor,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
const datasource = getElementDatasource(layer, layer.state.query, 'annotation', undefined, dsReferencesMapping);
|
// Transform v1 dashboard (using target) to v2 structure
|
||||||
|
// adds extra condition to prioritize query over target
|
||||||
let layerDs = layer.state.query.datasource;
|
// if query is defined, use it
|
||||||
|
if (layer.state.query.target && !layer.state.query.query) {
|
||||||
if (!layerDs) {
|
// Handle built-in annotations
|
||||||
// This can happen only if we are transforming a scene that was created
|
if (layer.state.query.builtIn) {
|
||||||
// from a v1 spec. In v1 annotation layer can contain no datasource ref, which is guaranteed
|
result.spec.query = {
|
||||||
// for layers created for v2 schema. See transform transformSaveModelSchemaV2ToScene.ts.
|
kind: 'grafana', // built-in annotations are always of type grafana
|
||||||
// In this case we will resolve default data source
|
spec: {
|
||||||
layerDs = getDefaultDataSourceRef();
|
...layer.state.query.target,
|
||||||
console.error(
|
},
|
||||||
'Misconfigured AnnotationsDataLayer: Data source is required for annotations. Resolving default data source',
|
};
|
||||||
layer,
|
} else {
|
||||||
layerDs
|
result.spec.query = {
|
||||||
);
|
kind: getAnnotationQueryKind(layer.state.query),
|
||||||
|
spec: {
|
||||||
|
...layer.state.query.target,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
// For annotations without query.query defined (e.g., grafana annotations without tags)
|
||||||
|
else if (layer.state.query.query?.kind) {
|
||||||
|
result.spec.query = {
|
||||||
|
kind: layer.state.query.query.kind,
|
||||||
|
spec: {
|
||||||
|
...layer.state.query.query.spec,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
// Collect datasource-specific properties not in standard annotation spec
|
||||||
|
let otherProps = omit(
|
||||||
|
layer.state.query,
|
||||||
|
'type',
|
||||||
|
'target',
|
||||||
|
'builtIn',
|
||||||
|
'name',
|
||||||
|
'datasource',
|
||||||
|
'iconColor',
|
||||||
|
'enable',
|
||||||
|
'hide',
|
||||||
|
'filter',
|
||||||
|
'query'
|
||||||
|
);
|
||||||
|
|
||||||
const result = transformV1ToV2AnnotationQuery(layer.state.query, layerDs.type!, layerDs.uid!, {
|
// Store extra properties in the legacyOptions field instead of directly in the spec
|
||||||
enable: layer.state.isEnabled,
|
if (Object.keys(otherProps).length > 0) {
|
||||||
hide: layer.state.isHidden,
|
// Extract options property and get the rest of the properties
|
||||||
});
|
const { legacyOptions, ...restProps } = otherProps;
|
||||||
|
// Merge options with the rest of the properties
|
||||||
const annotationQuery = layer.state.query;
|
result.spec.legacyOptions = { ...legacyOptions, ...restProps };
|
||||||
|
}
|
||||||
|
|
||||||
// If filter is an empty array, don't save it
|
// If filter is an empty array, don't save it
|
||||||
if (annotationQuery.filter?.ids?.length) {
|
if (layer.state.query.filter?.ids?.length) {
|
||||||
result.spec.filter = annotationQuery.filter;
|
result.spec.filter = layer.state.query.filter;
|
||||||
}
|
|
||||||
|
|
||||||
// Finally, if the datasource references mapping did not containt data source ref,
|
|
||||||
// this means that the original model that was fetched did not contain it. In such scenario we don't want to save
|
|
||||||
// the explicit data source reference, so lets remove it from the save model.
|
|
||||||
if (!datasource) {
|
|
||||||
delete result.spec.query.datasource;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
annotations.push(result);
|
annotations.push(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
return annotations;
|
return annotations;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,8 +22,8 @@ export default function ShareButton({ dashboard, panel }: { dashboard: Dashboard
|
|||||||
|
|
||||||
const [_, buildUrl] = useAsyncFn(async () => {
|
const [_, buildUrl] = useAsyncFn(async () => {
|
||||||
DashboardInteractions.toolbarShareClick();
|
DashboardInteractions.toolbarShareClick();
|
||||||
return await buildShareUrl(dashboard, panel);
|
await buildShareUrl(dashboard, panel);
|
||||||
}, [dashboard]);
|
}, [dashboard, panel]);
|
||||||
|
|
||||||
const onMenuClick = useCallback((isOpen: boolean) => {
|
const onMenuClick = useCallback((isOpen: boolean) => {
|
||||||
if (isOpen) {
|
if (isOpen) {
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import { locationService, reportInteraction } from '@grafana/runtime';
|
|||||||
import {
|
import {
|
||||||
AnnotationQueryKind,
|
AnnotationQueryKind,
|
||||||
Spec as DashboardV2Spec,
|
Spec as DashboardV2Spec,
|
||||||
defaultDataQueryKind,
|
|
||||||
} from '@grafana/schema/dist/esm/schema/dashboard/v2alpha1/types.spec.gen';
|
} from '@grafana/schema/dist/esm/schema/dashboard/v2alpha1/types.spec.gen';
|
||||||
import { Form } from 'app/core/components/Form/Form';
|
import { Form } from 'app/core/components/Form/Form';
|
||||||
import { getDashboardAPI } from 'app/features/dashboard/api/dashboard_api';
|
import { getDashboardAPI } from 'app/features/dashboard/api/dashboard_api';
|
||||||
@@ -17,8 +16,6 @@ import { ImportDashboardFormV2 } from './ImportDashboardFormV2';
|
|||||||
|
|
||||||
const IMPORT_FINISHED_EVENT_NAME = 'dashboard_import_imported';
|
const IMPORT_FINISHED_EVENT_NAME = 'dashboard_import_imported';
|
||||||
|
|
||||||
type FormData = SaveDashboardCommand<DashboardV2Spec> & { [key: `datasource-${string}`]: string };
|
|
||||||
|
|
||||||
export function ImportDashboardOverviewV2() {
|
export function ImportDashboardOverviewV2() {
|
||||||
const [uidReset, setUidReset] = useState(false);
|
const [uidReset, setUidReset] = useState(false);
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
@@ -37,29 +34,24 @@ export function ImportDashboardOverviewV2() {
|
|||||||
dispatch(clearLoadedDashboard());
|
dispatch(clearLoadedDashboard());
|
||||||
}
|
}
|
||||||
|
|
||||||
async function onSubmit(form: FormData) {
|
async function onSubmit(form: SaveDashboardCommand<DashboardV2Spec>) {
|
||||||
reportInteraction(IMPORT_FINISHED_EVENT_NAME);
|
reportInteraction(IMPORT_FINISHED_EVENT_NAME);
|
||||||
|
|
||||||
const dashboardWithDataSources: DashboardV2Spec = {
|
const dashboardWithDataSources: DashboardV2Spec = {
|
||||||
...dashboard,
|
...dashboard,
|
||||||
title: form.dashboard.title,
|
title: form.dashboard.title,
|
||||||
annotations: dashboard.annotations?.map((annotation: AnnotationQueryKind) => {
|
annotations: dashboard.annotations?.map((annotation: AnnotationQueryKind) => {
|
||||||
const dsType = annotation.spec.query?.spec.group;
|
if (annotation.spec.query?.kind) {
|
||||||
if (dsType) {
|
const dsType = annotation.spec.query.kind;
|
||||||
if (form[`datasource-${dsType}` as keyof typeof form]) {
|
if (form[`datasource-${dsType}` as keyof typeof form]) {
|
||||||
const ds = form[`datasource-${dsType}` as keyof typeof form] as { uid: string; type: string };
|
const ds = form[`datasource-${dsType}` as keyof typeof form] as { uid: string; type: string };
|
||||||
return {
|
return {
|
||||||
...annotation,
|
...annotation,
|
||||||
spec: {
|
spec: {
|
||||||
...annotation.spec,
|
...annotation.spec,
|
||||||
query: {
|
datasource: {
|
||||||
kind: 'DataQuery',
|
uid: ds.uid,
|
||||||
group: dsType,
|
type: ds.type,
|
||||||
version: defaultDataQueryKind().version,
|
|
||||||
datasource: { name: ds.uid },
|
|
||||||
spec: {
|
|
||||||
...annotation.spec.query?.spec,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@@ -69,23 +61,18 @@ export function ImportDashboardOverviewV2() {
|
|||||||
}),
|
}),
|
||||||
variables: dashboard.variables?.map((variable) => {
|
variables: dashboard.variables?.map((variable) => {
|
||||||
if (variable.kind === 'QueryVariable') {
|
if (variable.kind === 'QueryVariable') {
|
||||||
const dsType = variable.spec.query?.spec.group;
|
if (variable.spec.query?.kind) {
|
||||||
if (dsType) {
|
const dsType = variable.spec.query.kind;
|
||||||
if (form[`datasource-${dsType}` as keyof typeof form]) {
|
if (form[`datasource-${dsType}` as keyof typeof form]) {
|
||||||
const ds = form[`datasource-${dsType}` as keyof typeof form] as { uid: string; type: string };
|
const ds = form[`datasource-${dsType}` as keyof typeof form] as { uid: string; type: string };
|
||||||
return {
|
return {
|
||||||
...variable,
|
...variable,
|
||||||
spec: {
|
spec: {
|
||||||
...variable.spec,
|
...variable.spec,
|
||||||
query: {
|
datasource: {
|
||||||
...variable.spec.query,
|
...variable.spec.datasource,
|
||||||
spec: {
|
uid: ds.uid,
|
||||||
...variable.spec.query.spec,
|
type: ds.type,
|
||||||
group: ds.type,
|
|
||||||
datasource: {
|
|
||||||
name: ds.uid,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
options: [],
|
options: [],
|
||||||
current: {
|
current: {
|
||||||
@@ -170,7 +157,7 @@ export function ImportDashboardOverviewV2() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Form<FormData>
|
<Form<SaveDashboardCommand<DashboardV2Spec> & { [key: `datasource-${string}`]: string }>
|
||||||
onSubmit={onSubmit}
|
onSubmit={onSubmit}
|
||||||
defaultValues={{ dashboard, k8s: { annotations: { 'grafana.app/folder': folder.uid } } }}
|
defaultValues={{ dashboard, k8s: { annotations: { 'grafana.app/folder': folder.uid } } }}
|
||||||
validateOnMount
|
validateOnMount
|
||||||
|
|||||||
@@ -52,8 +52,7 @@ export function validateVariable<
|
|||||||
expect(sceneVariable?.state.pluginId).toBe(variableKind.spec.pluginId);
|
expect(sceneVariable?.state.pluginId).toBe(variableKind.spec.pluginId);
|
||||||
}
|
}
|
||||||
if (sceneVariable instanceof QueryVariable && variableKind.kind === 'QueryVariable') {
|
if (sceneVariable instanceof QueryVariable && variableKind.kind === 'QueryVariable') {
|
||||||
expect(sceneVariable?.state.datasource?.type).toBe(variableKind.spec.query?.group);
|
expect(sceneVariable?.state.datasource).toBe(variableKind.spec.datasource);
|
||||||
expect(sceneVariable?.state.datasource?.uid).toBe(variableKind.spec.query?.datasource?.name);
|
|
||||||
expect(sceneVariable?.state.query).toEqual(variableKind.spec.query.spec);
|
expect(sceneVariable?.state.query).toEqual(variableKind.spec.query.spec);
|
||||||
}
|
}
|
||||||
if (sceneVariable instanceof CustomVariable && variableKind.kind === 'CustomVariable') {
|
if (sceneVariable instanceof CustomVariable && variableKind.kind === 'CustomVariable') {
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ import { AnnotationQuery, DataQuery, VariableModel, VariableRefresh, Panel } fro
|
|||||||
import { handyTestingSchema } from '@grafana/schema/dist/esm/schema/dashboard/v2_examples';
|
import { handyTestingSchema } from '@grafana/schema/dist/esm/schema/dashboard/v2_examples';
|
||||||
import {
|
import {
|
||||||
Spec as DashboardV2Spec,
|
Spec as DashboardV2Spec,
|
||||||
defaultDataQueryKind,
|
|
||||||
GridLayoutItemKind,
|
GridLayoutItemKind,
|
||||||
GridLayoutKind,
|
GridLayoutKind,
|
||||||
PanelKind,
|
PanelKind,
|
||||||
@@ -467,14 +466,10 @@ describe('ResponseTransformers', () => {
|
|||||||
{
|
{
|
||||||
kind: 'PanelQuery',
|
kind: 'PanelQuery',
|
||||||
spec: {
|
spec: {
|
||||||
|
datasource: 'datasource1',
|
||||||
hidden: false,
|
hidden: false,
|
||||||
query: {
|
query: {
|
||||||
kind: 'DataQuery',
|
kind: 'prometheus',
|
||||||
version: defaultDataQueryKind().version,
|
|
||||||
group: 'prometheus',
|
|
||||||
datasource: {
|
|
||||||
name: 'datasource1',
|
|
||||||
},
|
|
||||||
spec: {
|
spec: {
|
||||||
expr: 'test-query',
|
expr: 'test-query',
|
||||||
},
|
},
|
||||||
@@ -978,9 +973,11 @@ describe('ResponseTransformers', () => {
|
|||||||
|
|
||||||
result.forEach((query) => {
|
result.forEach((query) => {
|
||||||
expect(query.kind).toBe('PanelQuery');
|
expect(query.kind).toBe('PanelQuery');
|
||||||
expect(query.spec.query.group).toEqual('theoretical-ds');
|
expect(query.spec.datasource).toEqual({
|
||||||
expect(query.spec.query.datasource?.name).toEqual('theoretical-uid');
|
type: 'theoretical-ds',
|
||||||
expect(query.spec.query.kind).toBe('DataQuery');
|
uid: 'theoretical-uid',
|
||||||
|
});
|
||||||
|
expect(query.spec.query.kind).toBe('theoretical-ds');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -1006,9 +1003,11 @@ describe('ResponseTransformers', () => {
|
|||||||
|
|
||||||
result.forEach((query) => {
|
result.forEach((query) => {
|
||||||
expect(query.kind).toBe('PanelQuery');
|
expect(query.kind).toBe('PanelQuery');
|
||||||
expect(query.spec.query.group).toEqual('theoretical-ds');
|
expect(query.spec.datasource).toEqual({
|
||||||
expect(query.spec.query.datasource?.name).toEqual('theoretical-uid');
|
type: 'theoretical-ds',
|
||||||
expect(query.spec.query.kind).toBe('DataQuery');
|
uid: 'theoretical-uid',
|
||||||
|
});
|
||||||
|
expect(query.spec.query.kind).toBe('theoretical-ds');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -1016,14 +1015,14 @@ describe('ResponseTransformers', () => {
|
|||||||
|
|
||||||
function validateAnnotation(v1: AnnotationQuery, v2: DashboardV2Spec['annotations'][0]) {
|
function validateAnnotation(v1: AnnotationQuery, v2: DashboardV2Spec['annotations'][0]) {
|
||||||
const { spec: v2Spec } = v2;
|
const { spec: v2Spec } = v2;
|
||||||
|
|
||||||
expect(v1.name).toBe(v2Spec.name);
|
expect(v1.name).toBe(v2Spec.name);
|
||||||
expect(v1.datasource?.type).toBe(v2Spec.query.group);
|
expect(v1.datasource).toBe(v2Spec.datasource);
|
||||||
expect(v1.datasource?.uid).toBe(v2Spec.query.datasource?.name);
|
|
||||||
expect(v1.enable).toBe(v2Spec.enable);
|
expect(v1.enable).toBe(v2Spec.enable);
|
||||||
expect(v1.hide).toBe(v2Spec.hide);
|
expect(v1.hide).toBe(v2Spec.hide);
|
||||||
expect(v1.iconColor).toBe(v2Spec.iconColor);
|
expect(v1.iconColor).toBe(v2Spec.iconColor);
|
||||||
expect(v1.builtIn).toBe(v2Spec.builtIn ? 1 : undefined);
|
expect(v1.builtIn).toBe(v2Spec.builtIn ? 1 : 0);
|
||||||
expect(v1.target).toEqual(v2Spec.query.spec);
|
expect(v1.target).toBe(v2Spec.query?.spec);
|
||||||
expect(v1.filter).toEqual(v2Spec.filter);
|
expect(v1.filter).toEqual(v2Spec.filter);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1044,10 +1043,7 @@ describe('ResponseTransformers', () => {
|
|||||||
return {
|
return {
|
||||||
refId: q.spec.refId,
|
refId: q.spec.refId,
|
||||||
hide: q.spec.hidden,
|
hide: q.spec.hidden,
|
||||||
datasource: {
|
datasource: q.spec.datasource,
|
||||||
type: q.spec.query.spec.group,
|
|
||||||
uid: q.spec.query.spec.datasource?.uid,
|
|
||||||
},
|
|
||||||
...q.spec.query.spec,
|
...q.spec.query.spec,
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
@@ -1097,24 +1093,18 @@ describe('ResponseTransformers', () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
expect(v2Common).toEqual(v1Common);
|
expect(v2Common).toEqual(v1Common);
|
||||||
|
|
||||||
if (v2.kind === 'QueryVariable') {
|
if (v2.kind === 'QueryVariable') {
|
||||||
expect(v2.spec.query).toMatchObject({
|
expect(v2.spec.datasource).toEqual(v1.datasource);
|
||||||
kind: 'DataQuery',
|
|
||||||
version: defaultDataQueryKind().version,
|
|
||||||
group: (v1.datasource?.type || getDefaultDataSourceRef()?.type) ?? 'grafana',
|
|
||||||
...(v1.datasource?.uid && {
|
|
||||||
datasource: {
|
|
||||||
name: v1.datasource?.uid,
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
if (typeof v1.query === 'string') {
|
if (typeof v1.query === 'string') {
|
||||||
expect(v2.spec.query.spec).toEqual({
|
expect(v2.spec.query.spec[LEGACY_STRING_VALUE_KEY]).toEqual(v1.query);
|
||||||
[LEGACY_STRING_VALUE_KEY]: v1.query,
|
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
expect(v2.spec.query.spec).toEqual({
|
expect(v2.spec.query).toEqual({
|
||||||
...(typeof v1.query === 'object' ? v1.query : {}),
|
kind: v1.datasource?.type,
|
||||||
|
spec: {
|
||||||
|
...(typeof v1.query === 'object' ? v1.query : {}),
|
||||||
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,7 +38,6 @@ import {
|
|||||||
LibraryPanelKind,
|
LibraryPanelKind,
|
||||||
PanelKind,
|
PanelKind,
|
||||||
GridLayoutItemKind,
|
GridLayoutItemKind,
|
||||||
defaultDataQueryKind,
|
|
||||||
RowsLayoutRowKind,
|
RowsLayoutRowKind,
|
||||||
GridLayoutKind,
|
GridLayoutKind,
|
||||||
} from '@grafana/schema/dist/esm/schema/dashboard/v2alpha1/types.spec.gen';
|
} from '@grafana/schema/dist/esm/schema/dashboard/v2alpha1/types.spec.gen';
|
||||||
@@ -56,7 +55,6 @@ import {
|
|||||||
DeprecatedInternalId,
|
DeprecatedInternalId,
|
||||||
ObjectMeta,
|
ObjectMeta,
|
||||||
} from 'app/features/apiserver/types';
|
} from 'app/features/apiserver/types';
|
||||||
import { transformV2ToV1AnnotationQuery } from 'app/features/dashboard-scene/serialization/annotations';
|
|
||||||
import { GRID_ROW_HEIGHT } from 'app/features/dashboard-scene/serialization/const';
|
import { GRID_ROW_HEIGHT } from 'app/features/dashboard-scene/serialization/const';
|
||||||
import { validateFiltersOrigin } from 'app/features/dashboard-scene/serialization/sceneVariablesSetToVariables';
|
import { validateFiltersOrigin } from 'app/features/dashboard-scene/serialization/sceneVariablesSetToVariables';
|
||||||
import { TypedVariableModelV2 } from 'app/features/dashboard-scene/serialization/transformSaveModelSchemaV2ToScene';
|
import { TypedVariableModelV2 } from 'app/features/dashboard-scene/serialization/transformSaveModelSchemaV2ToScene';
|
||||||
@@ -504,13 +502,9 @@ export function getPanelQueries(targets: DataQuery[], panelDatasource: DataSourc
|
|||||||
spec: {
|
spec: {
|
||||||
refId: t.refId,
|
refId: t.refId,
|
||||||
hidden: t.hide ?? false,
|
hidden: t.hide ?? false,
|
||||||
|
datasource: t.datasource ? t.datasource : panelDatasource,
|
||||||
query: {
|
query: {
|
||||||
kind: 'DataQuery',
|
kind: t.datasource?.type || panelDatasource.type!,
|
||||||
version: defaultDataQueryKind().version,
|
|
||||||
group: t.datasource?.type || panelDatasource.type!,
|
|
||||||
datasource: {
|
|
||||||
name: t.datasource?.uid || panelDatasource.uid!,
|
|
||||||
},
|
|
||||||
spec: {
|
spec: {
|
||||||
...query,
|
...query,
|
||||||
},
|
},
|
||||||
@@ -574,12 +568,7 @@ function getVariables(vars: TypedVariableModel[]): DashboardV2Spec['variables']
|
|||||||
regex: v.regex || '',
|
regex: v.regex || '',
|
||||||
sort: transformSortVariableToEnum(v.sort),
|
sort: transformSortVariableToEnum(v.sort),
|
||||||
query: {
|
query: {
|
||||||
kind: 'DataQuery',
|
kind: v.datasource?.type || getDefaultDatasourceType(),
|
||||||
version: defaultDataQueryKind().version,
|
|
||||||
group: v.datasource?.type ?? getDefaultDatasourceType(),
|
|
||||||
datasource: {
|
|
||||||
name: v.datasource?.uid,
|
|
||||||
},
|
|
||||||
spec: query,
|
spec: query,
|
||||||
},
|
},
|
||||||
allowCustomValue: v.allowCustomValue ?? true,
|
allowCustomValue: v.allowCustomValue ?? true,
|
||||||
@@ -733,12 +722,7 @@ function getAnnotations(annotations: AnnotationQuery[]): DashboardV2Spec['annota
|
|||||||
iconColor: a.iconColor,
|
iconColor: a.iconColor,
|
||||||
builtIn: Boolean(a.builtIn),
|
builtIn: Boolean(a.builtIn),
|
||||||
query: {
|
query: {
|
||||||
kind: 'DataQuery',
|
kind: a.datasource?.type || getDefaultDatasourceType(),
|
||||||
version: defaultDataQueryKind().version,
|
|
||||||
group: a.datasource?.type || getDefaultDatasourceType(),
|
|
||||||
datasource: {
|
|
||||||
name: a.datasource?.uid,
|
|
||||||
},
|
|
||||||
spec: {
|
spec: {
|
||||||
...a.target,
|
...a.target,
|
||||||
},
|
},
|
||||||
@@ -773,10 +757,7 @@ function getVariablesV1(vars: DashboardV2Spec['variables']): VariableModel[] {
|
|||||||
LEGACY_STRING_VALUE_KEY in v.spec.query.spec
|
LEGACY_STRING_VALUE_KEY in v.spec.query.spec
|
||||||
? v.spec.query.spec[LEGACY_STRING_VALUE_KEY]
|
? v.spec.query.spec[LEGACY_STRING_VALUE_KEY]
|
||||||
: v.spec.query.spec,
|
: v.spec.query.spec,
|
||||||
datasource: {
|
datasource: v.spec.datasource,
|
||||||
type: v.spec.query?.spec.group,
|
|
||||||
uid: v.spec.query?.spec.datasource?.name,
|
|
||||||
},
|
|
||||||
sort: transformSortVariableToEnumV1(v.spec.sort),
|
sort: transformSortVariableToEnumV1(v.spec.sort),
|
||||||
refresh: transformVariableRefreshToEnumV1(v.spec.refresh),
|
refresh: transformVariableRefreshToEnumV1(v.spec.refresh),
|
||||||
regex: v.spec.regex,
|
regex: v.spec.regex,
|
||||||
@@ -893,6 +874,22 @@ function getVariablesV1(vars: DashboardV2Spec['variables']): VariableModel[] {
|
|||||||
return variables;
|
return variables;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getAnnotationsV1(annotations: DashboardV2Spec['annotations']): AnnotationQuery[] {
|
||||||
|
// @ts-expect-error - target v2 query is not compatible with v1 target
|
||||||
|
return annotations.map((a) => {
|
||||||
|
return {
|
||||||
|
name: a.spec.name,
|
||||||
|
datasource: a.spec.datasource,
|
||||||
|
enable: a.spec.enable,
|
||||||
|
hide: a.spec.hide,
|
||||||
|
iconColor: a.spec.iconColor,
|
||||||
|
builtIn: a.spec.builtIn ? 1 : 0,
|
||||||
|
target: a.spec.query?.spec,
|
||||||
|
filter: a.spec.filter,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
interface LibraryPanelDTO extends Pick<Panel, 'libraryPanel' | 'id' | 'title' | 'gridPos' | 'type'> {}
|
interface LibraryPanelDTO extends Pick<Panel, 'libraryPanel' | 'id' | 'title' | 'gridPos' | 'type'> {}
|
||||||
|
|
||||||
function getPanelsV1(
|
function getPanelsV1(
|
||||||
@@ -953,10 +950,7 @@ function transformV2PanelToV1Panel(
|
|||||||
return {
|
return {
|
||||||
refId: q.spec.refId,
|
refId: q.spec.refId,
|
||||||
hide: q.spec.hidden,
|
hide: q.spec.hidden,
|
||||||
datasource: {
|
datasource: q.spec.datasource,
|
||||||
uid: q.spec.query.spec.datasource?.uid,
|
|
||||||
type: q.spec.query.spec.group,
|
|
||||||
},
|
|
||||||
...q.spec.query.spec,
|
...q.spec.query.spec,
|
||||||
};
|
};
|
||||||
}),
|
}),
|
||||||
@@ -1140,8 +1134,7 @@ function transformToV1VariableTypes(variable: TypedVariableModelV2): VariableTyp
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function transformDashboardV2SpecToV1(spec: DashboardV2Spec, metadata: ObjectMeta): DashboardDataDTO {
|
export function transformDashboardV2SpecToV1(spec: DashboardV2Spec, metadata: ObjectMeta): DashboardDataDTO {
|
||||||
const annotations = spec.annotations.map(transformV2ToV1AnnotationQuery);
|
const annotations = getAnnotationsV1(spec.annotations);
|
||||||
|
|
||||||
const variables = getVariablesV1(spec.variables);
|
const variables = getVariablesV1(spec.variables);
|
||||||
const panels = getPanelsV1(spec.elements, spec.layout);
|
const panels = getPanelsV1(spec.elements, spec.layout);
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -154,6 +154,7 @@ export const InfiniteScroll = ({
|
|||||||
displayedFields={displayedFields}
|
displayedFields={displayedFields}
|
||||||
index={index}
|
index={index}
|
||||||
log={logs[index]}
|
log={logs[index]}
|
||||||
|
logs={logs}
|
||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
showTime={showTime}
|
showTime={showTime}
|
||||||
style={style}
|
style={style}
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ describe.each(fontSizes)('LogLine', (fontSize: LogListFontSize) => {
|
|||||||
displayedFields: [],
|
displayedFields: [],
|
||||||
index: 0,
|
index: 0,
|
||||||
log,
|
log,
|
||||||
|
logs: [log],
|
||||||
onClick: jest.fn(),
|
onClick: jest.fn(),
|
||||||
showTime: true,
|
showTime: true,
|
||||||
style: {},
|
style: {},
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ export interface Props {
|
|||||||
displayedFields: string[];
|
displayedFields: string[];
|
||||||
index: number;
|
index: number;
|
||||||
log: LogListModel;
|
log: LogListModel;
|
||||||
|
logs: LogListModel[];
|
||||||
showTime: boolean;
|
showTime: boolean;
|
||||||
style: CSSProperties;
|
style: CSSProperties;
|
||||||
styles: LogLineStyles;
|
styles: LogLineStyles;
|
||||||
@@ -41,6 +42,7 @@ export const LogLine = ({
|
|||||||
displayedFields,
|
displayedFields,
|
||||||
index,
|
index,
|
||||||
log,
|
log,
|
||||||
|
logs,
|
||||||
style,
|
style,
|
||||||
styles,
|
styles,
|
||||||
onClick,
|
onClick,
|
||||||
@@ -57,6 +59,7 @@ export const LogLine = ({
|
|||||||
height={style.height}
|
height={style.height}
|
||||||
index={index}
|
index={index}
|
||||||
log={log}
|
log={log}
|
||||||
|
logs={logs}
|
||||||
styles={styles}
|
styles={styles}
|
||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
onOverflow={onOverflow}
|
onOverflow={onOverflow}
|
||||||
@@ -79,6 +82,7 @@ const LogLineComponent = memo(
|
|||||||
height,
|
height,
|
||||||
index,
|
index,
|
||||||
log,
|
log,
|
||||||
|
logs,
|
||||||
styles,
|
styles,
|
||||||
onClick,
|
onClick,
|
||||||
onOverflow,
|
onOverflow,
|
||||||
@@ -237,7 +241,7 @@ const LogLineComponent = memo(
|
|||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{detailsMode === 'inline' && detailsShown && <InlineLogLineDetails logs={[]} />}
|
{detailsMode === 'inline' && detailsShown && <InlineLogLineDetails logs={logs} />}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import { createLogLineLinks } from '../logParser';
|
|||||||
import { LogLineDetailsDisplayedFields } from './LogLineDetailsDisplayedFields';
|
import { LogLineDetailsDisplayedFields } from './LogLineDetailsDisplayedFields';
|
||||||
import { LabelWithLinks, LogLineDetailsFields, LogLineDetailsLabelFields } from './LogLineDetailsFields';
|
import { LabelWithLinks, LogLineDetailsFields, LogLineDetailsLabelFields } from './LogLineDetailsFields';
|
||||||
import { LogLineDetailsHeader } from './LogLineDetailsHeader';
|
import { LogLineDetailsHeader } from './LogLineDetailsHeader';
|
||||||
|
import { LogLineDetailsLog } from './LogLineDetailsLog';
|
||||||
import { useLogListContext } from './LogListContext';
|
import { useLogListContext } from './LogListContext';
|
||||||
import { LogListModel } from './processing';
|
import { LogListModel } from './processing';
|
||||||
|
|
||||||
@@ -102,7 +103,7 @@ export const LogLineDetailsComponent = ({ log, logs }: LogLineDetailsComponentPr
|
|||||||
isOpen={logLineOpen}
|
isOpen={logLineOpen}
|
||||||
onToggle={(isOpen: boolean) => handleToggle('logLineOpen', isOpen)}
|
onToggle={(isOpen: boolean) => handleToggle('logLineOpen', isOpen)}
|
||||||
>
|
>
|
||||||
<div className={styles.logLineWrapper}>{log.raw}</div>
|
<LogLineDetailsLog log={log} />
|
||||||
</ControlledCollapse>
|
</ControlledCollapse>
|
||||||
{displayedFields.length > 0 && setDisplayedFields && (
|
{displayedFields.length > 0 && setDisplayedFields && (
|
||||||
<ControlledCollapse
|
<ControlledCollapse
|
||||||
@@ -189,8 +190,4 @@ const getStyles = (theme: GrafanaTheme2) => ({
|
|||||||
componentWrapper: css({
|
componentWrapper: css({
|
||||||
padding: theme.spacing(0, 1, 1, 1),
|
padding: theme.spacing(0, 1, 1, 1),
|
||||||
}),
|
}),
|
||||||
logLineWrapper: css({
|
|
||||||
maxHeight: '50vh',
|
|
||||||
overflow: 'auto',
|
|
||||||
}),
|
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -0,0 +1,44 @@
|
|||||||
|
import { css } from '@emotion/css';
|
||||||
|
import { memo, useMemo } from 'react';
|
||||||
|
|
||||||
|
import { useStyles2 } from '@grafana/ui';
|
||||||
|
|
||||||
|
import { getStyles } from './LogLine';
|
||||||
|
import { useLogListContext } from './LogListContext';
|
||||||
|
import { LogListModel } from './processing';
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
log: LogListModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const LogLineDetailsLog = memo(({ log: originalLog }: Props) => {
|
||||||
|
const { syntaxHighlighting } = useLogListContext();
|
||||||
|
const logStyles = useStyles2(getStyles);
|
||||||
|
const log = useMemo(() => {
|
||||||
|
const log = originalLog.clone();
|
||||||
|
return log;
|
||||||
|
}, [originalLog]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={styles.logLineWrapper}>
|
||||||
|
{!syntaxHighlighting ? (
|
||||||
|
<div className="field no-highlighting">{log.body}</div>
|
||||||
|
) : (
|
||||||
|
<div className={logStyles.logLine}>
|
||||||
|
<div className={logStyles.wrappedLogLine}>
|
||||||
|
<div className="field log-syntax-highlight" dangerouslySetInnerHTML={{ __html: log.highlightedBody }} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
LogLineDetailsLog.displayName = 'LogLineDetailsLog';
|
||||||
|
|
||||||
|
const styles = {
|
||||||
|
logLineWrapper: css({
|
||||||
|
maxHeight: '50vh',
|
||||||
|
overflow: 'auto',
|
||||||
|
}),
|
||||||
|
};
|
||||||
@@ -140,6 +140,36 @@ describe('preProcessLogs', () => {
|
|||||||
);
|
);
|
||||||
expect(logListModel.getDisplayedFieldValue(LOG_LINE_BODY_FIELD_NAME, true)).toBe('log message 1');
|
expect(logListModel.getDisplayedFieldValue(LOG_LINE_BODY_FIELD_NAME, true)).toBe('log message 1');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('Prettifies JSON', () => {
|
||||||
|
const entry = '{"key": "value", "otherKey": "otherValue"}';
|
||||||
|
const logListModel = createLogLine(
|
||||||
|
{ entry },
|
||||||
|
{
|
||||||
|
escape: false,
|
||||||
|
order: LogsSortOrder.Descending,
|
||||||
|
timeZone: 'browser',
|
||||||
|
wrapLogMessage: false, // unwrapped
|
||||||
|
}
|
||||||
|
);
|
||||||
|
expect(logListModel.entry).toBe(entry);
|
||||||
|
expect(logListModel.body).not.toBe(entry);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Uses lossless parsing', () => {
|
||||||
|
const entry = '{"number": 90071992547409911}';
|
||||||
|
const logListModel = createLogLine(
|
||||||
|
{ entry },
|
||||||
|
{
|
||||||
|
escape: false,
|
||||||
|
order: LogsSortOrder.Descending,
|
||||||
|
timeZone: 'browser',
|
||||||
|
wrapLogMessage: false, // unwrapped
|
||||||
|
}
|
||||||
|
);
|
||||||
|
expect(logListModel.entry).toBe(entry);
|
||||||
|
expect(logListModel.body).toContain('90071992547409911');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Orders logs', () => {
|
test('Orders logs', () => {
|
||||||
@@ -243,6 +273,35 @@ describe('preProcessLogs', () => {
|
|||||||
expect(entry).toContain(longLog.body);
|
expect(entry).toContain(longLog.body);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('Sets the collapsed state based on the new lines count', () => {
|
||||||
|
const entry = new Array(virtualization.getTruncationLineCount()).fill('test\n').join('');
|
||||||
|
const multilineLog = createLogLine(
|
||||||
|
{ entry, labels: { field: 'value' } },
|
||||||
|
{ escape: false, order: LogsSortOrder.Descending, timeZone: 'browser', virtualization, wrapLogMessage: true }
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(multilineLog.collapsed).toBeUndefined();
|
||||||
|
|
||||||
|
multilineLog.updateCollapsedState([], container);
|
||||||
|
|
||||||
|
expect(multilineLog.collapsed).toBe(true);
|
||||||
|
expect(entry).toContain(multilineLog.body);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Correctly counts new lines', () => {
|
||||||
|
const entry = new Array(virtualization.getTruncationLineCount() - 1).fill('test\n').join('');
|
||||||
|
const multilineLog = createLogLine(
|
||||||
|
{ entry, labels: { field: 'value' } },
|
||||||
|
{ escape: false, order: LogsSortOrder.Descending, timeZone: 'browser', virtualization, wrapLogMessage: true }
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(multilineLog.collapsed).toBeUndefined();
|
||||||
|
|
||||||
|
multilineLog.updateCollapsedState([], container);
|
||||||
|
|
||||||
|
expect(multilineLog.collapsed).toBeUndefined();
|
||||||
|
});
|
||||||
|
|
||||||
test('Considers the displayed fields to set the collapsed state', () => {
|
test('Considers the displayed fields to set the collapsed state', () => {
|
||||||
// Make container half of the size
|
// Make container half of the size
|
||||||
jest.spyOn(container, 'clientWidth', 'get').mockReturnValue(100);
|
jest.spyOn(container, 'clientWidth', 'get').mockReturnValue(100);
|
||||||
@@ -255,6 +314,22 @@ describe('preProcessLogs', () => {
|
|||||||
expect(longLog.collapsed).toBeUndefined();
|
expect(longLog.collapsed).toBeUndefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('Considers new lines in displayed fields to set the collapsed state', () => {
|
||||||
|
const entry = new Array(virtualization.getTruncationLineCount() - 1).fill('test\n').join('');
|
||||||
|
const field = 'test\n';
|
||||||
|
const multilineLog = createLogLine(
|
||||||
|
{ entry, labels: { field } },
|
||||||
|
{ escape: false, order: LogsSortOrder.Descending, timeZone: 'browser', virtualization, wrapLogMessage: true }
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(multilineLog.collapsed).toBeUndefined();
|
||||||
|
|
||||||
|
multilineLog.updateCollapsedState(['field', LOG_LINE_BODY_FIELD_NAME], container);
|
||||||
|
|
||||||
|
expect(multilineLog.collapsed).toBe(true);
|
||||||
|
expect(entry).toContain(multilineLog.body);
|
||||||
|
});
|
||||||
|
|
||||||
test('Updates the body based on the collapsed state', () => {
|
test('Updates the body based on the collapsed state', () => {
|
||||||
expect(longLog.collapsed).toBeUndefined();
|
expect(longLog.collapsed).toBeUndefined();
|
||||||
expect(longLog.body).toBe(entry);
|
expect(longLog.body).toBe(entry);
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
import ansicolor from 'ansicolor';
|
import ansicolor from 'ansicolor';
|
||||||
|
import { parse, stringify } from 'lossless-json';
|
||||||
import Prism, { Grammar } from 'prismjs';
|
import Prism, { Grammar } from 'prismjs';
|
||||||
|
|
||||||
import { DataFrame, dateTimeFormat, Labels, LogLevel, LogRowModel, LogsSortOrder } from '@grafana/data';
|
import { DataFrame, dateTimeFormat, Labels, LogLevel, LogRowModel, LogsSortOrder, textUtil } from '@grafana/data';
|
||||||
import { GetFieldLinksFn } from 'app/plugins/panel/logs/types';
|
import { GetFieldLinksFn } from 'app/plugins/panel/logs/types';
|
||||||
|
|
||||||
import { checkLogsError, checkLogsSampled, escapeUnescapedString, sortLogRows } from '../../utils';
|
import { checkLogsError, checkLogsSampled, escapeUnescapedString, sortLogRows } from '../../utils';
|
||||||
@@ -97,8 +98,23 @@ export class LogListModel implements LogRowModel {
|
|||||||
this.raw = raw;
|
this.raw = raw;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
clone() {
|
||||||
|
const clone = Object.assign(Object.create(Object.getPrototypeOf(this)), this);
|
||||||
|
// Unless this function is required outside of <LogLineDetailsLog />, we create a wrapped clone, so new lines are not stripped.
|
||||||
|
clone._wrapLogMessage = true;
|
||||||
|
clone._body = undefined;
|
||||||
|
clone._highlightedBody = undefined;
|
||||||
|
return clone;
|
||||||
|
}
|
||||||
|
|
||||||
get body(): string {
|
get body(): string {
|
||||||
if (this._body === undefined) {
|
if (this._body === undefined) {
|
||||||
|
try {
|
||||||
|
const parsed = stringify(parse(this.raw), undefined, 2);
|
||||||
|
if (parsed) {
|
||||||
|
this.raw = parsed;
|
||||||
|
}
|
||||||
|
} catch (error) {}
|
||||||
this._body = this.collapsed
|
this._body = this.collapsed
|
||||||
? this.raw.substring(0, this._virtualization?.getTruncationLength(null) ?? TRUNCATION_DEFAULT_LENGTH)
|
? this.raw.substring(0, this._virtualization?.getTruncationLength(null) ?? TRUNCATION_DEFAULT_LENGTH)
|
||||||
: this.raw;
|
: this.raw;
|
||||||
@@ -124,7 +140,11 @@ export class LogListModel implements LogRowModel {
|
|||||||
if (this._highlightedBody === undefined) {
|
if (this._highlightedBody === undefined) {
|
||||||
this._grammar = this._grammar ?? generateLogGrammar(this);
|
this._grammar = this._grammar ?? generateLogGrammar(this);
|
||||||
const extraGrammar = generateTextMatchGrammar(this.searchWords, this._currentSearch);
|
const extraGrammar = generateTextMatchGrammar(this.searchWords, this._currentSearch);
|
||||||
this._highlightedBody = Prism.highlight(this.body, { ...extraGrammar, ...this._grammar }, 'lokiql');
|
this._highlightedBody = Prism.highlight(
|
||||||
|
textUtil.sanitize(this.body),
|
||||||
|
{ ...extraGrammar, ...this._grammar },
|
||||||
|
'lokiql'
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return this._highlightedBody;
|
return this._highlightedBody;
|
||||||
}
|
}
|
||||||
@@ -154,16 +174,27 @@ export class LogListModel implements LogRowModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
updateCollapsedState(displayedFields: string[], container: HTMLDivElement | null) {
|
updateCollapsedState(displayedFields: string[], container: HTMLDivElement | null) {
|
||||||
const lineLength =
|
const line =
|
||||||
displayedFields.length > 0
|
displayedFields.length > 0
|
||||||
? displayedFields.map((field) => this.getDisplayedFieldValue(field, true)).join('').length
|
? displayedFields.map((field) => this.getDisplayedFieldValue(field, true)).join('')
|
||||||
: this.entry.length;
|
: this.body;
|
||||||
const collapsed =
|
|
||||||
lineLength >= (this._virtualization?.getTruncationLength(container) ?? TRUNCATION_DEFAULT_LENGTH)
|
// Length truncation
|
||||||
|
let collapsed =
|
||||||
|
line.length >= (this._virtualization?.getTruncationLength(container) ?? TRUNCATION_DEFAULT_LENGTH)
|
||||||
? true
|
? true
|
||||||
: undefined;
|
: undefined;
|
||||||
|
|
||||||
|
// Newlines truncation
|
||||||
|
if (!collapsed && this._virtualization) {
|
||||||
|
const truncationLimit = this._virtualization.getTruncationLineCount();
|
||||||
|
collapsed = countNewLines(line, truncationLimit) >= truncationLimit ? true : collapsed;
|
||||||
|
}
|
||||||
|
|
||||||
if (this.collapsed === undefined || collapsed === undefined) {
|
if (this.collapsed === undefined || collapsed === undefined) {
|
||||||
this.collapsed = collapsed;
|
this.collapsed = collapsed;
|
||||||
|
this._body = undefined;
|
||||||
|
this._highlightedBody = undefined;
|
||||||
}
|
}
|
||||||
return this.collapsed;
|
return this.collapsed;
|
||||||
}
|
}
|
||||||
@@ -226,3 +257,23 @@ function logLevelToDisplayLevel(level = '') {
|
|||||||
return level;
|
return level;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function countNewLines(log: string, limit = Infinity) {
|
||||||
|
let count = 0;
|
||||||
|
for (let i = 0; i < log.length; ++i) {
|
||||||
|
// No need to iterate further
|
||||||
|
if (count > Infinity) {
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
if (log[i] === '\n') {
|
||||||
|
count += 1;
|
||||||
|
} else if (log[i] === '\r') {
|
||||||
|
count += 1;
|
||||||
|
// skip LF in CRLF
|
||||||
|
if (log[i] === '\n') {
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|||||||
@@ -55,7 +55,6 @@ export class LogLineVirtualization {
|
|||||||
getGridSize = () => this.gridSize;
|
getGridSize = () => this.gridSize;
|
||||||
getPaddingBottom = () => this.paddingBottom;
|
getPaddingBottom = () => this.paddingBottom;
|
||||||
|
|
||||||
// 2/3 of the viewport height
|
|
||||||
getTruncationLineCount = () => Math.round(window.innerHeight / this.getLineHeight() / 1.5);
|
getTruncationLineCount = () => Math.round(window.innerHeight / this.getLineHeight() / 1.5);
|
||||||
|
|
||||||
getTruncationLength = (container: HTMLDivElement | null) => {
|
getTruncationLength = (container: HTMLDivElement | null) => {
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import {
|
|||||||
defaultSpec as defaultDashboardV2Spec,
|
defaultSpec as defaultDashboardV2Spec,
|
||||||
defaultPanelSpec,
|
defaultPanelSpec,
|
||||||
defaultQueryVariableSpec,
|
defaultQueryVariableSpec,
|
||||||
defaultDataQueryKind,
|
|
||||||
} from '@grafana/schema/dist/esm/schema/dashboard/v2alpha1/types.spec.gen';
|
} from '@grafana/schema/dist/esm/schema/dashboard/v2alpha1/types.spec.gen';
|
||||||
import { browseDashboardsAPI } from 'app/features/browse-dashboards/api/browseDashboardsAPI';
|
import { browseDashboardsAPI } from 'app/features/browse-dashboards/api/browseDashboardsAPI';
|
||||||
import { getLibraryPanel } from 'app/features/library-panels/state/api';
|
import { getLibraryPanel } from 'app/features/library-panels/state/api';
|
||||||
@@ -837,9 +836,7 @@ describe('processV2Datasources', () => {
|
|||||||
refId: 'A',
|
refId: 'A',
|
||||||
hidden: false,
|
hidden: false,
|
||||||
query: {
|
query: {
|
||||||
kind: 'DataQuery',
|
kind: 'prometheus',
|
||||||
version: defaultDataQueryKind().version,
|
|
||||||
group: 'prometheus',
|
|
||||||
spec: {
|
spec: {
|
||||||
expr: 'access_evaluation_duration_count',
|
expr: 'access_evaluation_duration_count',
|
||||||
range: true,
|
range: true,
|
||||||
@@ -865,9 +862,7 @@ describe('processV2Datasources', () => {
|
|||||||
...defaultQueryVariableSpec(),
|
...defaultQueryVariableSpec(),
|
||||||
name: 'var1',
|
name: 'var1',
|
||||||
query: {
|
query: {
|
||||||
kind: 'DataQuery',
|
kind: 'loki',
|
||||||
version: defaultDataQueryKind().version,
|
|
||||||
group: 'loki',
|
|
||||||
spec: {
|
spec: {
|
||||||
expr: 'access_evaluation_duration_count',
|
expr: 'access_evaluation_duration_count',
|
||||||
range: true,
|
range: true,
|
||||||
@@ -885,9 +880,7 @@ describe('processV2Datasources', () => {
|
|||||||
hide: false,
|
hide: false,
|
||||||
iconColor: 'red',
|
iconColor: 'red',
|
||||||
query: {
|
query: {
|
||||||
kind: 'DataQuery',
|
kind: 'loki',
|
||||||
version: defaultDataQueryKind().version,
|
|
||||||
group: 'loki',
|
|
||||||
spec: {
|
spec: {
|
||||||
expr: 'access_evaluation_duration_count',
|
expr: 'access_evaluation_duration_count',
|
||||||
range: true,
|
range: true,
|
||||||
@@ -989,17 +982,13 @@ describe('processV2DatasourceInput', () => {
|
|||||||
...defaultQueryVariableSpec(),
|
...defaultQueryVariableSpec(),
|
||||||
name: 'var2WithGrafanaDs',
|
name: 'var2WithGrafanaDs',
|
||||||
query: {
|
query: {
|
||||||
kind: 'DataQuery' as const,
|
kind: 'grafana',
|
||||||
version: defaultDataQueryKind().version,
|
|
||||||
group: 'grafana',
|
|
||||||
spec: {
|
spec: {
|
||||||
expr: 'access_evaluation_duration_count',
|
panelId: 2,
|
||||||
range: true,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const result = await processV2DatasourceInput(queryVariable.spec, {});
|
const result = await processV2DatasourceInput(queryVariable.spec, {});
|
||||||
expect(result).toEqual({});
|
expect(result).toEqual({});
|
||||||
});
|
});
|
||||||
@@ -1012,9 +1001,7 @@ describe('processV2DatasourceInput', () => {
|
|||||||
refId: 'A',
|
refId: 'A',
|
||||||
hidden: false,
|
hidden: false,
|
||||||
query: {
|
query: {
|
||||||
kind: 'DataQuery' as const,
|
kind: 'datasource',
|
||||||
version: defaultDataQueryKind().version,
|
|
||||||
group: 'datasource',
|
|
||||||
spec: {
|
spec: {
|
||||||
panelId: 2,
|
panelId: 2,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -168,7 +168,6 @@ export function processV2Datasources(dashboard: DashboardV2Spec): ThunkResult<vo
|
|||||||
if (element.kind !== 'Panel') {
|
if (element.kind !== 'Panel') {
|
||||||
throw new Error('Only panels are currenlty supported in v2 dashboards');
|
throw new Error('Only panels are currenlty supported in v2 dashboards');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (element.spec.data.spec.queries.length > 0) {
|
if (element.spec.data.spec.queries.length > 0) {
|
||||||
for (const query of element.spec.data.spec.queries) {
|
for (const query of element.spec.data.spec.queries) {
|
||||||
inputs = await processV2DatasourceInput(query.spec, inputs);
|
inputs = await processV2DatasourceInput(query.spec, inputs);
|
||||||
@@ -333,43 +332,43 @@ export function getFolderByUid(uid: string): Promise<{ uid: string; title: strin
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function processV2DatasourceInput(
|
export async function processV2DatasourceInput(
|
||||||
spec: PanelQueryKind['spec'] | QueryVariableKind['spec'] | AnnotationQueryKind['spec'],
|
obj: PanelQueryKind['spec'] | QueryVariableKind['spec'] | AnnotationQueryKind['spec'],
|
||||||
inputs: Record<string, DataSourceInput> = {}
|
inputs: Record<string, DataSourceInput> = {}
|
||||||
) {
|
) {
|
||||||
const datasourceRef = spec.query.datasource;
|
const datasourceRef = obj?.datasource;
|
||||||
let dataSourceInput: DataSourceInput | undefined;
|
if (!datasourceRef && obj?.query) {
|
||||||
const dsType = spec.query.group;
|
const dsType = obj.query.kind;
|
||||||
|
|
||||||
if (!datasourceRef) {
|
|
||||||
// if dsType is grafana, it means we are using a built-in annotation or default grafana datasource, in those
|
// if dsType is grafana, it means we are using a built-in annotation or default grafana datasource, in those
|
||||||
// cases we don't need to map it
|
// cases we don't need to map it
|
||||||
// "datasource" type is what we call "--Dashboard--" datasource <.-.>
|
// "datasource" type is what we call "--Dashboard--" datasource <.-.>
|
||||||
if (dsType === 'grafana' || dsType === 'datasource') {
|
if (dsType === 'grafana' || dsType === 'datasource') {
|
||||||
return inputs;
|
return inputs;
|
||||||
}
|
}
|
||||||
}
|
const datasource = await getDatasourceSrv().get({ type: dsType });
|
||||||
|
let dataSourceInput: DataSourceInput | undefined;
|
||||||
|
if (datasource) {
|
||||||
|
dataSourceInput = {
|
||||||
|
name: datasource.name,
|
||||||
|
label: datasource.name,
|
||||||
|
info: `Select a ${datasource.name} data source`,
|
||||||
|
value: datasource.uid,
|
||||||
|
type: InputType.DataSource,
|
||||||
|
pluginId: datasource.meta?.id,
|
||||||
|
};
|
||||||
|
|
||||||
const datasource = await getDatasourceSrv().get({ type: dsType });
|
inputs[datasource.meta?.id] = dataSourceInput;
|
||||||
if (datasource) {
|
} else {
|
||||||
dataSourceInput = {
|
dataSourceInput = {
|
||||||
name: datasource.name,
|
name: dsType,
|
||||||
label: datasource.name,
|
label: dsType,
|
||||||
info: `Select a ${datasource.name} data source`,
|
info: `No data sources of type ${dsType} found`,
|
||||||
value: datasource.uid,
|
value: '',
|
||||||
type: InputType.DataSource,
|
type: InputType.DataSource,
|
||||||
pluginId: datasource.meta?.id,
|
pluginId: dsType,
|
||||||
};
|
};
|
||||||
inputs[datasource.meta?.id] = dataSourceInput;
|
|
||||||
} else {
|
inputs[dsType] = dataSourceInput;
|
||||||
dataSourceInput = {
|
}
|
||||||
name: dsType,
|
|
||||||
label: dsType,
|
|
||||||
info: `No data sources of type ${dsType} found`,
|
|
||||||
value: '',
|
|
||||||
type: InputType.DataSource,
|
|
||||||
pluginId: dsType,
|
|
||||||
};
|
|
||||||
inputs[dsType] = dataSourceInput;
|
|
||||||
}
|
}
|
||||||
return inputs;
|
return inputs;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18355,6 +18355,7 @@ __metadata:
|
|||||||
leven: "npm:^4.0.0"
|
leven: "npm:^4.0.0"
|
||||||
lodash: "npm:4.17.21"
|
lodash: "npm:4.17.21"
|
||||||
logfmt: "npm:^1.3.2"
|
logfmt: "npm:^1.3.2"
|
||||||
|
lossless-json: "npm:^4.1.1"
|
||||||
lru-cache: "npm:11.1.0"
|
lru-cache: "npm:11.1.0"
|
||||||
lru-memoize: "npm:^1.1.0"
|
lru-memoize: "npm:^1.1.0"
|
||||||
lucene: "npm:^2.1.1"
|
lucene: "npm:^2.1.1"
|
||||||
@@ -22160,6 +22161,13 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"lossless-json@npm:^4.1.1":
|
||||||
|
version: 4.1.1
|
||||||
|
resolution: "lossless-json@npm:4.1.1"
|
||||||
|
checksum: 10/1e22e9e4ad8ebf169567a8c24553403bfd7abc33c141f4918f1b9626417f80477b849e6175a315a224e0c68072759c69a0e332a925de80269a7f9720af3a7fbd
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"loupe@npm:^3.1.0, loupe@npm:^3.1.1, loupe@npm:^3.1.2":
|
"loupe@npm:^3.1.0, loupe@npm:^3.1.1, loupe@npm:^3.1.2":
|
||||||
version: 3.1.3
|
version: 3.1.3
|
||||||
resolution: "loupe@npm:3.1.3"
|
resolution: "loupe@npm:3.1.3"
|
||||||
|
|||||||
Reference in New Issue
Block a user