SchemaV2: Remove legacy rows from schema v2. (#105238)
* save transparent setting * make sure we test both transparent and non transparent * no more legacy rows * schema changes * Add testing, fix first row offset * Remove legacy row from transform test * Remove panel that's not present in layout * Remove expects after removing the row, fix lint issues * Remove unused commit * update codegen * update openapi snapshot * Fix snapshot * add missing default prop * Fix repeating, fix first row, fix not flushing last row * Use correct repeater * fix lint, remove unused empty check * update codegen * update openapi test snapshot
This commit is contained in:
@@ -518,21 +518,8 @@ GridLayoutItemKind: {
|
||||
spec: GridLayoutItemSpec
|
||||
}
|
||||
|
||||
GridLayoutRowKind: {
|
||||
kind: "GridLayoutRow"
|
||||
spec: GridLayoutRowSpec
|
||||
}
|
||||
|
||||
GridLayoutRowSpec: {
|
||||
y: int
|
||||
collapsed: bool
|
||||
title: string
|
||||
elements: [...GridLayoutItemKind] // Grid items in the row will have their Y value be relative to the rows Y value. This means a panel positioned at Y: 0 in a row with Y: 10 will be positioned at Y: 11 (row header has a heigh of 1) in the dashboard.
|
||||
repeat?: RowRepeatOptions
|
||||
}
|
||||
|
||||
GridLayoutSpec: {
|
||||
items: [...GridLayoutItemKind | GridLayoutRowKind]
|
||||
items: [...GridLayoutItemKind]
|
||||
}
|
||||
|
||||
GridLayoutKind: {
|
||||
|
||||
@@ -522,21 +522,8 @@ GridLayoutItemKind: {
|
||||
spec: GridLayoutItemSpec
|
||||
}
|
||||
|
||||
GridLayoutRowKind: {
|
||||
kind: "GridLayoutRow"
|
||||
spec: GridLayoutRowSpec
|
||||
}
|
||||
|
||||
GridLayoutRowSpec: {
|
||||
y: int
|
||||
collapsed: bool
|
||||
title: string
|
||||
elements: [...GridLayoutItemKind] // Grid items in the row will have their Y value be relative to the rows Y value. This means a panel positioned at Y: 0 in a row with Y: 10 will be positioned at Y: 11 (row header has a heigh of 1) in the dashboard.
|
||||
repeat?: RowRepeatOptions
|
||||
}
|
||||
|
||||
GridLayoutSpec: {
|
||||
items: [...GridLayoutItemKind | GridLayoutRowKind]
|
||||
items: [...GridLayoutItemKind]
|
||||
}
|
||||
|
||||
GridLayoutKind: {
|
||||
|
||||
@@ -688,7 +688,7 @@ func NewDashboardGridLayoutKind() *DashboardGridLayoutKind {
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type DashboardGridLayoutSpec struct {
|
||||
Items []DashboardGridLayoutItemKindOrGridLayoutRowKind `json:"items"`
|
||||
Items []DashboardGridLayoutItemKind `json:"items"`
|
||||
}
|
||||
|
||||
// NewDashboardGridLayoutSpec creates a new DashboardGridLayoutSpec object.
|
||||
@@ -758,46 +758,6 @@ func NewDashboardRepeatOptions() *DashboardRepeatOptions {
|
||||
// +k8s:openapi-gen=true
|
||||
const DashboardRepeatMode = "variable"
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type DashboardGridLayoutRowKind struct {
|
||||
Kind string `json:"kind"`
|
||||
Spec DashboardGridLayoutRowSpec `json:"spec"`
|
||||
}
|
||||
|
||||
// NewDashboardGridLayoutRowKind creates a new DashboardGridLayoutRowKind object.
|
||||
func NewDashboardGridLayoutRowKind() *DashboardGridLayoutRowKind {
|
||||
return &DashboardGridLayoutRowKind{
|
||||
Kind: "GridLayoutRow",
|
||||
Spec: *NewDashboardGridLayoutRowSpec(),
|
||||
}
|
||||
}
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type DashboardGridLayoutRowSpec struct {
|
||||
Y int64 `json:"y"`
|
||||
Collapsed bool `json:"collapsed"`
|
||||
Title string `json:"title"`
|
||||
// Grid items in the row will have their Y value be relative to the rows Y value. This means a panel positioned at Y: 0 in a row with Y: 10 will be positioned at Y: 11 (row header has a heigh of 1) in the dashboard.
|
||||
Elements []DashboardGridLayoutItemKind `json:"elements"`
|
||||
Repeat *DashboardRowRepeatOptions `json:"repeat,omitempty"`
|
||||
}
|
||||
|
||||
// NewDashboardGridLayoutRowSpec creates a new DashboardGridLayoutRowSpec object.
|
||||
func NewDashboardGridLayoutRowSpec() *DashboardGridLayoutRowSpec {
|
||||
return &DashboardGridLayoutRowSpec{}
|
||||
}
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type DashboardRowRepeatOptions struct {
|
||||
Mode string `json:"mode"`
|
||||
Value string `json:"value"`
|
||||
}
|
||||
|
||||
// NewDashboardRowRepeatOptions creates a new DashboardRowRepeatOptions object.
|
||||
func NewDashboardRowRepeatOptions() *DashboardRowRepeatOptions {
|
||||
return &DashboardRowRepeatOptions{}
|
||||
}
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type DashboardRowsLayoutKind struct {
|
||||
Kind string `json:"kind"`
|
||||
@@ -954,6 +914,17 @@ func NewDashboardConditionalRenderingTimeRangeSizeSpec() *DashboardConditionalRe
|
||||
return &DashboardConditionalRenderingTimeRangeSizeSpec{}
|
||||
}
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type DashboardRowRepeatOptions struct {
|
||||
Mode string `json:"mode"`
|
||||
Value string `json:"value"`
|
||||
}
|
||||
|
||||
// NewDashboardRowRepeatOptions creates a new DashboardRowRepeatOptions object.
|
||||
func NewDashboardRowRepeatOptions() *DashboardRowRepeatOptions {
|
||||
return &DashboardRowRepeatOptions{}
|
||||
}
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type DashboardAutoGridLayoutKind struct {
|
||||
Kind string `json:"kind"`
|
||||
@@ -2027,67 +1998,6 @@ func (resource *DashboardValueMapOrRangeMapOrRegexMapOrSpecialValueMap) Unmarsha
|
||||
return fmt.Errorf("could not unmarshal resource with `type = %v`", discriminator)
|
||||
}
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type DashboardGridLayoutItemKindOrGridLayoutRowKind struct {
|
||||
GridLayoutItemKind *DashboardGridLayoutItemKind `json:"GridLayoutItemKind,omitempty"`
|
||||
GridLayoutRowKind *DashboardGridLayoutRowKind `json:"GridLayoutRowKind,omitempty"`
|
||||
}
|
||||
|
||||
// NewDashboardGridLayoutItemKindOrGridLayoutRowKind creates a new DashboardGridLayoutItemKindOrGridLayoutRowKind object.
|
||||
func NewDashboardGridLayoutItemKindOrGridLayoutRowKind() *DashboardGridLayoutItemKindOrGridLayoutRowKind {
|
||||
return &DashboardGridLayoutItemKindOrGridLayoutRowKind{}
|
||||
}
|
||||
|
||||
// MarshalJSON implements a custom JSON marshalling logic to encode `DashboardGridLayoutItemKindOrGridLayoutRowKind` as JSON.
|
||||
func (resource DashboardGridLayoutItemKindOrGridLayoutRowKind) MarshalJSON() ([]byte, error) {
|
||||
if resource.GridLayoutItemKind != nil {
|
||||
return json.Marshal(resource.GridLayoutItemKind)
|
||||
}
|
||||
if resource.GridLayoutRowKind != nil {
|
||||
return json.Marshal(resource.GridLayoutRowKind)
|
||||
}
|
||||
return []byte("null"), nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements a custom JSON unmarshalling logic to decode `DashboardGridLayoutItemKindOrGridLayoutRowKind` from JSON.
|
||||
func (resource *DashboardGridLayoutItemKindOrGridLayoutRowKind) UnmarshalJSON(raw []byte) error {
|
||||
if raw == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// FIXME: this is wasteful, we need to find a more efficient way to unmarshal this.
|
||||
parsedAsMap := make(map[string]interface{})
|
||||
if err := json.Unmarshal(raw, &parsedAsMap); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
discriminator, found := parsedAsMap["kind"]
|
||||
if !found {
|
||||
return errors.New("discriminator field 'kind' not found in payload")
|
||||
}
|
||||
|
||||
switch discriminator {
|
||||
case "GridLayoutItem":
|
||||
var dashboardGridLayoutItemKind DashboardGridLayoutItemKind
|
||||
if err := json.Unmarshal(raw, &dashboardGridLayoutItemKind); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
resource.GridLayoutItemKind = &dashboardGridLayoutItemKind
|
||||
return nil
|
||||
case "GridLayoutRow":
|
||||
var dashboardGridLayoutRowKind DashboardGridLayoutRowKind
|
||||
if err := json.Unmarshal(raw, &dashboardGridLayoutRowKind); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
resource.GridLayoutRowKind = &dashboardGridLayoutRowKind
|
||||
return nil
|
||||
}
|
||||
|
||||
return fmt.Errorf("could not unmarshal resource with `kind = %v`", discriminator)
|
||||
}
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type DashboardGridLayoutKindOrAutoGridLayoutKindOrTabsLayoutKindOrRowsLayoutKind struct {
|
||||
GridLayoutKind *DashboardGridLayoutKind `json:"GridLayoutKind,omitempty"`
|
||||
|
||||
@@ -56,13 +56,10 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA
|
||||
"github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1.DashboardFieldConfig": schema_pkg_apis_dashboard_v2alpha1_DashboardFieldConfig(ref),
|
||||
"github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1.DashboardFieldConfigSource": schema_pkg_apis_dashboard_v2alpha1_DashboardFieldConfigSource(ref),
|
||||
"github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1.DashboardGridLayoutItemKind": schema_pkg_apis_dashboard_v2alpha1_DashboardGridLayoutItemKind(ref),
|
||||
"github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1.DashboardGridLayoutItemKindOrGridLayoutRowKind": schema_pkg_apis_dashboard_v2alpha1_DashboardGridLayoutItemKindOrGridLayoutRowKind(ref),
|
||||
"github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1.DashboardGridLayoutItemSpec": schema_pkg_apis_dashboard_v2alpha1_DashboardGridLayoutItemSpec(ref),
|
||||
"github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1.DashboardGridLayoutKind": schema_pkg_apis_dashboard_v2alpha1_DashboardGridLayoutKind(ref),
|
||||
"github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1.DashboardGridLayoutKindOrAutoGridLayoutKindOrTabsLayoutKindOrRowsLayoutKind": schema_pkg_apis_dashboard_v2alpha1_DashboardGridLayoutKindOrAutoGridLayoutKindOrTabsLayoutKindOrRowsLayoutKind(ref),
|
||||
"github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1.DashboardGridLayoutKindOrRowsLayoutKindOrAutoGridLayoutKindOrTabsLayoutKind": schema_pkg_apis_dashboard_v2alpha1_DashboardGridLayoutKindOrRowsLayoutKindOrAutoGridLayoutKindOrTabsLayoutKind(ref),
|
||||
"github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1.DashboardGridLayoutRowKind": schema_pkg_apis_dashboard_v2alpha1_DashboardGridLayoutRowKind(ref),
|
||||
"github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1.DashboardGridLayoutRowSpec": schema_pkg_apis_dashboard_v2alpha1_DashboardGridLayoutRowSpec(ref),
|
||||
"github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1.DashboardGridLayoutSpec": schema_pkg_apis_dashboard_v2alpha1_DashboardGridLayoutSpec(ref),
|
||||
"github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1.DashboardGroupByVariableKind": schema_pkg_apis_dashboard_v2alpha1_DashboardGroupByVariableKind(ref),
|
||||
"github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1.DashboardGroupByVariableSpec": schema_pkg_apis_dashboard_v2alpha1_DashboardGroupByVariableSpec(ref),
|
||||
@@ -2057,30 +2054,6 @@ func schema_pkg_apis_dashboard_v2alpha1_DashboardGridLayoutItemKind(ref common.R
|
||||
}
|
||||
}
|
||||
|
||||
func schema_pkg_apis_dashboard_v2alpha1_DashboardGridLayoutItemKindOrGridLayoutRowKind(ref common.ReferenceCallback) common.OpenAPIDefinition {
|
||||
return common.OpenAPIDefinition{
|
||||
Schema: spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Type: []string{"object"},
|
||||
Properties: map[string]spec.Schema{
|
||||
"GridLayoutItemKind": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Ref: ref("github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1.DashboardGridLayoutItemKind"),
|
||||
},
|
||||
},
|
||||
"GridLayoutRowKind": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Ref: ref("github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1.DashboardGridLayoutRowKind"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Dependencies: []string{
|
||||
"github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1.DashboardGridLayoutItemKind", "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1.DashboardGridLayoutRowKind"},
|
||||
}
|
||||
}
|
||||
|
||||
func schema_pkg_apis_dashboard_v2alpha1_DashboardGridLayoutItemSpec(ref common.ReferenceCallback) common.OpenAPIDefinition {
|
||||
return common.OpenAPIDefinition{
|
||||
Schema: spec.Schema{
|
||||
@@ -2232,89 +2205,6 @@ func schema_pkg_apis_dashboard_v2alpha1_DashboardGridLayoutKindOrRowsLayoutKindO
|
||||
}
|
||||
}
|
||||
|
||||
func schema_pkg_apis_dashboard_v2alpha1_DashboardGridLayoutRowKind(ref common.ReferenceCallback) common.OpenAPIDefinition {
|
||||
return common.OpenAPIDefinition{
|
||||
Schema: spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Type: []string{"object"},
|
||||
Properties: map[string]spec.Schema{
|
||||
"kind": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Default: "",
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
"spec": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Default: map[string]interface{}{},
|
||||
Ref: ref("github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1.DashboardGridLayoutRowSpec"),
|
||||
},
|
||||
},
|
||||
},
|
||||
Required: []string{"kind", "spec"},
|
||||
},
|
||||
},
|
||||
Dependencies: []string{
|
||||
"github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1.DashboardGridLayoutRowSpec"},
|
||||
}
|
||||
}
|
||||
|
||||
func schema_pkg_apis_dashboard_v2alpha1_DashboardGridLayoutRowSpec(ref common.ReferenceCallback) common.OpenAPIDefinition {
|
||||
return common.OpenAPIDefinition{
|
||||
Schema: spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Type: []string{"object"},
|
||||
Properties: map[string]spec.Schema{
|
||||
"y": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Default: 0,
|
||||
Type: []string{"integer"},
|
||||
Format: "int64",
|
||||
},
|
||||
},
|
||||
"collapsed": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Default: false,
|
||||
Type: []string{"boolean"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
"title": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Default: "",
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
"elements": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "Grid items in the row will have their Y value be relative to the rows Y value. This means a panel positioned at Y: 0 in a row with Y: 10 will be positioned at Y: 11 (row header has a heigh of 1) in the dashboard.",
|
||||
Type: []string{"array"},
|
||||
Items: &spec.SchemaOrArray{
|
||||
Schema: &spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Default: map[string]interface{}{},
|
||||
Ref: ref("github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1.DashboardGridLayoutItemKind"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"repeat": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Ref: ref("github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1.DashboardRowRepeatOptions"),
|
||||
},
|
||||
},
|
||||
},
|
||||
Required: []string{"y", "collapsed", "title", "elements"},
|
||||
},
|
||||
},
|
||||
Dependencies: []string{
|
||||
"github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1.DashboardGridLayoutItemKind", "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1.DashboardRowRepeatOptions"},
|
||||
}
|
||||
}
|
||||
|
||||
func schema_pkg_apis_dashboard_v2alpha1_DashboardGridLayoutSpec(ref common.ReferenceCallback) common.OpenAPIDefinition {
|
||||
return common.OpenAPIDefinition{
|
||||
Schema: spec.Schema{
|
||||
@@ -2327,7 +2217,8 @@ func schema_pkg_apis_dashboard_v2alpha1_DashboardGridLayoutSpec(ref common.Refer
|
||||
Items: &spec.SchemaOrArray{
|
||||
Schema: &spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Ref: ref("github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1.DashboardGridLayoutItemKindOrGridLayoutRowKind"),
|
||||
Default: map[string]interface{}{},
|
||||
Ref: ref("github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1.DashboardGridLayoutItemKind"),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -2338,7 +2229,7 @@ func schema_pkg_apis_dashboard_v2alpha1_DashboardGridLayoutSpec(ref common.Refer
|
||||
},
|
||||
},
|
||||
Dependencies: []string{
|
||||
"github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1.DashboardGridLayoutItemKindOrGridLayoutRowKind"},
|
||||
"github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1.DashboardGridLayoutItemKind"},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2390,6 +2281,11 @@ func schema_pkg_apis_dashboard_v2alpha1_DashboardGroupByVariableSpec(ref common.
|
||||
Ref: ref("github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1.DashboardDataSourceRef"),
|
||||
},
|
||||
},
|
||||
"defaultValue": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Ref: ref("github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1.DashboardVariableOption"),
|
||||
},
|
||||
},
|
||||
"current": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Default: map[string]interface{}{},
|
||||
|
||||
-3
@@ -12,7 +12,6 @@ API rule violation: list_type_missing,github.com/grafana/grafana/apps/dashboard/
|
||||
API rule violation: list_type_missing,github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1,DashboardFieldConfig,Links
|
||||
API rule violation: list_type_missing,github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1,DashboardFieldConfig,Mappings
|
||||
API rule violation: list_type_missing,github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1,DashboardFieldConfigSource,Overrides
|
||||
API rule violation: list_type_missing,github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1,DashboardGridLayoutRowSpec,Elements
|
||||
API rule violation: list_type_missing,github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1,DashboardGridLayoutSpec,Items
|
||||
API rule violation: list_type_missing,github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1,DashboardGroupByVariableSpec,Options
|
||||
API rule violation: list_type_missing,github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1,DashboardIntervalVariableSpec,Options
|
||||
@@ -36,8 +35,6 @@ API rule violation: list_type_missing,github.com/grafana/grafana/apps/dashboard/
|
||||
API rule violation: names_match,github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1,DashboardConditionalRenderingVariableKindOrConditionalRenderingDataKindOrConditionalRenderingTimeRangeSizeKind,ConditionalRenderingDataKind
|
||||
API rule violation: names_match,github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1,DashboardConditionalRenderingVariableKindOrConditionalRenderingDataKindOrConditionalRenderingTimeRangeSizeKind,ConditionalRenderingTimeRangeSizeKind
|
||||
API rule violation: names_match,github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1,DashboardConditionalRenderingVariableKindOrConditionalRenderingDataKindOrConditionalRenderingTimeRangeSizeKind,ConditionalRenderingVariableKind
|
||||
API rule violation: names_match,github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1,DashboardGridLayoutItemKindOrGridLayoutRowKind,GridLayoutItemKind
|
||||
API rule violation: names_match,github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1,DashboardGridLayoutItemKindOrGridLayoutRowKind,GridLayoutRowKind
|
||||
API rule violation: names_match,github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1,DashboardGridLayoutKindOrAutoGridLayoutKindOrTabsLayoutKindOrRowsLayoutKind,AutoGridLayoutKind
|
||||
API rule violation: names_match,github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1,DashboardGridLayoutKindOrAutoGridLayoutKindOrTabsLayoutKindOrRowsLayoutKind,GridLayoutKind
|
||||
API rule violation: names_match,github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1,DashboardGridLayoutKindOrAutoGridLayoutKindOrTabsLayoutKindOrRowsLayoutKind,RowsLayoutKind
|
||||
|
||||
@@ -202,60 +202,6 @@ export const handyTestingSchema: Spec = {
|
||||
},
|
||||
},
|
||||
},
|
||||
'panel-3': {
|
||||
kind: 'Panel',
|
||||
spec: {
|
||||
data: {
|
||||
kind: 'QueryGroup',
|
||||
spec: {
|
||||
queries: [
|
||||
{
|
||||
kind: 'PanelQuery',
|
||||
spec: {
|
||||
refId: 'A',
|
||||
datasource: {
|
||||
type: 'prometheus',
|
||||
uid: 'datasource1',
|
||||
},
|
||||
query: {
|
||||
kind: 'prometheus',
|
||||
spec: {
|
||||
expr: 'test-query',
|
||||
},
|
||||
},
|
||||
hidden: false,
|
||||
},
|
||||
},
|
||||
],
|
||||
queryOptions: {
|
||||
timeFrom: '1h',
|
||||
maxDataPoints: 100,
|
||||
timeShift: '1h',
|
||||
queryCachingTTL: 60,
|
||||
interval: '1m',
|
||||
cacheTimeout: '1m',
|
||||
hideTimeOverride: false,
|
||||
},
|
||||
transformations: [],
|
||||
},
|
||||
},
|
||||
description: 'Test Description',
|
||||
links: [],
|
||||
title: 'Test Panel 3',
|
||||
id: 3,
|
||||
vizConfig: {
|
||||
kind: 'timeseries',
|
||||
spec: {
|
||||
fieldConfig: {
|
||||
defaults: {},
|
||||
overrides: [],
|
||||
},
|
||||
options: {},
|
||||
pluginVersion: '7.0.0',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
layout: {
|
||||
kind: 'GridLayout',
|
||||
@@ -292,30 +238,6 @@ export const handyTestingSchema: Spec = {
|
||||
y: 2,
|
||||
},
|
||||
},
|
||||
{
|
||||
kind: 'GridLayoutRow',
|
||||
spec: {
|
||||
y: 20,
|
||||
collapsed: false,
|
||||
title: 'Row 1',
|
||||
repeat: { value: 'customVar', mode: 'variable' },
|
||||
elements: [
|
||||
{
|
||||
kind: 'GridLayoutItem',
|
||||
spec: {
|
||||
element: {
|
||||
kind: 'ElementReference',
|
||||
name: 'panel-3',
|
||||
},
|
||||
height: 10,
|
||||
width: 10,
|
||||
x: 0,
|
||||
y: 0,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
|
||||
@@ -518,21 +518,8 @@ GridLayoutItemKind: {
|
||||
spec: GridLayoutItemSpec
|
||||
}
|
||||
|
||||
GridLayoutRowKind: {
|
||||
kind: "GridLayoutRow"
|
||||
spec: GridLayoutRowSpec
|
||||
}
|
||||
|
||||
GridLayoutRowSpec: {
|
||||
y: int
|
||||
collapsed: bool
|
||||
title: string
|
||||
elements: [...GridLayoutItemKind] // Grid items in the row will have their Y value be relative to the rows Y value. This means a panel positioned at Y: 0 in a row with Y: 10 will be positioned at Y: 11 (row header has a heigh of 1) in the dashboard.
|
||||
repeat?: RowRepeatOptions
|
||||
}
|
||||
|
||||
GridLayoutSpec: {
|
||||
items: [...GridLayoutItemKind | GridLayoutRowKind]
|
||||
items: [...GridLayoutItemKind]
|
||||
}
|
||||
|
||||
GridLayoutKind: {
|
||||
|
||||
@@ -609,7 +609,7 @@ export const defaultGridLayoutKind = (): GridLayoutKind => ({
|
||||
});
|
||||
|
||||
export interface GridLayoutSpec {
|
||||
items: (GridLayoutItemKind | GridLayoutRowKind)[];
|
||||
items: GridLayoutItemKind[];
|
||||
}
|
||||
|
||||
export const defaultGridLayoutSpec = (): GridLayoutSpec => ({
|
||||
@@ -669,42 +669,6 @@ export const defaultRepeatOptions = (): RepeatOptions => ({
|
||||
// other repeat modes will be added in the future: label, frame
|
||||
export const RepeatMode = "variable";
|
||||
|
||||
export interface GridLayoutRowKind {
|
||||
kind: "GridLayoutRow";
|
||||
spec: GridLayoutRowSpec;
|
||||
}
|
||||
|
||||
export const defaultGridLayoutRowKind = (): GridLayoutRowKind => ({
|
||||
kind: "GridLayoutRow",
|
||||
spec: defaultGridLayoutRowSpec(),
|
||||
});
|
||||
|
||||
export interface GridLayoutRowSpec {
|
||||
y: number;
|
||||
collapsed: boolean;
|
||||
title: string;
|
||||
// Grid items in the row will have their Y value be relative to the rows Y value. This means a panel positioned at Y: 0 in a row with Y: 10 will be positioned at Y: 11 (row header has a heigh of 1) in the dashboard.
|
||||
elements: GridLayoutItemKind[];
|
||||
repeat?: RowRepeatOptions;
|
||||
}
|
||||
|
||||
export const defaultGridLayoutRowSpec = (): GridLayoutRowSpec => ({
|
||||
y: 0,
|
||||
collapsed: false,
|
||||
title: "",
|
||||
elements: [],
|
||||
});
|
||||
|
||||
export interface RowRepeatOptions {
|
||||
mode: "variable";
|
||||
value: string;
|
||||
}
|
||||
|
||||
export const defaultRowRepeatOptions = (): RowRepeatOptions => ({
|
||||
mode: RepeatMode,
|
||||
value: "",
|
||||
});
|
||||
|
||||
export interface RowsLayoutKind {
|
||||
kind: "RowsLayout";
|
||||
spec: RowsLayoutSpec;
|
||||
@@ -747,6 +711,16 @@ export const defaultRowsLayoutRowSpec = (): RowsLayoutRowSpec => ({
|
||||
layout: defaultGridLayoutKind(),
|
||||
});
|
||||
|
||||
export interface RowRepeatOptions {
|
||||
mode: "variable";
|
||||
value: string;
|
||||
}
|
||||
|
||||
export const defaultRowRepeatOptions = (): RowRepeatOptions => ({
|
||||
mode: RepeatMode,
|
||||
value: "",
|
||||
});
|
||||
|
||||
export interface ConditionalRenderingGroupKind {
|
||||
kind: "ConditionalRenderingGroup";
|
||||
spec: ConditionalRenderingGroupSpec;
|
||||
|
||||
@@ -564,7 +564,7 @@ export const defaultGridLayoutKind = (): GridLayoutKind => ({
|
||||
});
|
||||
|
||||
export interface GridLayoutSpec {
|
||||
items: (GridLayoutItemKind | GridLayoutRowKind)[];
|
||||
items: GridLayoutItemKind[];
|
||||
}
|
||||
|
||||
export const defaultGridLayoutSpec = (): GridLayoutSpec => ({
|
||||
@@ -624,42 +624,6 @@ export const defaultRepeatOptions = (): RepeatOptions => ({
|
||||
// other repeat modes will be added in the future: label, frame
|
||||
export const RepeatMode = "variable";
|
||||
|
||||
export interface GridLayoutRowKind {
|
||||
kind: "GridLayoutRow";
|
||||
spec: GridLayoutRowSpec;
|
||||
}
|
||||
|
||||
export const defaultGridLayoutRowKind = (): GridLayoutRowKind => ({
|
||||
kind: "GridLayoutRow",
|
||||
spec: defaultGridLayoutRowSpec(),
|
||||
});
|
||||
|
||||
export interface GridLayoutRowSpec {
|
||||
y: number;
|
||||
collapsed: boolean;
|
||||
title: string;
|
||||
// Grid items in the row will have their Y value be relative to the rows Y value. This means a panel positioned at Y: 0 in a row with Y: 10 will be positioned at Y: 11 (row header has a heigh of 1) in the dashboard.
|
||||
elements: GridLayoutItemKind[];
|
||||
repeat?: RowRepeatOptions;
|
||||
}
|
||||
|
||||
export const defaultGridLayoutRowSpec = (): GridLayoutRowSpec => ({
|
||||
y: 0,
|
||||
collapsed: false,
|
||||
title: "",
|
||||
elements: [],
|
||||
});
|
||||
|
||||
export interface RowRepeatOptions {
|
||||
mode: "variable";
|
||||
value: string;
|
||||
}
|
||||
|
||||
export const defaultRowRepeatOptions = (): RowRepeatOptions => ({
|
||||
mode: RepeatMode,
|
||||
value: "",
|
||||
});
|
||||
|
||||
export interface RowsLayoutKind {
|
||||
kind: "RowsLayout";
|
||||
spec: RowsLayoutSpec;
|
||||
@@ -782,6 +746,16 @@ export const defaultConditionalRenderingTimeRangeSizeSpec = (): ConditionalRende
|
||||
value: "",
|
||||
});
|
||||
|
||||
export interface RowRepeatOptions {
|
||||
mode: "variable";
|
||||
value: string;
|
||||
}
|
||||
|
||||
export const defaultRowRepeatOptions = (): RowRepeatOptions => ({
|
||||
mode: RepeatMode,
|
||||
value: "",
|
||||
});
|
||||
|
||||
export interface AutoGridLayoutKind {
|
||||
kind: "AutoGridLayout";
|
||||
spec: AutoGridLayoutSpec;
|
||||
|
||||
@@ -2230,17 +2230,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"com.github.grafana.grafana.apps.dashboard.pkg.apis.dashboard.v2alpha1.DashboardGridLayoutItemKindOrGridLayoutRowKind": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"GridLayoutItemKind": {
|
||||
"$ref": "#/components/schemas/com.github.grafana.grafana.apps.dashboard.pkg.apis.dashboard.v2alpha1.DashboardGridLayoutItemKind"
|
||||
},
|
||||
"GridLayoutRowKind": {
|
||||
"$ref": "#/components/schemas/com.github.grafana.grafana.apps.dashboard.pkg.apis.dashboard.v2alpha1.DashboardGridLayoutRowKind"
|
||||
}
|
||||
}
|
||||
},
|
||||
"com.github.grafana.grafana.apps.dashboard.pkg.apis.dashboard.v2alpha1.DashboardGridLayoutItemSpec": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
@@ -2340,66 +2329,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"com.github.grafana.grafana.apps.dashboard.pkg.apis.dashboard.v2alpha1.DashboardGridLayoutRowKind": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"kind",
|
||||
"spec"
|
||||
],
|
||||
"properties": {
|
||||
"kind": {
|
||||
"type": "string",
|
||||
"default": ""
|
||||
},
|
||||
"spec": {
|
||||
"default": {},
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/com.github.grafana.grafana.apps.dashboard.pkg.apis.dashboard.v2alpha1.DashboardGridLayoutRowSpec"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"com.github.grafana.grafana.apps.dashboard.pkg.apis.dashboard.v2alpha1.DashboardGridLayoutRowSpec": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"y",
|
||||
"collapsed",
|
||||
"title",
|
||||
"elements"
|
||||
],
|
||||
"properties": {
|
||||
"collapsed": {
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"elements": {
|
||||
"description": "Grid items in the row will have their Y value be relative to the rows Y value. This means a panel positioned at Y: 0 in a row with Y: 10 will be positioned at Y: 11 (row header has a heigh of 1) in the dashboard.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"default": {},
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/com.github.grafana.grafana.apps.dashboard.pkg.apis.dashboard.v2alpha1.DashboardGridLayoutItemKind"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"repeat": {
|
||||
"$ref": "#/components/schemas/com.github.grafana.grafana.apps.dashboard.pkg.apis.dashboard.v2alpha1.DashboardRowRepeatOptions"
|
||||
},
|
||||
"title": {
|
||||
"type": "string",
|
||||
"default": ""
|
||||
},
|
||||
"y": {
|
||||
"type": "integer",
|
||||
"format": "int64",
|
||||
"default": 0
|
||||
}
|
||||
}
|
||||
},
|
||||
"com.github.grafana.grafana.apps.dashboard.pkg.apis.dashboard.v2alpha1.DashboardGridLayoutSpec": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
@@ -2409,7 +2338,12 @@
|
||||
"items": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/com.github.grafana.grafana.apps.dashboard.pkg.apis.dashboard.v2alpha1.DashboardGridLayoutItemKindOrGridLayoutRowKind"
|
||||
"default": {},
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/com.github.grafana.grafana.apps.dashboard.pkg.apis.dashboard.v2alpha1.DashboardGridLayoutItemKind"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2459,6 +2393,9 @@
|
||||
"datasource": {
|
||||
"$ref": "#/components/schemas/com.github.grafana.grafana.apps.dashboard.pkg.apis.dashboard.v2alpha1.DashboardDataSourceRef"
|
||||
},
|
||||
"defaultValue": {
|
||||
"$ref": "#/components/schemas/com.github.grafana.grafana.apps.dashboard.pkg.apis.dashboard.v2alpha1.DashboardVariableOption"
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
},
|
||||
|
||||
@@ -12,14 +12,7 @@ export function removePanelRefFromLayout(layout: DashboardV2Spec['layout'], elem
|
||||
case 'GridLayout': {
|
||||
const items = layout.spec.items || [];
|
||||
layout.spec.items = items.filter((item) => {
|
||||
if (item.kind === 'GridLayoutItem') {
|
||||
return item.spec.element.name !== elementName;
|
||||
} else if (item.kind === 'GridLayoutRow') {
|
||||
item.spec.elements = item.spec.elements.filter((el) => el.spec.element.name !== elementName);
|
||||
// Keep the row if it still has elements left
|
||||
return item.spec.elements.length > 0;
|
||||
}
|
||||
return true;
|
||||
return item.spec.element.name !== elementName;
|
||||
});
|
||||
break;
|
||||
}
|
||||
@@ -60,17 +53,7 @@ function isLayoutEmpty(layout: DashboardV2Spec['layout']) {
|
||||
switch (layout.kind) {
|
||||
case 'GridLayout': {
|
||||
const items = layout.spec.items || [];
|
||||
return (
|
||||
items.length === 0 ||
|
||||
items.every((item) => {
|
||||
if (item.kind === 'GridLayoutItem') {
|
||||
return false;
|
||||
} else if (item.kind === 'GridLayoutRow') {
|
||||
return item.spec.elements.length === 0;
|
||||
}
|
||||
return false;
|
||||
})
|
||||
);
|
||||
return items.length === 0;
|
||||
}
|
||||
|
||||
case 'AutoGridLayout': {
|
||||
|
||||
-65
@@ -85,44 +85,6 @@ exports[`transformSceneToSaveModelSchemaV2 should transform scene to save model
|
||||
},
|
||||
},
|
||||
},
|
||||
"panel-2": {
|
||||
"kind": "Panel",
|
||||
"spec": {
|
||||
"data": {
|
||||
"kind": "QueryGroup",
|
||||
"spec": {
|
||||
"queries": [],
|
||||
"queryOptions": {},
|
||||
"transformations": [],
|
||||
},
|
||||
},
|
||||
"description": "Test Description 2",
|
||||
"id": 2,
|
||||
"links": [
|
||||
{
|
||||
"targetBlank": true,
|
||||
"title": "Test Link 1",
|
||||
"url": "http://test1.com",
|
||||
},
|
||||
{
|
||||
"title": "Test Link 2",
|
||||
"url": "http://test2.com",
|
||||
},
|
||||
],
|
||||
"title": "Test Panel 2",
|
||||
"vizConfig": {
|
||||
"kind": "graph",
|
||||
"spec": {
|
||||
"fieldConfig": {
|
||||
"defaults": {},
|
||||
"overrides": [],
|
||||
},
|
||||
"options": {},
|
||||
"pluginVersion": "7.0.0",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"layout": {
|
||||
"kind": "GridLayout",
|
||||
@@ -141,33 +103,6 @@ exports[`transformSceneToSaveModelSchemaV2 should transform scene to save model
|
||||
"y": 0,
|
||||
},
|
||||
},
|
||||
{
|
||||
"kind": "GridLayoutRow",
|
||||
"spec": {
|
||||
"collapsed": false,
|
||||
"elements": [
|
||||
{
|
||||
"kind": "GridLayoutItem",
|
||||
"spec": {
|
||||
"element": {
|
||||
"kind": "ElementReference",
|
||||
"name": "panel-2",
|
||||
},
|
||||
"height": 0,
|
||||
"width": 0,
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
},
|
||||
},
|
||||
],
|
||||
"repeat": {
|
||||
"mode": "variable",
|
||||
"value": "customVar",
|
||||
},
|
||||
"title": "Test Row",
|
||||
"y": 10,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
|
||||
+3
-76
@@ -1,9 +1,8 @@
|
||||
import { SceneGridItemLike, SceneGridLayout, SceneGridRow, SceneObject, VizPanel } from '@grafana/scenes';
|
||||
import { SceneGridItemLike, SceneGridLayout, VizPanel } from '@grafana/scenes';
|
||||
import {
|
||||
Spec as DashboardV2Spec,
|
||||
GridLayoutItemKind,
|
||||
GridLayoutKind,
|
||||
GridLayoutRowKind,
|
||||
RepeatOptions,
|
||||
Element,
|
||||
GridLayoutItemSpec,
|
||||
@@ -14,12 +13,8 @@ import { contextSrv } from 'app/core/core';
|
||||
|
||||
import { DashboardGridItem } from '../../scene/layout-default/DashboardGridItem';
|
||||
import { DefaultGridLayoutManager } from '../../scene/layout-default/DefaultGridLayoutManager';
|
||||
import { RowRepeaterBehavior } from '../../scene/layout-default/RowRepeaterBehavior';
|
||||
import { RowActions } from '../../scene/layout-default/row-actions/RowActions';
|
||||
import { getOriginalKey, isClonedKey } from '../../utils/clone';
|
||||
import { dashboardSceneGraph } from '../../utils/dashboardSceneGraph';
|
||||
import { calculateGridItemDimensions, isLibraryPanel } from '../../utils/utils';
|
||||
import { GRID_ROW_HEIGHT } from '../const';
|
||||
|
||||
import { buildLibraryPanel, buildVizPanel } from './utils';
|
||||
|
||||
@@ -52,11 +47,8 @@ export function deserializeDefaultGridLayout(
|
||||
});
|
||||
}
|
||||
|
||||
function getGridLayoutItems(
|
||||
body: DefaultGridLayoutManager,
|
||||
isSnapshot?: boolean
|
||||
): Array<GridLayoutItemKind | GridLayoutRowKind> {
|
||||
let items: Array<GridLayoutItemKind | GridLayoutRowKind> = [];
|
||||
function getGridLayoutItems(body: DefaultGridLayoutManager, isSnapshot?: boolean): GridLayoutItemKind[] {
|
||||
let items: GridLayoutItemKind[] = [];
|
||||
for (const child of body.state.grid.state.children) {
|
||||
if (child instanceof DashboardGridItem) {
|
||||
// TODO: handle panel repeater scenario
|
||||
@@ -65,50 +57,12 @@ function getGridLayoutItems(
|
||||
} else {
|
||||
items.push(gridItemToGridLayoutItemKind(child));
|
||||
}
|
||||
} else if (child instanceof SceneGridRow) {
|
||||
if (isClonedKey(child.state.key!) && !isSnapshot) {
|
||||
// Skip repeat rows
|
||||
continue;
|
||||
}
|
||||
items.push(gridRowToLayoutRowKind(child, isSnapshot));
|
||||
}
|
||||
}
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
function getRowRepeat(row: SceneGridRow): RepeatOptions | undefined {
|
||||
if (row.state.$behaviors) {
|
||||
for (const behavior of row.state.$behaviors) {
|
||||
if (behavior instanceof RowRepeaterBehavior) {
|
||||
return { value: behavior.state.variableName, mode: 'variable' };
|
||||
}
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function gridRowToLayoutRowKind(row: SceneGridRow, isSnapshot = false): GridLayoutRowKind {
|
||||
const children = row.state.children.map((child) => {
|
||||
if (!(child instanceof DashboardGridItem)) {
|
||||
throw new Error('Unsupported row child type');
|
||||
}
|
||||
const y = (child.state.y ?? 0) - (row.state.y ?? 0) - GRID_ROW_HEIGHT;
|
||||
return gridItemToGridLayoutItemKind(child, y);
|
||||
});
|
||||
|
||||
return {
|
||||
kind: 'GridLayoutRow',
|
||||
spec: {
|
||||
title: row.state.title,
|
||||
y: row.state.y ?? 0,
|
||||
collapsed: Boolean(row.state.isCollapsed),
|
||||
elements: children,
|
||||
repeat: getRowRepeat(row),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export function gridItemToGridLayoutItemKind(gridItem: DashboardGridItem, yOverride?: number): GridLayoutItemKind {
|
||||
let elementGridItem: GridLayoutItemKind | undefined;
|
||||
let x = 0,
|
||||
@@ -234,34 +188,7 @@ function createSceneGridLayoutForItems(
|
||||
return gridItems.map((item) => {
|
||||
if (item.kind === 'GridLayoutItem') {
|
||||
return deserializeGridItem(item, elements, panelIdGenerator);
|
||||
} else if (item.kind === 'GridLayoutRow') {
|
||||
const children = item.spec.elements.map((gridElement) => {
|
||||
const panel = elements[getOriginalKey(gridElement.spec.element.name)];
|
||||
if (panel.kind === 'Panel' || panel.kind === 'LibraryPanel') {
|
||||
let id: number | undefined;
|
||||
if (panelIdGenerator) {
|
||||
id = panelIdGenerator();
|
||||
}
|
||||
return buildGridItem(gridElement.spec, panel, item.spec.y + GRID_ROW_HEIGHT + gridElement.spec.y, id);
|
||||
} else {
|
||||
throw new Error(`Unknown element kind: ${gridElement.kind}`);
|
||||
}
|
||||
});
|
||||
let behaviors: SceneObject[] | undefined;
|
||||
if (item.spec.repeat) {
|
||||
behaviors = [new RowRepeaterBehavior({ variableName: item.spec.repeat.value })];
|
||||
}
|
||||
return new SceneGridRow({
|
||||
y: item.spec.y,
|
||||
isCollapsed: item.spec.collapsed,
|
||||
title: item.spec.title,
|
||||
$behaviors: behaviors,
|
||||
actions: new RowActions({}),
|
||||
children,
|
||||
});
|
||||
} else {
|
||||
// If this has been validated by the schema we should never reach this point, which is why TS is telling us this is an error.
|
||||
//@ts-expect-error
|
||||
throw new Error(`Unknown layout element kind: ${item.kind}`);
|
||||
}
|
||||
});
|
||||
|
||||
+374
@@ -0,0 +1,374 @@
|
||||
{
|
||||
"annotations": {
|
||||
"list": [
|
||||
{
|
||||
"builtIn": 1,
|
||||
"datasource": {
|
||||
"type": "grafana",
|
||||
"uid": "-- Grafana --"
|
||||
},
|
||||
"enable": true,
|
||||
"hide": true,
|
||||
"iconColor": "rgba(0, 211, 255, 1)",
|
||||
"name": "Annotations & Alerts",
|
||||
"type": "dashboard"
|
||||
}
|
||||
]
|
||||
},
|
||||
"editable": true,
|
||||
"fiscalYearStartMonth": 0,
|
||||
"graphTooltip": 0,
|
||||
"links": [],
|
||||
"liveNow": false,
|
||||
"panels": [
|
||||
{
|
||||
"gridPos": {
|
||||
"h": 2,
|
||||
"w": 24,
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
"id": 15,
|
||||
"options": {
|
||||
"code": {
|
||||
"language": "plaintext",
|
||||
"showLineNumbers": false,
|
||||
"showMiniMap": false
|
||||
},
|
||||
"content": "First panel",
|
||||
"mode": "markdown"
|
||||
},
|
||||
"pluginVersion": "10.2.0-pre",
|
||||
"type": "text",
|
||||
"title": "First panel"
|
||||
},
|
||||
{
|
||||
"collapsed": false,
|
||||
"gridPos": {
|
||||
"h": 1,
|
||||
"w": 24,
|
||||
"x": 0,
|
||||
"y": 3
|
||||
},
|
||||
"id": 20,
|
||||
"panels": [],
|
||||
"title": "Row at the top - not repeated - saved expanded",
|
||||
"type": "row"
|
||||
},
|
||||
{
|
||||
"gridPos": {
|
||||
"h": 2,
|
||||
"w": 24,
|
||||
"x": 0,
|
||||
"y": 4
|
||||
},
|
||||
"id": 15,
|
||||
"options": {
|
||||
"code": {
|
||||
"language": "plaintext",
|
||||
"showLineNumbers": false,
|
||||
"showMiniMap": false
|
||||
},
|
||||
"content": "<div class=\"center-vh\">\n Repeated row below. The row has \n a panel that is also repeated horizontally based\n on values in the $pod variable. \n</div>",
|
||||
"mode": "markdown"
|
||||
},
|
||||
"pluginVersion": "10.2.0-pre",
|
||||
"type": "text"
|
||||
},
|
||||
{
|
||||
"gridPos": {
|
||||
"h": 1,
|
||||
"w": 24,
|
||||
"x": 0,
|
||||
"y": 5
|
||||
},
|
||||
"id": 16,
|
||||
"panels": [],
|
||||
"repeat": "server",
|
||||
"repeatDirection": "h",
|
||||
"title": "Row for server $server",
|
||||
"type": "row"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "testdata",
|
||||
"uid": "PD8C576611E62080A"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "palette-classic"
|
||||
},
|
||||
"custom": {
|
||||
"axisCenteredZero": false,
|
||||
"axisColorMode": "text",
|
||||
"axisLabel": "",
|
||||
"axisPlacement": "auto",
|
||||
"axisBorderShow": false,
|
||||
"barAlignment": 0,
|
||||
"drawStyle": "line",
|
||||
"fillOpacity": 0,
|
||||
"gradientMode": "none",
|
||||
"hideFrom": {
|
||||
"legend": false,
|
||||
"tooltip": false,
|
||||
"viz": false
|
||||
},
|
||||
"insertNulls": false,
|
||||
"lineInterpolation": "linear",
|
||||
"lineWidth": 1,
|
||||
"pointSize": 5,
|
||||
"scaleDistribution": {
|
||||
"type": "linear"
|
||||
},
|
||||
"showPoints": "auto",
|
||||
"spanNulls": false,
|
||||
"stacking": {
|
||||
"group": "A",
|
||||
"mode": "none"
|
||||
},
|
||||
"thresholdsStyle": {
|
||||
"mode": "off"
|
||||
}
|
||||
},
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 10,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 6
|
||||
},
|
||||
"id": 2,
|
||||
"maxPerRow": 3,
|
||||
"options": {
|
||||
"legend": {
|
||||
"calcs": [],
|
||||
"displayMode": "list",
|
||||
"placement": "bottom",
|
||||
"showLegend": true
|
||||
},
|
||||
"tooltip": {
|
||||
"mode": "single",
|
||||
"sort": "none"
|
||||
}
|
||||
},
|
||||
"repeat": "pod",
|
||||
"repeatDirection": "h",
|
||||
"targets": [
|
||||
{
|
||||
"alias": "server = $server, pod id = $pod ",
|
||||
"datasource": {
|
||||
"type": "testdata",
|
||||
"uid": "PD8C576611E62080A"
|
||||
},
|
||||
"refId": "A",
|
||||
"scenarioId": "random_walk",
|
||||
"seriesCount": 1
|
||||
}
|
||||
],
|
||||
"title": "server = $server, pod = $pod",
|
||||
"type": "timeseries"
|
||||
},
|
||||
{
|
||||
"collapsed": true,
|
||||
"gridPos": {
|
||||
"h": 1,
|
||||
"w": 24,
|
||||
"x": 0,
|
||||
"y": 25
|
||||
},
|
||||
"id": 25,
|
||||
"panels": [
|
||||
{
|
||||
"gridPos": {
|
||||
"h": 2,
|
||||
"w": 24,
|
||||
"x": 0,
|
||||
"y": 26
|
||||
},
|
||||
"id": 30,
|
||||
"title": "Text panel in collapsed row",
|
||||
"options": {
|
||||
"code": {
|
||||
"language": "plaintext",
|
||||
"showLineNumbers": false,
|
||||
"showMiniMap": false
|
||||
},
|
||||
"content": "<div class=\"center-vh\">\n Just a panel\n</div>",
|
||||
"mode": "markdown"
|
||||
},
|
||||
"pluginVersion": "10.2.0-pre",
|
||||
"type": "text"
|
||||
}
|
||||
],
|
||||
"title": "Row at the bottom - not repeated - saved collapsed ",
|
||||
"type": "row"
|
||||
}
|
||||
],
|
||||
"refresh": "",
|
||||
"schemaVersion": 38,
|
||||
"tags": ["templating", "gdev"],
|
||||
"templating": {
|
||||
"list": [
|
||||
{
|
||||
"current": {
|
||||
"selected": true,
|
||||
"text": ["A", "B"],
|
||||
"value": ["A", "B"]
|
||||
},
|
||||
"hide": 0,
|
||||
"includeAll": true,
|
||||
"multi": true,
|
||||
"name": "server",
|
||||
"options": [
|
||||
{
|
||||
"selected": false,
|
||||
"text": "All",
|
||||
"value": "$__all"
|
||||
},
|
||||
{
|
||||
"selected": true,
|
||||
"text": "A",
|
||||
"value": "A"
|
||||
},
|
||||
{
|
||||
"selected": true,
|
||||
"text": "B",
|
||||
"value": "B"
|
||||
},
|
||||
{
|
||||
"selected": false,
|
||||
"text": "C",
|
||||
"value": "C"
|
||||
},
|
||||
{
|
||||
"selected": false,
|
||||
"text": "D",
|
||||
"value": "D"
|
||||
},
|
||||
{
|
||||
"selected": false,
|
||||
"text": "E",
|
||||
"value": "E"
|
||||
},
|
||||
{
|
||||
"selected": false,
|
||||
"text": "F",
|
||||
"value": "F"
|
||||
},
|
||||
{
|
||||
"selected": false,
|
||||
"text": "E",
|
||||
"value": "E"
|
||||
},
|
||||
{
|
||||
"selected": false,
|
||||
"text": "G",
|
||||
"value": "G"
|
||||
},
|
||||
{
|
||||
"selected": false,
|
||||
"text": "H",
|
||||
"value": "H"
|
||||
},
|
||||
{
|
||||
"selected": false,
|
||||
"text": "I",
|
||||
"value": "I"
|
||||
},
|
||||
{
|
||||
"selected": false,
|
||||
"text": "J",
|
||||
"value": "J"
|
||||
},
|
||||
{
|
||||
"selected": false,
|
||||
"text": "K",
|
||||
"value": "K"
|
||||
},
|
||||
{
|
||||
"selected": false,
|
||||
"text": "L",
|
||||
"value": "L"
|
||||
}
|
||||
],
|
||||
"query": "A,B,C,D,E,F,E,G,H,I,J,K,L",
|
||||
"queryValue": "",
|
||||
"skipUrlSync": false,
|
||||
"type": "custom"
|
||||
},
|
||||
{
|
||||
"current": {
|
||||
"selected": true,
|
||||
"text": ["Bob", "Rob"],
|
||||
"value": ["1", "2"]
|
||||
},
|
||||
"hide": 0,
|
||||
"includeAll": true,
|
||||
"multi": true,
|
||||
"name": "pod",
|
||||
"options": [
|
||||
{
|
||||
"selected": false,
|
||||
"text": "All",
|
||||
"value": "$__all"
|
||||
},
|
||||
{
|
||||
"selected": true,
|
||||
"text": "Bob",
|
||||
"value": "1"
|
||||
},
|
||||
{
|
||||
"selected": true,
|
||||
"text": "Rob",
|
||||
"value": "2"
|
||||
},
|
||||
{
|
||||
"selected": false,
|
||||
"text": "Sod",
|
||||
"value": "3"
|
||||
},
|
||||
{
|
||||
"selected": false,
|
||||
"text": "Hod",
|
||||
"value": "4"
|
||||
},
|
||||
{
|
||||
"selected": false,
|
||||
"text": "Cod",
|
||||
"value": "5"
|
||||
}
|
||||
],
|
||||
"query": "Bob : 1, Rob : 2,Sod : 3, Hod : 4, Cod : 5",
|
||||
"queryValue": "",
|
||||
"skipUrlSync": false,
|
||||
"type": "custom"
|
||||
}
|
||||
]
|
||||
},
|
||||
"time": {
|
||||
"from": "now-6h",
|
||||
"to": "now"
|
||||
},
|
||||
"timepicker": {},
|
||||
"timezone": "",
|
||||
"title": "Repeating rows",
|
||||
"uid": "Repeating-rows-uid",
|
||||
"version": 1
|
||||
}
|
||||
+5
-9
@@ -13,7 +13,6 @@ import {
|
||||
GroupByVariable,
|
||||
AdHocFiltersVariable,
|
||||
SceneDataTransformer,
|
||||
SceneGridRow,
|
||||
SceneGridItem,
|
||||
} from '@grafana/scenes';
|
||||
import { handyTestingSchema } from '@grafana/schema/dist/esm/schema/dashboard/v2_examples';
|
||||
@@ -239,14 +238,14 @@ describe('transformSaveModelSchemaV2ToScene', () => {
|
||||
|
||||
// VizPanel
|
||||
const vizPanels = (scene.state.body as DashboardLayoutManager).getVizPanels();
|
||||
expect(vizPanels).toHaveLength(3);
|
||||
expect(vizPanels).toHaveLength(2);
|
||||
|
||||
// Layout
|
||||
const layout = scene.state.body as DefaultGridLayoutManager;
|
||||
|
||||
// Panel
|
||||
const panel = getPanelElement(dash, 'panel-1')!;
|
||||
expect(layout.state.grid.state.children.length).toBe(3);
|
||||
expect(layout.state.grid.state.children.length).toBe(2);
|
||||
expect(layout.state.grid.state.children[0].state.key).toBe(`grid-item-${panel.spec.id}`);
|
||||
const gridLayoutItemSpec = (dash.layout.spec as GridLayoutSpec).items[0].spec as GridLayoutItemSpec;
|
||||
expect(layout.state.grid.state.children[0].state.width).toBe(gridLayoutItemSpec.width);
|
||||
@@ -267,9 +266,6 @@ describe('transformSaveModelSchemaV2ToScene', () => {
|
||||
const vizLibraryPanel = vizPanels.find((p) => p.state.key === 'panel-2')!;
|
||||
validateVizPanel(vizLibraryPanel, dash);
|
||||
|
||||
expect((layout.state.grid.state.children[2] as SceneGridRow).state.isCollapsed).toBe(false);
|
||||
expect((layout.state.grid.state.children[2] as SceneGridRow).state.y).toBe(20);
|
||||
|
||||
// Transformations
|
||||
const panelWithTransformations = vizPanels.find((p) => p.state.key === 'panel-1')!;
|
||||
expect((panelWithTransformations.state.$data as SceneDataTransformer)?.state.transformations[0]).toEqual(
|
||||
@@ -300,7 +296,7 @@ describe('transformSaveModelSchemaV2ToScene', () => {
|
||||
const scene = transformSaveModelSchemaV2ToScene(dashboard);
|
||||
|
||||
const vizPanels = (scene.state.body as DashboardLayoutManager).getVizPanels();
|
||||
expect(vizPanels.length).toBe(3);
|
||||
expect(vizPanels.length).toBe(2);
|
||||
expect(getQueryRunnerFor(vizPanels[0])?.state.datasource?.type).toBe('mixed');
|
||||
expect(getQueryRunnerFor(vizPanels[0])?.state.datasource?.uid).toBe(MIXED_DATASOURCE_NAME);
|
||||
});
|
||||
@@ -328,7 +324,7 @@ describe('transformSaveModelSchemaV2ToScene', () => {
|
||||
const scene = transformSaveModelSchemaV2ToScene(dashboard);
|
||||
|
||||
const vizPanels = (scene.state.body as DashboardLayoutManager).getVizPanels();
|
||||
expect(vizPanels.length).toBe(3);
|
||||
expect(vizPanels.length).toBe(2);
|
||||
expect(getQueryRunnerFor(vizPanels[0])?.state.queries[0].datasource).toEqual({
|
||||
type: 'prometheus',
|
||||
uid: 'datasource1',
|
||||
@@ -355,7 +351,7 @@ describe('transformSaveModelSchemaV2ToScene', () => {
|
||||
const scene = transformSaveModelSchemaV2ToScene(dashboard);
|
||||
|
||||
const vizPanels = (scene.state.body as DashboardLayoutManager).getVizPanels();
|
||||
expect(vizPanels.length).toBe(3);
|
||||
expect(vizPanels.length).toBe(2);
|
||||
expect(getQueryRunnerFor(vizPanels[0])?.state.datasource?.type).toBe('mixed');
|
||||
expect(getQueryRunnerFor(vizPanels[0])?.state.datasource?.uid).toBe(MIXED_DATASOURCE_NAME);
|
||||
});
|
||||
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
behaviors,
|
||||
ConstantVariable,
|
||||
SceneDataTransformer,
|
||||
SceneGridItem,
|
||||
SceneGridLayout,
|
||||
SceneGridRow,
|
||||
SceneQueryRunner,
|
||||
@@ -32,6 +33,8 @@ import { PanelTimeRange } from '../scene/PanelTimeRange';
|
||||
import { DashboardGridItem } from '../scene/layout-default/DashboardGridItem';
|
||||
import { DefaultGridLayoutManager } from '../scene/layout-default/DefaultGridLayoutManager';
|
||||
import { RowRepeaterBehavior } from '../scene/layout-default/RowRepeaterBehavior';
|
||||
import { RowItemRepeaterBehavior } from '../scene/layout-rows/RowItemRepeaterBehavior';
|
||||
import { RowsLayoutManager } from '../scene/layout-rows/RowsLayoutManager';
|
||||
import { NEW_LINK } from '../settings/links/utils';
|
||||
import { getQueryRunnerFor } from '../utils/utils';
|
||||
|
||||
@@ -40,6 +43,7 @@ import { GRAFANA_DATASOURCE_REF } from './const';
|
||||
import { SnapshotVariable } from './custom-variables/SnapshotVariable';
|
||||
import dashboard_to_load1 from './testfiles/dashboard_to_load1.json';
|
||||
import repeatingRowsAndPanelsDashboardJson from './testfiles/repeating_rows_and_panels.json';
|
||||
import rowsAfterFreePanels from './testfiles/rows_after_free_panels.json';
|
||||
import {
|
||||
createDashboardSceneFromDashboardModel,
|
||||
buildGridItemForPanel,
|
||||
@@ -809,6 +813,68 @@ describe('transformSaveModelToScene', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('Convert to new rows', () => {
|
||||
beforeEach(() => {
|
||||
// set feature flag to true
|
||||
config.featureToggles.dashboardNewLayouts = true;
|
||||
});
|
||||
afterEach(() => {
|
||||
config.featureToggles.dashboardNewLayouts = false;
|
||||
});
|
||||
|
||||
it('Should convert legacy rows to new rows', () => {
|
||||
const scene = transformSaveModelToScene({
|
||||
dashboard: repeatingRowsAndPanelsDashboardJson as DashboardDataDTO,
|
||||
meta: {},
|
||||
});
|
||||
|
||||
const layout = scene.state.body as RowsLayoutManager;
|
||||
const row1 = layout.state.rows[0];
|
||||
|
||||
expect(row1.state.title).toBe('Row at the top - not repeated - saved expanded');
|
||||
const row1Layout = row1.state.layout as DefaultGridLayoutManager;
|
||||
expect(row1Layout.state.grid.state.children).toHaveLength(1);
|
||||
const row1gridItem = row1Layout.state.grid.state.children[0] as SceneGridItem;
|
||||
expect(row1gridItem.state.body).toBeInstanceOf(VizPanel);
|
||||
const row1Panel = row1gridItem.state.body as VizPanel;
|
||||
expect(row1Panel.state.pluginId).toBe('text');
|
||||
const row1PanelOptions = row1Panel.state.options as { content: string };
|
||||
expect(row1PanelOptions.content).toBe(
|
||||
'<div class=\"center-vh\">\n Repeated row below. The row has \n a panel that is also repeated horizontally based\n on values in the $pod variable. \n</div>'
|
||||
);
|
||||
|
||||
const row2 = layout.state.rows[1];
|
||||
|
||||
expect(row2.state.$behaviors?.[0]).toBeInstanceOf(RowItemRepeaterBehavior);
|
||||
|
||||
const repeatBehavior = row2.state.$behaviors?.[0] as RowItemRepeaterBehavior;
|
||||
expect(repeatBehavior.state.variableName).toBe('server');
|
||||
|
||||
const lastRow = layout.state.rows[layout.state.rows.length - 1];
|
||||
expect(lastRow.state.title).toBe('Row at the bottom - not repeated - saved collapsed ');
|
||||
const lastRowLayout = lastRow.state.layout as DefaultGridLayoutManager;
|
||||
expect(lastRowLayout.state.grid.state.children).toHaveLength(1);
|
||||
const lastRowgridItem = lastRowLayout.state.grid.state.children[0] as SceneGridItem;
|
||||
expect(lastRowgridItem.state.body).toBeInstanceOf(VizPanel);
|
||||
const lastRowPanel = lastRowgridItem.state.body as VizPanel;
|
||||
expect(lastRowPanel.state.pluginId).toBe('text');
|
||||
});
|
||||
|
||||
it('Should convert legacy rows to new rows with free panels before first row', () => {
|
||||
const scene = transformSaveModelToScene({
|
||||
dashboard: rowsAfterFreePanels as DashboardDataDTO,
|
||||
meta: {},
|
||||
});
|
||||
|
||||
const layout = scene.state.body as RowsLayoutManager;
|
||||
const row1 = layout.state.rows[0];
|
||||
expect(row1.state.title).toBe('');
|
||||
expect(row1.state.hideHeader).toBe(true);
|
||||
const row1Layout = row1.state.layout as DefaultGridLayoutManager;
|
||||
expect(row1Layout.state.grid.state.children).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Repeating rows', () => {
|
||||
it('Should build correct scene model', () => {
|
||||
const scene = transformSaveModelToScene({
|
||||
|
||||
@@ -44,7 +44,11 @@ import { DashboardGridItem, RepeatDirection } from '../scene/layout-default/Dash
|
||||
import { DefaultGridLayoutManager } from '../scene/layout-default/DefaultGridLayoutManager';
|
||||
import { RowRepeaterBehavior } from '../scene/layout-default/RowRepeaterBehavior';
|
||||
import { RowActions } from '../scene/layout-default/row-actions/RowActions';
|
||||
import { RowItem } from '../scene/layout-rows/RowItem';
|
||||
import { RowItemRepeaterBehavior } from '../scene/layout-rows/RowItemRepeaterBehavior';
|
||||
import { RowsLayoutManager } from '../scene/layout-rows/RowsLayoutManager';
|
||||
import { setDashboardPanelContext } from '../scene/setDashboardPanelContext';
|
||||
import { DashboardLayoutManager } from '../scene/types/DashboardLayoutManager';
|
||||
import { createPanelDataProvider } from '../utils/createPanelDataProvider';
|
||||
import { DashboardInteractions } from '../utils/interactions';
|
||||
import { getVizPanelKeyForPanelId } from '../utils/utils';
|
||||
@@ -79,6 +83,56 @@ export function transformSaveModelToScene(rsp: DashboardDTO): DashboardScene {
|
||||
return scene;
|
||||
}
|
||||
|
||||
export function createRowsFromPanels(oldPanels: PanelModel[]): RowsLayoutManager {
|
||||
const rowItems: RowItem[] = [];
|
||||
|
||||
let currentLegacyRow: PanelModel | null = null;
|
||||
let currentRowPanels: DashboardGridItem[] = [];
|
||||
|
||||
for (const panel of oldPanels) {
|
||||
if (panel.type === 'row') {
|
||||
if (!currentLegacyRow && currentRowPanels.length === 0) {
|
||||
// This is the first row, and we have no panels before it. We set currentLegacyRow to the first row.
|
||||
currentLegacyRow = panel;
|
||||
} else if (!currentLegacyRow) {
|
||||
// This is the first row but we have panels before the first row. We should flush the current panels into a row item with header hidden.
|
||||
rowItems.push(
|
||||
new RowItem({
|
||||
title: '',
|
||||
collapse: panel.collapsed,
|
||||
layout: new DefaultGridLayoutManager({
|
||||
grid: new SceneGridLayout({
|
||||
children: currentRowPanels,
|
||||
}),
|
||||
}),
|
||||
hideHeader: true,
|
||||
$behaviors: [],
|
||||
})
|
||||
);
|
||||
currentRowPanels = [];
|
||||
|
||||
currentLegacyRow = panel;
|
||||
} else {
|
||||
// This is a new row. We should flush the current panels into a row item.
|
||||
rowItems.push(createRowItemFromLegacyRow(currentLegacyRow, currentRowPanels));
|
||||
currentRowPanels = [];
|
||||
currentLegacyRow = panel;
|
||||
}
|
||||
} else {
|
||||
currentRowPanels.push(buildGridItemForPanel(panel));
|
||||
}
|
||||
}
|
||||
|
||||
if (currentLegacyRow) {
|
||||
// If there is a row left to process, we should flush it into a row item.
|
||||
rowItems.push(createRowItemFromLegacyRow(currentLegacyRow, currentRowPanels));
|
||||
}
|
||||
|
||||
return new RowsLayoutManager({
|
||||
rows: rowItems,
|
||||
});
|
||||
}
|
||||
|
||||
export function createSceneObjectsForPanels(oldPanels: PanelModel[]): SceneGridItemLike[] {
|
||||
// collects all panels and rows
|
||||
const panels: SceneGridItemLike[] = [];
|
||||
@@ -174,6 +228,22 @@ function createRowFromPanelModel(row: PanelModel, content: SceneGridItemLike[]):
|
||||
});
|
||||
}
|
||||
|
||||
function createRowItemFromLegacyRow(row: PanelModel, panels: DashboardGridItem[]): RowItem {
|
||||
const rowItem = new RowItem({
|
||||
key: getVizPanelKeyForPanelId(row.id),
|
||||
title: row.title,
|
||||
collapse: row.collapsed,
|
||||
layout: new DefaultGridLayoutManager({
|
||||
grid: new SceneGridLayout({
|
||||
// If the row is collapsed it will have panels within the row model.
|
||||
children: (row.panels?.map((p) => buildGridItemForPanel(p)) ?? []).concat(panels),
|
||||
}),
|
||||
}),
|
||||
$behaviors: row.repeat ? [new RowItemRepeaterBehavior({ variableName: row.repeat })] : undefined,
|
||||
});
|
||||
return rowItem;
|
||||
}
|
||||
|
||||
export function createDashboardSceneFromDashboardModel(oldModel: DashboardModel, dto: DashboardDataDTO) {
|
||||
let variables: SceneVariableSet | undefined;
|
||||
let annotationLayers: SceneDataLayerProvider[] = [];
|
||||
@@ -241,6 +311,20 @@ export function createDashboardSceneFromDashboardModel(oldModel: DashboardModel,
|
||||
version: oldModel.version,
|
||||
}),
|
||||
];
|
||||
|
||||
let body: DashboardLayoutManager;
|
||||
|
||||
if (config.featureToggles.dashboardNewLayouts && oldModel.panels.some((p) => p.type === 'row')) {
|
||||
body = createRowsFromPanels(oldModel.panels);
|
||||
} else {
|
||||
body = new DefaultGridLayoutManager({
|
||||
grid: new SceneGridLayout({
|
||||
isLazy: !(dto.preload || contextSrv.user.authenticatedBy === 'render'),
|
||||
children: createSceneObjectsForPanels(oldModel.panels),
|
||||
}),
|
||||
});
|
||||
}
|
||||
|
||||
const dashboardScene = new DashboardScene(
|
||||
{
|
||||
uid,
|
||||
@@ -255,12 +339,7 @@ export function createDashboardSceneFromDashboardModel(oldModel: DashboardModel,
|
||||
title: oldModel.title,
|
||||
version: oldModel.version,
|
||||
scopeMeta,
|
||||
body: new DefaultGridLayoutManager({
|
||||
grid: new SceneGridLayout({
|
||||
isLazy: !(dto.preload || contextSrv.user.authenticatedBy === 'render'),
|
||||
children: createSceneObjectsForPanels(oldModel.panels),
|
||||
}),
|
||||
}),
|
||||
body,
|
||||
$timeRange: new SceneTimeRange({
|
||||
from: oldModel.time.from,
|
||||
to: oldModel.time.to,
|
||||
|
||||
-26
@@ -10,7 +10,6 @@ import {
|
||||
IntervalVariable,
|
||||
QueryVariable,
|
||||
SceneGridLayout,
|
||||
SceneGridRow,
|
||||
SceneRefreshPicker,
|
||||
SceneTimePicker,
|
||||
SceneTimeRange,
|
||||
@@ -45,7 +44,6 @@ import { AutoGridLayout } from '../scene/layout-auto-grid/AutoGridLayout';
|
||||
import { AutoGridLayoutManager } from '../scene/layout-auto-grid/AutoGridLayoutManager';
|
||||
import { DashboardGridItem } from '../scene/layout-default/DashboardGridItem';
|
||||
import { DefaultGridLayoutManager } from '../scene/layout-default/DefaultGridLayoutManager';
|
||||
import { RowRepeaterBehavior } from '../scene/layout-default/RowRepeaterBehavior';
|
||||
import { RowItem } from '../scene/layout-rows/RowItem';
|
||||
import { RowsLayoutManager } from '../scene/layout-rows/RowsLayoutManager';
|
||||
import { TabItem } from '../scene/layout-tabs/TabItem';
|
||||
@@ -254,30 +252,6 @@ describe('transformSceneToSaveModelSchemaV2', () => {
|
||||
// repeatDirection?: RepeatDirection,
|
||||
// maxPerRow?: number,
|
||||
}),
|
||||
new SceneGridRow({
|
||||
key: 'panel-4',
|
||||
title: 'Test Row',
|
||||
y: 10,
|
||||
$behaviors: [new RowRepeaterBehavior({ variableName: 'customVar' })],
|
||||
children: [
|
||||
new DashboardGridItem({
|
||||
y: 11,
|
||||
body: new VizPanel({
|
||||
key: 'panel-2',
|
||||
pluginId: 'graph',
|
||||
title: 'Test Panel 2',
|
||||
description: 'Test Description 2',
|
||||
fieldConfig: { defaults: {}, overrides: [] },
|
||||
pluginVersion: '7.0.0',
|
||||
$timeRange: new SceneTimeRange({
|
||||
timeZone: 'UTC',
|
||||
from: 'now-3h',
|
||||
to: 'now',
|
||||
}),
|
||||
}),
|
||||
}),
|
||||
],
|
||||
}),
|
||||
],
|
||||
}),
|
||||
}),
|
||||
|
||||
@@ -3,10 +3,10 @@ import { handyTestingSchema } from '@grafana/schema/dist/esm/schema/dashboard/v2
|
||||
import {
|
||||
Spec as DashboardV2Spec,
|
||||
GridLayoutItemKind,
|
||||
GridLayoutItemSpec,
|
||||
GridLayoutKind,
|
||||
GridLayoutRowSpec,
|
||||
PanelKind,
|
||||
RowsLayoutKind,
|
||||
RowsLayoutRowKind,
|
||||
VariableKind,
|
||||
} from '@grafana/schema/dist/esm/schema/dashboard/v2alpha1/types.spec.gen';
|
||||
import {
|
||||
@@ -352,76 +352,6 @@ describe('ResponseTransformers', () => {
|
||||
},
|
||||
gridPos: { x: 0, y: 8, w: 12, h: 8 },
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
type: 'row',
|
||||
title: 'Row test title',
|
||||
gridPos: { x: 0, y: 16, w: 12, h: 1 },
|
||||
panels: [],
|
||||
collapsed: false,
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
type: 'timeseries',
|
||||
title: 'Panel in row',
|
||||
gridPos: { x: 0, y: 17, w: 16, h: 8 },
|
||||
targets: [
|
||||
{
|
||||
refId: 'A',
|
||||
datasource: 'datasource1',
|
||||
expr: 'test-query',
|
||||
hide: false,
|
||||
},
|
||||
],
|
||||
datasource: {
|
||||
type: 'prometheus',
|
||||
uid: 'datasource1',
|
||||
},
|
||||
fieldConfig: { defaults: {}, overrides: [] },
|
||||
options: {},
|
||||
transparent: false,
|
||||
links: [],
|
||||
transformations: [],
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
type: 'row',
|
||||
title: 'Collapsed row title',
|
||||
gridPos: { x: 0, y: 25, w: 12, h: 1 },
|
||||
panels: [
|
||||
{
|
||||
id: 5,
|
||||
type: 'timeseries',
|
||||
title: 'Panel in collapsed row',
|
||||
gridPos: { x: 0, y: 26, w: 16, h: 8 },
|
||||
targets: [
|
||||
{
|
||||
refId: 'A',
|
||||
datasource: 'datasource1',
|
||||
expr: 'test-query',
|
||||
hide: false,
|
||||
},
|
||||
],
|
||||
datasource: {
|
||||
type: 'prometheus',
|
||||
uid: 'datasource1',
|
||||
},
|
||||
fieldConfig: { defaults: {}, overrides: [] },
|
||||
options: {},
|
||||
transparent: false,
|
||||
links: [],
|
||||
transformations: [],
|
||||
},
|
||||
],
|
||||
collapsed: true,
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
type: 'row',
|
||||
title: 'Row with no panel property',
|
||||
gridPos: { x: 0, y: 25, w: 12, h: 1 },
|
||||
collapsed: true,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
@@ -499,7 +429,7 @@ describe('ResponseTransformers', () => {
|
||||
// Panel
|
||||
expect(spec.layout.kind).toBe('GridLayout');
|
||||
const layout = spec.layout as GridLayoutKind;
|
||||
expect(layout.spec.items).toHaveLength(5);
|
||||
expect(layout.spec.items).toHaveLength(2);
|
||||
expect(layout.spec.items[0].spec).toEqual({
|
||||
element: {
|
||||
kind: 'ElementReference',
|
||||
@@ -585,48 +515,6 @@ describe('ResponseTransformers', () => {
|
||||
},
|
||||
});
|
||||
|
||||
const rowSpec = layout.spec.items[2].spec as GridLayoutRowSpec;
|
||||
|
||||
expect(rowSpec.collapsed).toBe(false);
|
||||
expect(rowSpec.title).toBe('Row test title');
|
||||
expect(rowSpec.repeat).toBeUndefined();
|
||||
|
||||
const panelInRow = rowSpec.elements[0].spec as GridLayoutItemSpec;
|
||||
|
||||
expect(panelInRow).toEqual({
|
||||
element: {
|
||||
kind: 'ElementReference',
|
||||
name: 'panel-4',
|
||||
},
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: 16,
|
||||
height: 8,
|
||||
});
|
||||
|
||||
const collapsedRowSpec = layout.spec.items[3].spec as GridLayoutRowSpec;
|
||||
expect(collapsedRowSpec.collapsed).toBe(true);
|
||||
expect(collapsedRowSpec.title).toBe('Collapsed row title');
|
||||
expect(collapsedRowSpec.repeat).toBeUndefined();
|
||||
|
||||
const panelInCollapsedRow = collapsedRowSpec.elements[0].spec as GridLayoutItemSpec;
|
||||
|
||||
expect(panelInCollapsedRow).toEqual({
|
||||
element: {
|
||||
kind: 'ElementReference',
|
||||
name: 'panel-5',
|
||||
},
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: 16,
|
||||
height: 8,
|
||||
});
|
||||
|
||||
const rowWithNoPanelProperty = layout.spec.items[4].spec as GridLayoutRowSpec;
|
||||
expect(rowWithNoPanelProperty.collapsed).toBe(true);
|
||||
expect(rowWithNoPanelProperty.title).toBe('Row with no panel property');
|
||||
expect(rowWithNoPanelProperty.elements).toHaveLength(0);
|
||||
|
||||
// Variables
|
||||
validateVariablesV1ToV2(spec.variables[0], dashboardV1.templating?.list?.[0]);
|
||||
validateVariablesV1ToV2(spec.variables[1], dashboardV1.templating?.list?.[1]);
|
||||
@@ -640,6 +528,254 @@ describe('ResponseTransformers', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('v1 -> v2 transformation with rows', () => {
|
||||
it('should transform DashboardDTO to DashboardWithAccessInfo<DashboardV2Spec>', () => {
|
||||
const dashboardV1: DashboardDataDTO = {
|
||||
uid: 'dashboard-uid',
|
||||
id: 123,
|
||||
title: 'Dashboard Title',
|
||||
description: 'Dashboard Description',
|
||||
tags: ['tag1', 'tag2'],
|
||||
schemaVersion: 1,
|
||||
graphTooltip: 0,
|
||||
preload: true,
|
||||
liveNow: false,
|
||||
editable: true,
|
||||
time: { from: 'now-6h', to: 'now' },
|
||||
timezone: 'browser',
|
||||
refresh: '5m',
|
||||
timepicker: {
|
||||
refresh_intervals: ['5s', '10s', '30s'],
|
||||
hidden: false,
|
||||
nowDelay: '1m',
|
||||
quick_ranges: [
|
||||
{
|
||||
display: 'Last 6 hours',
|
||||
from: 'now-6h',
|
||||
to: 'now',
|
||||
},
|
||||
{
|
||||
display: 'Last 7 days',
|
||||
from: 'now-7d',
|
||||
to: 'now',
|
||||
},
|
||||
],
|
||||
},
|
||||
fiscalYearStartMonth: 1,
|
||||
weekStart: 'monday',
|
||||
version: 1,
|
||||
gnetId: 'something-like-a-uid',
|
||||
revision: 225,
|
||||
links: [],
|
||||
annotations: {
|
||||
list: [],
|
||||
},
|
||||
templating: {
|
||||
list: [],
|
||||
},
|
||||
panels: [
|
||||
{
|
||||
id: 1,
|
||||
type: 'timeseries',
|
||||
title: 'Panel Title',
|
||||
gridPos: { x: 0, y: 0, w: 12, h: 8 },
|
||||
targets: [
|
||||
{
|
||||
refId: 'A',
|
||||
datasource: 'datasource1',
|
||||
expr: 'test-query',
|
||||
hide: false,
|
||||
},
|
||||
],
|
||||
datasource: {
|
||||
type: 'prometheus',
|
||||
uid: 'datasource1',
|
||||
},
|
||||
fieldConfig: { defaults: {}, overrides: [] },
|
||||
options: {},
|
||||
transparent: false,
|
||||
links: [],
|
||||
transformations: [],
|
||||
repeat: 'var1',
|
||||
repeatDirection: 'h',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
type: 'table',
|
||||
title: 'Just a shared table',
|
||||
libraryPanel: {
|
||||
uid: 'library-panel-table',
|
||||
name: 'Table Panel as Library Panel',
|
||||
},
|
||||
gridPos: { x: 0, y: 8, w: 12, h: 8 },
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
type: 'row',
|
||||
title: 'Row test title',
|
||||
gridPos: { x: 0, y: 16, w: 12, h: 1 },
|
||||
repeat: 'var1',
|
||||
repeatDirection: 'v',
|
||||
panels: [],
|
||||
collapsed: false,
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
type: 'timeseries',
|
||||
title: 'Panel in row',
|
||||
gridPos: { x: 0, y: 17, w: 16, h: 8 },
|
||||
targets: [
|
||||
{
|
||||
refId: 'A',
|
||||
datasource: 'datasource1',
|
||||
expr: 'test-query',
|
||||
hide: false,
|
||||
},
|
||||
],
|
||||
datasource: {
|
||||
type: 'prometheus',
|
||||
uid: 'datasource1',
|
||||
},
|
||||
fieldConfig: { defaults: {}, overrides: [] },
|
||||
options: {},
|
||||
transparent: false,
|
||||
links: [],
|
||||
transformations: [],
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
type: 'row',
|
||||
title: 'Collapsed row title',
|
||||
gridPos: { x: 0, y: 25, w: 12, h: 1 },
|
||||
panels: [
|
||||
{
|
||||
id: 6,
|
||||
type: 'timeseries',
|
||||
title: 'Panel in collapsed row',
|
||||
gridPos: { x: 0, y: 26, w: 16, h: 8 },
|
||||
targets: [
|
||||
{
|
||||
refId: 'A',
|
||||
datasource: 'datasource1',
|
||||
expr: 'test-query',
|
||||
hide: false,
|
||||
},
|
||||
],
|
||||
datasource: {
|
||||
type: 'prometheus',
|
||||
uid: 'datasource1',
|
||||
},
|
||||
fieldConfig: { defaults: {}, overrides: [] },
|
||||
options: {},
|
||||
transparent: false,
|
||||
links: [],
|
||||
transformations: [],
|
||||
},
|
||||
],
|
||||
collapsed: true,
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
type: 'row',
|
||||
title: 'collapsed row with no panel property',
|
||||
gridPos: { x: 0, y: 26, w: 12, h: 1 },
|
||||
collapsed: true,
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
type: 'row',
|
||||
title: 'empty row',
|
||||
gridPos: { x: 0, y: 27, w: 12, h: 1 },
|
||||
collapsed: false,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const dto: DashboardWithAccessInfo<DashboardDataDTO> = {
|
||||
spec: dashboardV1,
|
||||
access: {
|
||||
slug: 'dashboard-slug',
|
||||
url: '/d/dashboard-slug',
|
||||
canAdmin: true,
|
||||
canDelete: true,
|
||||
canEdit: true,
|
||||
canSave: true,
|
||||
canShare: true,
|
||||
canStar: true,
|
||||
annotationsPermissions: {
|
||||
dashboard: { canAdd: true, canEdit: true, canDelete: true },
|
||||
organization: { canAdd: true, canEdit: true, canDelete: true },
|
||||
},
|
||||
},
|
||||
apiVersion: 'v1',
|
||||
kind: 'DashboardWithAccessInfo',
|
||||
metadata: {
|
||||
name: 'dashboard-uid',
|
||||
resourceVersion: '1',
|
||||
creationTimestamp: '2023-01-01T00:00:00Z',
|
||||
annotations: {
|
||||
[AnnoKeyCreatedBy]: 'user1',
|
||||
[AnnoKeyUpdatedBy]: 'user2',
|
||||
[AnnoKeyUpdatedTimestamp]: '2023-01-02T00:00:00Z',
|
||||
[AnnoKeyFolder]: 'folder1',
|
||||
[AnnoKeySlug]: 'dashboard-slug',
|
||||
},
|
||||
labels: {
|
||||
[DeprecatedInternalId]: '123',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const transformed = ResponseTransformers.ensureV2Response(dto);
|
||||
|
||||
const spec = transformed.spec;
|
||||
|
||||
// Panel
|
||||
expect(spec.layout.kind).toBe('RowsLayout');
|
||||
const layout = spec.layout as RowsLayoutKind;
|
||||
expect(layout.spec.rows).toHaveLength(5);
|
||||
|
||||
const row0grid = layout.spec.rows[0].spec.layout as GridLayoutKind;
|
||||
expect(row0grid.kind).toBe('GridLayout');
|
||||
expect(row0grid.spec.items).toHaveLength(2);
|
||||
expect(row0grid.spec.items[0].spec.element.name).toBe('panel-1');
|
||||
expect(row0grid.spec.items[0].spec.y).toBe(0);
|
||||
expect(row0grid.spec.items[1].spec.element.name).toBe('panel-2');
|
||||
expect(row0grid.spec.items[1].spec.y).toBe(8);
|
||||
|
||||
const row1 = layout.spec.rows[1] as RowsLayoutRowKind;
|
||||
expect(row1.kind).toBe('RowsLayoutRow');
|
||||
expect(row1.spec.repeat?.value).toBe('var1');
|
||||
expect(row1.spec.repeat?.mode).toBe('variable');
|
||||
|
||||
const row1grid = layout.spec.rows[1].spec.layout as GridLayoutKind;
|
||||
expect(row1grid.kind).toBe('GridLayout');
|
||||
expect(row1grid.spec.items).toHaveLength(1);
|
||||
expect(row1grid.spec.items[0].spec.element.name).toBe('panel-4');
|
||||
|
||||
const row2grid = layout.spec.rows[2].spec.layout as GridLayoutKind;
|
||||
expect(row2grid.kind).toBe('GridLayout');
|
||||
expect(row2grid.spec.items).toHaveLength(1);
|
||||
expect(row2grid.spec.items[0].spec.element.name).toBe('panel-6');
|
||||
|
||||
const row3 = layout.spec.rows[3] as RowsLayoutRowKind;
|
||||
expect(row3.kind).toBe('RowsLayoutRow');
|
||||
expect(row3.spec.collapse).toBe(true);
|
||||
expect(row3.spec.layout.kind).toBe('GridLayout');
|
||||
const row3grid = row3.spec.layout as GridLayoutKind;
|
||||
expect(row3grid.kind).toBe('GridLayout');
|
||||
expect(row3grid.spec.items).toHaveLength(0);
|
||||
|
||||
const row4 = layout.spec.rows[4] as RowsLayoutRowKind;
|
||||
expect(row4.kind).toBe('RowsLayoutRow');
|
||||
expect(row4.spec.collapse).toBe(false);
|
||||
expect(row4.spec.layout.kind).toBe('GridLayout');
|
||||
const row4grid = row4.spec.layout as GridLayoutKind;
|
||||
expect(row4grid.kind).toBe('GridLayout');
|
||||
expect(row4grid.spec.items).toHaveLength(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('v2 -> v1 transformation', () => {
|
||||
it('should return the same object if it is already a DashboardDTO', () => {
|
||||
const dashboard: DashboardDTO = {
|
||||
@@ -804,9 +940,6 @@ describe('ResponseTransformers', () => {
|
||||
uid: 'uid-for-library-panel',
|
||||
name: 'Library Panel',
|
||||
});
|
||||
expect(dashboard.panels![2].type).toBe('row');
|
||||
expect(dashboard.panels![2].id).toBe(4); // Row id should be assigned to unique number following the highest id of panels.
|
||||
expect(dashboard.panels![3].type).toBe('timeseries');
|
||||
});
|
||||
|
||||
describe('getPanelQueries', () => {
|
||||
|
||||
@@ -37,8 +37,9 @@ import {
|
||||
GroupByVariableKind,
|
||||
LibraryPanelKind,
|
||||
PanelKind,
|
||||
GridLayoutRowKind,
|
||||
GridLayoutItemKind,
|
||||
RowsLayoutRowKind,
|
||||
GridLayoutKind,
|
||||
} from '@grafana/schema/dist/esm/schema/dashboard/v2alpha1/types.spec.gen';
|
||||
import { DashboardLink, DataTransformerConfig } from '@grafana/schema/src/raw/dashboard/x/dashboard_types.gen';
|
||||
import { isWeekStart, WeekStart } from '@grafana/ui';
|
||||
@@ -259,22 +260,49 @@ function getElementsFromPanels(
|
||||
return [elements, layout];
|
||||
}
|
||||
|
||||
let currentRow: GridLayoutRowKind | null = null;
|
||||
if (panels.some(isRowPanel)) {
|
||||
return convertToRowsLayout(panels);
|
||||
}
|
||||
|
||||
// iterate over panels
|
||||
for (const p of panels) {
|
||||
const [element, elementName] = buildElement(p);
|
||||
|
||||
elements[elementName] = element;
|
||||
|
||||
layout.spec.items.push(buildGridItemKind(p, elementName));
|
||||
}
|
||||
|
||||
return [elements, layout];
|
||||
}
|
||||
|
||||
function convertToRowsLayout(
|
||||
panels: Array<Panel | RowPanel>
|
||||
): [DashboardV2Spec['elements'], DashboardV2Spec['layout']] {
|
||||
let currentRow: RowsLayoutRowKind | null = null;
|
||||
let legacyRowY = 0;
|
||||
const elements: DashboardV2Spec['elements'] = {};
|
||||
const layout: DashboardV2Spec['layout'] = {
|
||||
kind: 'RowsLayout',
|
||||
spec: {
|
||||
rows: [],
|
||||
},
|
||||
};
|
||||
|
||||
for (const p of panels) {
|
||||
if (isRowPanel(p)) {
|
||||
legacyRowY = p.gridPos!.y;
|
||||
if (currentRow) {
|
||||
// Flush current row to layout before we create a new one
|
||||
layout.spec.items.push(currentRow);
|
||||
layout.spec.rows.push(currentRow);
|
||||
}
|
||||
|
||||
// If the row is collapsed it will have panels
|
||||
const rowElements = [];
|
||||
|
||||
for (const panel of p.panels || []) {
|
||||
const [element, name] = buildElement(panel);
|
||||
elements[name] = element;
|
||||
rowElements.push(buildGridItemKind(panel, name, yOffsetInRows(panel, p.gridPos!.y)));
|
||||
rowElements.push(buildGridItemKind(panel, name, yOffsetInRows(panel, legacyRowY)));
|
||||
}
|
||||
|
||||
currentRow = buildRowKind(p, rowElements);
|
||||
@@ -285,18 +313,41 @@ function getElementsFromPanels(
|
||||
|
||||
if (currentRow) {
|
||||
// Collect panels to current layout row
|
||||
currentRow.spec.elements.push(buildGridItemKind(p, elementName, yOffsetInRows(p, currentRow.spec.y)));
|
||||
if (currentRow.spec.layout.kind === 'GridLayout') {
|
||||
currentRow.spec.layout.spec.items.push(buildGridItemKind(p, elementName, yOffsetInRows(p, legacyRowY)));
|
||||
} else {
|
||||
throw new Error('RowsLayoutRow from legacy row must have a GridLayout');
|
||||
}
|
||||
} else {
|
||||
layout.spec.items.push(buildGridItemKind(p, elementName));
|
||||
// This is the first row. In V1 these items could live outside of a row. In V2 they will be in a row with header hidden so that it will look similar to V1.
|
||||
const grid: GridLayoutKind = {
|
||||
kind: 'GridLayout',
|
||||
spec: {
|
||||
items: [buildGridItemKind(p, elementName)],
|
||||
},
|
||||
};
|
||||
|
||||
// Since this row does not exist in V1, we simulate it being outside of the grid above the first panel
|
||||
// The Y position does not matter for the rows layout, but it's used to calculate the position of the panels in the grid layout in the row.
|
||||
legacyRowY = -1;
|
||||
|
||||
currentRow = {
|
||||
kind: 'RowsLayoutRow',
|
||||
spec: {
|
||||
collapse: false,
|
||||
title: '',
|
||||
hideHeader: true,
|
||||
layout: grid,
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (currentRow) {
|
||||
// Flush last row to layout
|
||||
layout.spec.items.push(currentRow);
|
||||
layout.spec.rows.push(currentRow);
|
||||
}
|
||||
|
||||
return [elements, layout];
|
||||
}
|
||||
|
||||
@@ -311,15 +362,19 @@ function getWeekStart(weekStart?: string, defaultWeekStart?: WeekStart): WeekSta
|
||||
return weekStart;
|
||||
}
|
||||
|
||||
function buildRowKind(p: RowPanel, elements: GridLayoutItemKind[]): GridLayoutRowKind {
|
||||
function buildRowKind(p: RowPanel, elements: GridLayoutItemKind[]): RowsLayoutRowKind {
|
||||
return {
|
||||
kind: 'GridLayoutRow',
|
||||
kind: 'RowsLayoutRow',
|
||||
spec: {
|
||||
collapsed: p.collapsed,
|
||||
collapse: p.collapsed,
|
||||
title: p.title ?? '',
|
||||
repeat: p.repeat ? { value: p.repeat, mode: 'variable' } : undefined,
|
||||
y: p.gridPos?.y ?? 0,
|
||||
elements,
|
||||
layout: {
|
||||
kind: 'GridLayout',
|
||||
spec: {
|
||||
items: elements,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -849,46 +904,11 @@ function getPanelsV1(
|
||||
}
|
||||
|
||||
for (const item of layout.spec.items) {
|
||||
if (item.kind === 'GridLayoutItem') {
|
||||
const panel = panels[item.spec.element.name];
|
||||
const v1Panel = transformV2PanelToV1Panel(panel, item);
|
||||
panelsV1.push(v1Panel);
|
||||
if (v1Panel.id ?? 0 > maxPanelId) {
|
||||
maxPanelId = v1Panel.id ?? 0;
|
||||
}
|
||||
} else if (item.kind === 'GridLayoutRow') {
|
||||
const row: RowPanel = {
|
||||
id: -1, // Temporarily set to -1, updated later to be unique
|
||||
type: 'row',
|
||||
title: item.spec.title,
|
||||
collapsed: item.spec.collapsed,
|
||||
repeat: item.spec.repeat ? item.spec.repeat.value : undefined,
|
||||
gridPos: {
|
||||
x: 0,
|
||||
y: item.spec.y,
|
||||
w: 24,
|
||||
h: GRID_ROW_HEIGHT,
|
||||
},
|
||||
panels: [],
|
||||
};
|
||||
|
||||
const rowPanels = [];
|
||||
for (const panel of item.spec.elements) {
|
||||
const panelElement = panels[panel.spec.element.name];
|
||||
const v1Panel = transformV2PanelToV1Panel(panelElement, panel, item.spec.y + GRID_ROW_HEIGHT + panel.spec.y);
|
||||
rowPanels.push(v1Panel);
|
||||
if (v1Panel.id ?? 0 > maxPanelId) {
|
||||
maxPanelId = v1Panel.id ?? 0;
|
||||
}
|
||||
}
|
||||
if (item.spec.collapsed) {
|
||||
// When a row is collapsed, panels inside it are stored in the panels property.
|
||||
row.panels = rowPanels;
|
||||
panelsV1.push(row);
|
||||
} else {
|
||||
panelsV1.push(row);
|
||||
panelsV1.push(...rowPanels);
|
||||
}
|
||||
const panel = panels[item.spec.element.name];
|
||||
const v1Panel = transformV2PanelToV1Panel(panel, item);
|
||||
panelsV1.push(v1Panel);
|
||||
if (v1Panel.id ?? 0 > maxPanelId) {
|
||||
maxPanelId = v1Panel.id ?? 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user