Dynamic dashboards: Refactor serializing and deserializing layout managers to simplify (#103008)
Refactor serializing and deserializing layout managers to simplify
This commit is contained in:
+6
-1
@@ -12,6 +12,7 @@ import {
|
||||
useSceneObjectState,
|
||||
SceneGridLayoutDragStartEvent,
|
||||
} from '@grafana/scenes';
|
||||
import { DashboardV2Spec } from '@grafana/schema/dist/esm/schema/dashboard/v2alpha0';
|
||||
import { GRID_COLUMN_COUNT } from 'app/core/constants';
|
||||
import { t } from 'app/core/internationalization';
|
||||
import DashboardEmpty from 'app/features/dashboard/dashgrid/DashboardEmpty';
|
||||
@@ -21,6 +22,7 @@ import {
|
||||
ObjectRemovedFromCanvasEvent,
|
||||
ObjectsReorderedOnCanvasEvent,
|
||||
} from '../../edit-pane/shared';
|
||||
import { serializeDefaultGridLayout } from '../../serialization/layoutSerializers/DefaultGridLayoutSerializer';
|
||||
import { isClonedKey, joinCloneKeys } from '../../utils/clone';
|
||||
import { dashboardSceneGraph } from '../../utils/dashboardSceneGraph';
|
||||
import {
|
||||
@@ -61,10 +63,13 @@ export class DefaultGridLayoutManager
|
||||
},
|
||||
id: 'default-grid',
|
||||
createFromLayout: DefaultGridLayoutManager.createFromLayout,
|
||||
kind: 'GridLayout',
|
||||
isGridLayout: true,
|
||||
};
|
||||
|
||||
public serialize(): DashboardV2Spec['layout'] {
|
||||
return serializeDefaultGridLayout(this);
|
||||
}
|
||||
|
||||
public readonly descriptor = DefaultGridLayoutManager.descriptor;
|
||||
|
||||
public constructor(state: DefaultGridLayoutManagerState) {
|
||||
|
||||
+6
-1
@@ -1,9 +1,11 @@
|
||||
import { SceneComponentProps, SceneObjectBase, SceneObjectState, VizPanel } from '@grafana/scenes';
|
||||
import { DashboardV2Spec } from '@grafana/schema/dist/esm/schema/dashboard/v2alpha0';
|
||||
import { GRID_CELL_VMARGIN } from 'app/core/constants';
|
||||
import { t } from 'app/core/internationalization';
|
||||
import { OptionsPaneItemDescriptor } from 'app/features/dashboard/components/PanelEditor/OptionsPaneItemDescriptor';
|
||||
|
||||
import { NewObjectAddedToCanvasEvent, ObjectRemovedFromCanvasEvent } from '../../edit-pane/shared';
|
||||
import { serializeAutoGridLayout } from '../../serialization/layoutSerializers/ResponsiveGridLayoutSerializer';
|
||||
import { joinCloneKeys } from '../../utils/clone';
|
||||
import { dashboardSceneGraph } from '../../utils/dashboardSceneGraph';
|
||||
import {
|
||||
@@ -52,10 +54,13 @@ export class AutoGridLayoutManager
|
||||
},
|
||||
id: 'auto-grid',
|
||||
createFromLayout: AutoGridLayoutManager.createFromLayout,
|
||||
kind: 'AutoGridLayout',
|
||||
isGridLayout: true,
|
||||
};
|
||||
|
||||
public serialize(): DashboardV2Spec['layout'] {
|
||||
return serializeAutoGridLayout(this);
|
||||
}
|
||||
|
||||
public readonly descriptor = AutoGridLayoutManager.descriptor;
|
||||
|
||||
public constructor(state: Partial<AutoGridLayoutManagerState>) {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { SceneGridItemLike, SceneGridRow, SceneObjectBase, SceneObjectState, VizPanel } from '@grafana/scenes';
|
||||
import { DashboardV2Spec } from '@grafana/schema/dist/esm/schema/dashboard/v2alpha0';
|
||||
import { t } from 'app/core/internationalization';
|
||||
|
||||
import {
|
||||
@@ -6,6 +7,7 @@ import {
|
||||
ObjectRemovedFromCanvasEvent,
|
||||
ObjectsReorderedOnCanvasEvent,
|
||||
} from '../../edit-pane/shared';
|
||||
import { serializeRowsLayout } from '../../serialization/layoutSerializers/RowsLayoutSerializer';
|
||||
import { isClonedKey } from '../../utils/clone';
|
||||
import { dashboardSceneGraph } from '../../utils/dashboardSceneGraph';
|
||||
import { DashboardGridItem } from '../layout-default/DashboardGridItem';
|
||||
@@ -37,10 +39,13 @@ export class RowsLayoutManager extends SceneObjectBase<RowsLayoutManagerState> i
|
||||
},
|
||||
id: 'rows-layout',
|
||||
createFromLayout: RowsLayoutManager.createFromLayout,
|
||||
kind: 'RowsLayout',
|
||||
isGridLayout: false,
|
||||
};
|
||||
|
||||
public serialize(): DashboardV2Spec['layout'] {
|
||||
return serializeRowsLayout(this);
|
||||
}
|
||||
|
||||
public readonly descriptor = RowsLayoutManager.descriptor;
|
||||
|
||||
public addPanel(vizPanel: VizPanel) {
|
||||
|
||||
@@ -5,6 +5,7 @@ import {
|
||||
SceneObjectUrlValues,
|
||||
VizPanel,
|
||||
} from '@grafana/scenes';
|
||||
import { DashboardV2Spec } from '@grafana/schema/dist/esm/schema/dashboard/v2alpha0';
|
||||
import { t } from 'app/core/internationalization';
|
||||
|
||||
import {
|
||||
@@ -12,6 +13,7 @@ import {
|
||||
ObjectRemovedFromCanvasEvent,
|
||||
ObjectsReorderedOnCanvasEvent,
|
||||
} from '../../edit-pane/shared';
|
||||
import { serializeTabsLayout } from '../../serialization/layoutSerializers/TabsLayoutSerializer';
|
||||
import { RowItem } from '../layout-rows/RowItem';
|
||||
import { RowsLayoutManager } from '../layout-rows/RowsLayoutManager';
|
||||
import { DashboardLayoutManager } from '../types/DashboardLayoutManager';
|
||||
@@ -39,10 +41,13 @@ export class TabsLayoutManager extends SceneObjectBase<TabsLayoutManagerState> i
|
||||
},
|
||||
id: 'tabs-layout',
|
||||
createFromLayout: TabsLayoutManager.createFromLayout,
|
||||
kind: 'TabsLayout',
|
||||
isGridLayout: false,
|
||||
};
|
||||
|
||||
public serialize(): DashboardV2Spec['layout'] {
|
||||
return serializeTabsLayout(this);
|
||||
}
|
||||
|
||||
public readonly descriptor = TabsLayoutManager.descriptor;
|
||||
|
||||
protected _urlSync = new SceneObjectUrlSyncConfig(this, { keys: () => [this.getUrlKey()] });
|
||||
|
||||
@@ -17,6 +17,11 @@ export interface DashboardLayoutManager<S = {}> extends SceneObject {
|
||||
*/
|
||||
descriptor: Readonly<LayoutRegistryItem>;
|
||||
|
||||
/**
|
||||
* Serializer for layout
|
||||
*/
|
||||
serialize(): DashboardV2Spec['layout'];
|
||||
|
||||
/**
|
||||
* Adds a new panel to the layout
|
||||
*/
|
||||
|
||||
@@ -1,29 +1,17 @@
|
||||
import { RegistryItem } from '@grafana/data';
|
||||
import { DashboardV2Spec } from '@grafana/schema/dist/esm/schema/dashboard/v2alpha0';
|
||||
|
||||
import { DashboardLayoutManager } from './DashboardLayoutManager';
|
||||
|
||||
/**
|
||||
* The layout descriptor used when selecting / switching layouts
|
||||
*/
|
||||
export interface LayoutRegistryItem<S = {}> extends RegistryItem {
|
||||
export interface LayoutRegistryItem extends RegistryItem {
|
||||
/**
|
||||
* When switching between layouts
|
||||
* @param currentLayout
|
||||
*/
|
||||
createFromLayout(currentLayout: DashboardLayoutManager): DashboardLayoutManager;
|
||||
|
||||
/**
|
||||
* Create from persisted state
|
||||
* @param saveModel
|
||||
*/
|
||||
createFromSaveModel?(saveModel: S): void;
|
||||
|
||||
/**
|
||||
* Schema kind of layout
|
||||
*/
|
||||
kind?: DashboardV2Spec['layout']['kind'];
|
||||
|
||||
/**
|
||||
* Is grid layout (that contains panels)
|
||||
*/
|
||||
|
||||
+24
-24
@@ -16,7 +16,6 @@ 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 { DashboardLayoutManager, LayoutManagerSerializer } from '../../scene/types/DashboardLayoutManager';
|
||||
import { getOriginalKey, isClonedKey } from '../../utils/clone';
|
||||
import { dashboardSceneGraph } from '../../utils/dashboardSceneGraph';
|
||||
import { calculateGridItemDimensions, isLibraryPanel } from '../../utils/utils';
|
||||
@@ -24,31 +23,32 @@ import { GRID_ROW_HEIGHT } from '../const';
|
||||
|
||||
import { buildLibraryPanel, buildVizPanel } from './utils';
|
||||
|
||||
export class DefaultGridLayoutManagerSerializer implements LayoutManagerSerializer {
|
||||
serialize(layoutManager: DefaultGridLayoutManager, isSnapshot?: boolean): DashboardV2Spec['layout'] {
|
||||
return {
|
||||
kind: 'GridLayout',
|
||||
spec: {
|
||||
items: getGridLayoutItems(layoutManager, isSnapshot),
|
||||
},
|
||||
};
|
||||
}
|
||||
export function serializeDefaultGridLayout(
|
||||
layoutManager: DefaultGridLayoutManager,
|
||||
isSnapshot?: boolean
|
||||
): DashboardV2Spec['layout'] {
|
||||
return {
|
||||
kind: 'GridLayout',
|
||||
spec: {
|
||||
items: getGridLayoutItems(layoutManager, isSnapshot),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
deserialize(
|
||||
layout: DashboardV2Spec['layout'],
|
||||
elements: DashboardV2Spec['elements'],
|
||||
preload: boolean
|
||||
): DashboardLayoutManager {
|
||||
if (layout.kind !== 'GridLayout') {
|
||||
throw new Error('Invalid layout kind');
|
||||
}
|
||||
return new DefaultGridLayoutManager({
|
||||
grid: new SceneGridLayout({
|
||||
isLazy: !(preload || contextSrv.user.authenticatedBy === 'render'),
|
||||
children: createSceneGridLayoutForItems(layout, elements),
|
||||
}),
|
||||
});
|
||||
export function deserializeDefaultGridLayout(
|
||||
layout: DashboardV2Spec['layout'],
|
||||
elements: DashboardV2Spec['elements'],
|
||||
preload: boolean
|
||||
): DefaultGridLayoutManager {
|
||||
if (layout.kind !== 'GridLayout') {
|
||||
throw new Error('Invalid layout kind');
|
||||
}
|
||||
return new DefaultGridLayoutManager({
|
||||
grid: new SceneGridLayout({
|
||||
isLazy: !(preload || contextSrv.user.authenticatedBy === 'render'),
|
||||
children: createSceneGridLayoutForItems(layout, elements),
|
||||
}),
|
||||
});
|
||||
}
|
||||
|
||||
function getGridLayoutItems(
|
||||
|
||||
+84
-84
@@ -15,99 +15,99 @@ import {
|
||||
getTemplateColumnsTemplate,
|
||||
AutoGridLayoutManager,
|
||||
} from '../../scene/layout-responsive-grid/ResponsiveGridLayoutManager';
|
||||
import { DashboardLayoutManager, LayoutManagerSerializer } from '../../scene/types/DashboardLayoutManager';
|
||||
import { dashboardSceneGraph } from '../../utils/dashboardSceneGraph';
|
||||
import { getGridItemKeyForPanelId } from '../../utils/utils';
|
||||
|
||||
import { buildLibraryPanel, buildVizPanel, getConditionalRendering } from './utils';
|
||||
|
||||
export class AutoGridLayoutSerializer implements LayoutManagerSerializer {
|
||||
serialize(layoutManager: AutoGridLayoutManager): DashboardV2Spec['layout'] {
|
||||
const { maxColumnCount, fillScreen, columnWidth, rowHeight, layout } = layoutManager.state;
|
||||
const defaults = defaultAutoGridLayoutSpec();
|
||||
export function serializeAutoGridLayout(layoutManager: AutoGridLayoutManager): DashboardV2Spec['layout'] {
|
||||
const { maxColumnCount, fillScreen, columnWidth, rowHeight, layout } = layoutManager.state;
|
||||
const defaults = defaultAutoGridLayoutSpec();
|
||||
|
||||
return {
|
||||
kind: 'AutoGridLayout',
|
||||
spec: {
|
||||
maxColumnCount,
|
||||
fillScreen: fillScreen === defaults.fillScreen ? undefined : fillScreen,
|
||||
...serializeAutoGridColumnWidth(columnWidth),
|
||||
...serializeAutoGridRowHeight(rowHeight),
|
||||
items: layout.state.children.map((child) => {
|
||||
if (!(child instanceof AutoGridItem)) {
|
||||
throw new Error('Expected AutoGridItem');
|
||||
}
|
||||
// For serialization we should retrieve the original element key
|
||||
const elementKey = dashboardSceneGraph.getElementIdentifierForVizPanel(child.state?.body);
|
||||
|
||||
const layoutItem: AutoGridLayoutItemKind = {
|
||||
kind: 'AutoGridLayoutItem',
|
||||
spec: {
|
||||
element: {
|
||||
kind: 'ElementReference',
|
||||
name: elementKey,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const conditionalRenderingRootGroup = child.state.conditionalRendering?.serialize();
|
||||
// Only serialize the conditional rendering if it has items
|
||||
if (conditionalRenderingRootGroup?.spec.items.length) {
|
||||
layoutItem.spec.conditionalRendering = conditionalRenderingRootGroup;
|
||||
}
|
||||
|
||||
if (child.state.variableName) {
|
||||
layoutItem.spec.repeat = {
|
||||
mode: 'variable',
|
||||
value: child.state.variableName,
|
||||
};
|
||||
}
|
||||
|
||||
return layoutItem;
|
||||
}),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
deserialize(layout: DashboardV2Spec['layout'], elements: DashboardV2Spec['elements']): DashboardLayoutManager {
|
||||
if (layout.kind !== 'AutoGridLayout') {
|
||||
throw new Error('Invalid layout kind');
|
||||
}
|
||||
|
||||
const defaults = defaultAutoGridLayoutSpec();
|
||||
const { maxColumnCount, columnWidthMode, columnWidth, rowHeightMode, rowHeight, fillScreen } = layout.spec;
|
||||
|
||||
const children = layout.spec.items.map((item) => {
|
||||
const panel = elements[item.spec.element.name];
|
||||
if (!panel) {
|
||||
throw new Error(`Panel with uid ${item.spec.element.name} not found in the dashboard elements`);
|
||||
}
|
||||
return new AutoGridItem({
|
||||
key: getGridItemKeyForPanelId(panel.spec.id),
|
||||
body: panel.kind === 'LibraryPanel' ? buildLibraryPanel(panel) : buildVizPanel(panel),
|
||||
variableName: item.spec.repeat?.value,
|
||||
conditionalRendering: getConditionalRendering(item),
|
||||
});
|
||||
});
|
||||
|
||||
const columnWidthCombined = columnWidthMode === 'custom' ? columnWidth : columnWidthMode;
|
||||
const rowHeightCombined = rowHeightMode === 'custom' ? rowHeight : rowHeightMode;
|
||||
|
||||
return new AutoGridLayoutManager({
|
||||
return {
|
||||
kind: 'AutoGridLayout',
|
||||
spec: {
|
||||
maxColumnCount,
|
||||
columnWidth: columnWidthCombined,
|
||||
rowHeight: rowHeightCombined,
|
||||
fillScreen: fillScreen ?? defaults.fillScreen,
|
||||
layout: new AutoGridLayout({
|
||||
templateColumns: getTemplateColumnsTemplate(
|
||||
maxColumnCount ?? defaults.maxColumnCount!,
|
||||
columnWidthCombined ?? AUTO_GRID_DEFAULT_COLUMN_WIDTH
|
||||
),
|
||||
autoRows: getAutoRowsTemplate(rowHeightCombined ?? AUTO_GRID_DEFAULT_ROW_HEIGHT, fillScreen ?? false),
|
||||
children,
|
||||
fillScreen: fillScreen === defaults.fillScreen ? undefined : fillScreen,
|
||||
...serializeAutoGridColumnWidth(columnWidth),
|
||||
...serializeAutoGridRowHeight(rowHeight),
|
||||
items: layout.state.children.map((child) => {
|
||||
if (!(child instanceof AutoGridItem)) {
|
||||
throw new Error('Expected AutoGridItem');
|
||||
}
|
||||
// For serialization we should retrieve the original element key
|
||||
const elementKey = dashboardSceneGraph.getElementIdentifierForVizPanel(child.state?.body);
|
||||
|
||||
const layoutItem: AutoGridLayoutItemKind = {
|
||||
kind: 'AutoGridLayoutItem',
|
||||
spec: {
|
||||
element: {
|
||||
kind: 'ElementReference',
|
||||
name: elementKey,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const conditionalRenderingRootGroup = child.state.conditionalRendering?.serialize();
|
||||
// Only serialize the conditional rendering if it has items
|
||||
if (conditionalRenderingRootGroup?.spec.items.length) {
|
||||
layoutItem.spec.conditionalRendering = conditionalRenderingRootGroup;
|
||||
}
|
||||
|
||||
if (child.state.variableName) {
|
||||
layoutItem.spec.repeat = {
|
||||
mode: 'variable',
|
||||
value: child.state.variableName,
|
||||
};
|
||||
}
|
||||
|
||||
return layoutItem;
|
||||
}),
|
||||
});
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export function deserializeAutoGridLayout(
|
||||
layout: DashboardV2Spec['layout'],
|
||||
elements: DashboardV2Spec['elements']
|
||||
): AutoGridLayoutManager {
|
||||
if (layout.kind !== 'AutoGridLayout') {
|
||||
throw new Error('Invalid layout kind');
|
||||
}
|
||||
|
||||
const defaults = defaultAutoGridLayoutSpec();
|
||||
const { maxColumnCount, columnWidthMode, columnWidth, rowHeightMode, rowHeight, fillScreen } = layout.spec;
|
||||
|
||||
const children = layout.spec.items.map((item) => {
|
||||
const panel = elements[item.spec.element.name];
|
||||
if (!panel) {
|
||||
throw new Error(`Panel with uid ${item.spec.element.name} not found in the dashboard elements`);
|
||||
}
|
||||
return new AutoGridItem({
|
||||
key: getGridItemKeyForPanelId(panel.spec.id),
|
||||
body: panel.kind === 'LibraryPanel' ? buildLibraryPanel(panel) : buildVizPanel(panel),
|
||||
variableName: item.spec.repeat?.value,
|
||||
conditionalRendering: getConditionalRendering(item),
|
||||
});
|
||||
});
|
||||
|
||||
const columnWidthCombined = columnWidthMode === 'custom' ? columnWidth : columnWidthMode;
|
||||
const rowHeightCombined = rowHeightMode === 'custom' ? rowHeight : rowHeightMode;
|
||||
|
||||
return new AutoGridLayoutManager({
|
||||
maxColumnCount,
|
||||
columnWidth: columnWidthCombined,
|
||||
rowHeight: rowHeightCombined,
|
||||
fillScreen: fillScreen ?? defaults.fillScreen,
|
||||
layout: new AutoGridLayout({
|
||||
templateColumns: getTemplateColumnsTemplate(
|
||||
maxColumnCount ?? defaults.maxColumnCount!,
|
||||
columnWidthCombined ?? AUTO_GRID_DEFAULT_COLUMN_WIDTH
|
||||
),
|
||||
autoRows: getAutoRowsTemplate(rowHeightCombined ?? AUTO_GRID_DEFAULT_ROW_HEIGHT, fillScreen ?? false),
|
||||
children,
|
||||
}),
|
||||
});
|
||||
}
|
||||
|
||||
function serializeAutoGridColumnWidth(columnWidth: AutoGridColumnWidth) {
|
||||
|
||||
+11
-21
@@ -8,7 +8,7 @@ import { RowItem } from '../../scene/layout-rows/RowItem';
|
||||
import { RowItemRepeaterBehavior } from '../../scene/layout-rows/RowItemRepeaterBehavior';
|
||||
import { RowsLayoutManager } from '../../scene/layout-rows/RowsLayoutManager';
|
||||
|
||||
import { RowsLayoutSerializer } from './RowsLayoutSerializer';
|
||||
import { deserializeRowsLayout, serializeRowsLayout } from './RowsLayoutSerializer';
|
||||
|
||||
describe('deserialization', () => {
|
||||
it('should deserialize rows layout with default grid child', () => {
|
||||
@@ -27,8 +27,7 @@ describe('deserialization', () => {
|
||||
],
|
||||
},
|
||||
};
|
||||
const serializer = new RowsLayoutSerializer();
|
||||
const deserialized = serializer.deserialize(layout, {}, false);
|
||||
const deserialized = deserializeRowsLayout(layout, {}, false);
|
||||
expect(deserialized).toBeInstanceOf(RowsLayoutManager);
|
||||
expect(deserialized.state.rows[0].state.layout).toBeInstanceOf(DefaultGridLayoutManager);
|
||||
});
|
||||
@@ -51,8 +50,7 @@ describe('deserialization', () => {
|
||||
],
|
||||
},
|
||||
};
|
||||
const serializer = new RowsLayoutSerializer();
|
||||
const deserialized = serializer.deserialize(layout, {}, false);
|
||||
const deserialized = deserializeRowsLayout(layout, {}, false);
|
||||
expect(deserialized).toBeInstanceOf(RowsLayoutManager);
|
||||
expect(deserialized.state.rows[0].state.layout).toBeInstanceOf(DefaultGridLayoutManager);
|
||||
expect(deserialized.state.rows[0].state.collapse).toBe(true);
|
||||
@@ -84,8 +82,7 @@ describe('deserialization', () => {
|
||||
],
|
||||
},
|
||||
};
|
||||
const serializer = new RowsLayoutSerializer();
|
||||
const deserialized = serializer.deserialize(layout, {}, false);
|
||||
const deserialized = deserializeRowsLayout(layout, {}, false);
|
||||
expect(deserialized).toBeInstanceOf(RowsLayoutManager);
|
||||
expect(deserialized.state.rows[0].state.layout).toBeInstanceOf(AutoGridLayoutManager);
|
||||
});
|
||||
@@ -126,8 +123,7 @@ describe('deserialization', () => {
|
||||
],
|
||||
},
|
||||
};
|
||||
const serializer = new RowsLayoutSerializer();
|
||||
const deserialized = serializer.deserialize(layout, {}, false);
|
||||
const deserialized = deserializeRowsLayout(layout, {}, false);
|
||||
expect(deserialized).toBeInstanceOf(RowsLayoutManager);
|
||||
expect(deserialized.state.rows).toHaveLength(2);
|
||||
expect(deserialized.state.rows[0].state.layout).toBeInstanceOf(AutoGridLayoutManager);
|
||||
@@ -143,8 +139,7 @@ describe('deserialization', () => {
|
||||
rows: [],
|
||||
},
|
||||
};
|
||||
const serializer = new RowsLayoutSerializer();
|
||||
const deserialized = serializer.deserialize(layout, {}, false);
|
||||
const deserialized = deserializeRowsLayout(layout, {}, false);
|
||||
expect(deserialized).toBeInstanceOf(RowsLayoutManager);
|
||||
expect(deserialized.state.rows).toHaveLength(0);
|
||||
});
|
||||
@@ -168,8 +163,7 @@ describe('deserialization', () => {
|
||||
],
|
||||
},
|
||||
};
|
||||
const serializer = new RowsLayoutSerializer();
|
||||
const deserialized = serializer.deserialize(layout, {}, false);
|
||||
const deserialized = deserializeRowsLayout(layout, {}, false);
|
||||
|
||||
expect(deserialized).toBeInstanceOf(RowsLayoutManager);
|
||||
expect(deserialized.state.rows).toHaveLength(1);
|
||||
@@ -202,8 +196,7 @@ describe('serialization', () => {
|
||||
],
|
||||
});
|
||||
|
||||
const serializer = new RowsLayoutSerializer();
|
||||
const serialized = serializer.serialize(rowsLayout);
|
||||
const serialized = serializeRowsLayout(rowsLayout);
|
||||
|
||||
expect(serialized).toEqual({
|
||||
kind: 'RowsLayout',
|
||||
@@ -243,8 +236,7 @@ describe('serialization', () => {
|
||||
],
|
||||
});
|
||||
|
||||
const serializer = new RowsLayoutSerializer();
|
||||
const serialized = serializer.serialize(rowsLayout);
|
||||
const serialized = serializeRowsLayout(rowsLayout);
|
||||
|
||||
expect(serialized).toEqual({
|
||||
kind: 'RowsLayout',
|
||||
@@ -283,8 +275,7 @@ describe('serialization', () => {
|
||||
],
|
||||
});
|
||||
|
||||
const serializer = new RowsLayoutSerializer();
|
||||
const serialized = serializer.serialize(rowsLayout);
|
||||
const serialized = serializeRowsLayout(rowsLayout);
|
||||
|
||||
expect(serialized).toEqual({
|
||||
kind: 'RowsLayout',
|
||||
@@ -335,8 +326,7 @@ describe('serialization', () => {
|
||||
],
|
||||
});
|
||||
|
||||
const serializer = new RowsLayoutSerializer();
|
||||
const serialized = serializer.serialize(rowsLayout);
|
||||
const serialized = serializeRowsLayout(rowsLayout);
|
||||
|
||||
expect(serialized).toEqual({
|
||||
kind: 'RowsLayout',
|
||||
|
||||
+58
-61
@@ -4,76 +4,73 @@ import { DashboardV2Spec, RowsLayoutRowKind } from '@grafana/schema/dist/esm/sch
|
||||
import { RowItem } from '../../scene/layout-rows/RowItem';
|
||||
import { RowItemRepeaterBehavior } from '../../scene/layout-rows/RowItemRepeaterBehavior';
|
||||
import { RowsLayoutManager } from '../../scene/layout-rows/RowsLayoutManager';
|
||||
import { LayoutManagerSerializer } from '../../scene/types/DashboardLayoutManager';
|
||||
|
||||
import { layoutSerializerRegistry } from './layoutSerializerRegistry';
|
||||
import { getConditionalRendering, getLayout } from './utils';
|
||||
import { layoutDeserializerRegistry } from './layoutSerializerRegistry';
|
||||
import { getConditionalRendering } from './utils';
|
||||
|
||||
export class RowsLayoutSerializer implements LayoutManagerSerializer {
|
||||
serialize(layoutManager: RowsLayoutManager): DashboardV2Spec['layout'] {
|
||||
return {
|
||||
kind: 'RowsLayout',
|
||||
spec: {
|
||||
rows: layoutManager.state.rows.map((row) => {
|
||||
const layout = getLayout(row.state.layout);
|
||||
const rowKind: RowsLayoutRowKind = {
|
||||
kind: 'RowsLayoutRow',
|
||||
spec: {
|
||||
title: row.state.title,
|
||||
collapse: row.state.collapse,
|
||||
layout: layout,
|
||||
fillScreen: row.state.fillScreen,
|
||||
hideHeader: row.state.hideHeader,
|
||||
},
|
||||
};
|
||||
export function serializeRowsLayout(layoutManager: RowsLayoutManager): DashboardV2Spec['layout'] {
|
||||
return {
|
||||
kind: 'RowsLayout',
|
||||
spec: {
|
||||
rows: layoutManager.state.rows.map((row) => {
|
||||
const layout = row.state.layout.serialize();
|
||||
const rowKind: RowsLayoutRowKind = {
|
||||
kind: 'RowsLayoutRow',
|
||||
spec: {
|
||||
title: row.state.title,
|
||||
collapse: row.state.collapse,
|
||||
layout: layout,
|
||||
fillScreen: row.state.fillScreen,
|
||||
hideHeader: row.state.hideHeader,
|
||||
},
|
||||
};
|
||||
|
||||
const conditionalRenderingRootGroup = row.state.conditionalRendering?.serialize();
|
||||
// Only serialize the conditional rendering if it has items
|
||||
if (conditionalRenderingRootGroup?.spec.items.length) {
|
||||
rowKind.spec.conditionalRendering = conditionalRenderingRootGroup;
|
||||
}
|
||||
const conditionalRenderingRootGroup = row.state.conditionalRendering?.serialize();
|
||||
// Only serialize the conditional rendering if it has items
|
||||
if (conditionalRenderingRootGroup?.spec.items.length) {
|
||||
rowKind.spec.conditionalRendering = conditionalRenderingRootGroup;
|
||||
}
|
||||
|
||||
if (row.state.$behaviors) {
|
||||
for (const behavior of row.state.$behaviors) {
|
||||
if (behavior instanceof RowItemRepeaterBehavior) {
|
||||
if (rowKind.spec.repeat) {
|
||||
throw new Error('Multiple repeaters are not supported');
|
||||
}
|
||||
rowKind.spec.repeat = { value: behavior.state.variableName, mode: 'variable' };
|
||||
if (row.state.$behaviors) {
|
||||
for (const behavior of row.state.$behaviors) {
|
||||
if (behavior instanceof RowItemRepeaterBehavior) {
|
||||
if (rowKind.spec.repeat) {
|
||||
throw new Error('Multiple repeaters are not supported');
|
||||
}
|
||||
rowKind.spec.repeat = { value: behavior.state.variableName, mode: 'variable' };
|
||||
}
|
||||
}
|
||||
return rowKind;
|
||||
}),
|
||||
},
|
||||
};
|
||||
}
|
||||
return rowKind;
|
||||
}),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export function deserializeRowsLayout(
|
||||
layout: DashboardV2Spec['layout'],
|
||||
elements: DashboardV2Spec['elements'],
|
||||
preload: boolean
|
||||
): RowsLayoutManager {
|
||||
if (layout.kind !== 'RowsLayout') {
|
||||
throw new Error('Invalid layout kind');
|
||||
}
|
||||
|
||||
deserialize(
|
||||
layout: DashboardV2Spec['layout'],
|
||||
elements: DashboardV2Spec['elements'],
|
||||
preload: boolean
|
||||
): RowsLayoutManager {
|
||||
if (layout.kind !== 'RowsLayout') {
|
||||
throw new Error('Invalid layout kind');
|
||||
const rows = layout.spec.rows.map((row) => {
|
||||
const layout = row.spec.layout;
|
||||
const behaviors: SceneObject[] = [];
|
||||
if (row.spec.repeat) {
|
||||
behaviors.push(new RowItemRepeaterBehavior({ variableName: row.spec.repeat.value }));
|
||||
}
|
||||
const rows = layout.spec.rows.map((row) => {
|
||||
const layout = row.spec.layout;
|
||||
const behaviors: SceneObject[] = [];
|
||||
if (row.spec.repeat) {
|
||||
behaviors.push(new RowItemRepeaterBehavior({ variableName: row.spec.repeat.value }));
|
||||
}
|
||||
|
||||
return new RowItem({
|
||||
title: row.spec.title,
|
||||
collapse: row.spec.collapse,
|
||||
hideHeader: row.spec.hideHeader,
|
||||
fillScreen: row.spec.fillScreen,
|
||||
$behaviors: behaviors,
|
||||
layout: layoutSerializerRegistry.get(layout.kind).serializer.deserialize(layout, elements, preload),
|
||||
conditionalRendering: getConditionalRendering(row),
|
||||
});
|
||||
return new RowItem({
|
||||
title: row.spec.title,
|
||||
collapse: row.spec.collapse,
|
||||
hideHeader: row.spec.hideHeader,
|
||||
fillScreen: row.spec.fillScreen,
|
||||
$behaviors: behaviors,
|
||||
layout: layoutDeserializerRegistry.get(layout.kind).deserialize(layout, elements, preload),
|
||||
conditionalRendering: getConditionalRendering(row),
|
||||
});
|
||||
return new RowsLayoutManager({ rows });
|
||||
}
|
||||
});
|
||||
return new RowsLayoutManager({ rows });
|
||||
}
|
||||
|
||||
+6
-11
@@ -5,7 +5,7 @@ import { AutoGridLayoutManager } from '../../scene/layout-responsive-grid/Respon
|
||||
import { RowsLayoutManager } from '../../scene/layout-rows/RowsLayoutManager';
|
||||
import { TabsLayoutManager } from '../../scene/layout-tabs/TabsLayoutManager';
|
||||
|
||||
import { TabsLayoutSerializer } from './TabsLayoutSerializer';
|
||||
import { deserializeTabsLayout } from './TabsLayoutSerializer';
|
||||
|
||||
describe('deserialization', () => {
|
||||
it('should deserialize tabs layout with row child', () => {
|
||||
@@ -15,8 +15,7 @@ describe('deserialization', () => {
|
||||
tabs: [{ kind: 'TabsLayoutTab', spec: { title: 'Tab 1', layout: { kind: 'RowsLayout', spec: { rows: [] } } } }],
|
||||
},
|
||||
};
|
||||
const serializer = new TabsLayoutSerializer();
|
||||
const deserialized = serializer.deserialize(layout, {}, false);
|
||||
const deserialized = deserializeTabsLayout(layout, {}, false);
|
||||
expect(deserialized).toBeInstanceOf(TabsLayoutManager);
|
||||
expect(deserialized.state.tabs[0].state.layout).toBeInstanceOf(RowsLayoutManager);
|
||||
});
|
||||
@@ -39,8 +38,7 @@ describe('deserialization', () => {
|
||||
],
|
||||
},
|
||||
};
|
||||
const serializer = new TabsLayoutSerializer();
|
||||
const deserialized = serializer.deserialize(layout, {}, false);
|
||||
const deserialized = deserializeTabsLayout(layout, {}, false);
|
||||
expect(deserialized).toBeInstanceOf(TabsLayoutManager);
|
||||
expect(deserialized.state.tabs[0].state.layout).toBeInstanceOf(AutoGridLayoutManager);
|
||||
});
|
||||
@@ -57,8 +55,7 @@ describe('deserialization', () => {
|
||||
],
|
||||
},
|
||||
};
|
||||
const serializer = new TabsLayoutSerializer();
|
||||
const deserialized = serializer.deserialize(layout, {}, false);
|
||||
const deserialized = deserializeTabsLayout(layout, {}, false);
|
||||
expect(deserialized).toBeInstanceOf(TabsLayoutManager);
|
||||
expect(deserialized.state.tabs[0].state.layout).toBeInstanceOf(DefaultGridLayoutManager);
|
||||
});
|
||||
@@ -82,8 +79,7 @@ describe('deserialization', () => {
|
||||
],
|
||||
},
|
||||
};
|
||||
const serializer = new TabsLayoutSerializer();
|
||||
const deserialized = serializer.deserialize(layout, {}, false);
|
||||
const deserialized = deserializeTabsLayout(layout, {}, false);
|
||||
expect(deserialized).toBeInstanceOf(TabsLayoutManager);
|
||||
expect(deserialized.state.tabs[0].state.layout).toBeInstanceOf(AutoGridLayoutManager);
|
||||
expect(deserialized.state.tabs[1].state.layout).toBeInstanceOf(DefaultGridLayoutManager);
|
||||
@@ -96,8 +92,7 @@ describe('deserialization', () => {
|
||||
tabs: [],
|
||||
},
|
||||
};
|
||||
const serializer = new TabsLayoutSerializer();
|
||||
const deserialized = serializer.deserialize(layout, {}, false);
|
||||
const deserialized = deserializeTabsLayout(layout, {}, false);
|
||||
expect(deserialized).toBeInstanceOf(TabsLayoutManager);
|
||||
expect(deserialized.state.tabs).toHaveLength(0);
|
||||
});
|
||||
|
||||
+33
-37
@@ -2,45 +2,41 @@ import { DashboardV2Spec } from '@grafana/schema/dist/esm/schema/dashboard/v2alp
|
||||
|
||||
import { TabItem } from '../../scene/layout-tabs/TabItem';
|
||||
import { TabsLayoutManager } from '../../scene/layout-tabs/TabsLayoutManager';
|
||||
import { LayoutManagerSerializer } from '../../scene/types/DashboardLayoutManager';
|
||||
|
||||
import { layoutSerializerRegistry } from './layoutSerializerRegistry';
|
||||
import { getLayout } from './utils';
|
||||
import { layoutDeserializerRegistry } from './layoutSerializerRegistry';
|
||||
|
||||
export class TabsLayoutSerializer implements LayoutManagerSerializer {
|
||||
serialize(layoutManager: TabsLayoutManager): DashboardV2Spec['layout'] {
|
||||
return {
|
||||
kind: 'TabsLayout',
|
||||
spec: {
|
||||
tabs: layoutManager.state.tabs.map((tab) => {
|
||||
const layout = getLayout(tab.state.layout);
|
||||
return {
|
||||
kind: 'TabsLayoutTab',
|
||||
spec: {
|
||||
title: tab.state.title,
|
||||
layout: layout,
|
||||
},
|
||||
};
|
||||
}),
|
||||
},
|
||||
};
|
||||
export function serializeTabsLayout(layoutManager: TabsLayoutManager): DashboardV2Spec['layout'] {
|
||||
return {
|
||||
kind: 'TabsLayout',
|
||||
spec: {
|
||||
tabs: layoutManager.state.tabs.map((tab) => {
|
||||
const layout = tab.state.layout.serialize();
|
||||
return {
|
||||
kind: 'TabsLayoutTab',
|
||||
spec: {
|
||||
title: tab.state.title,
|
||||
layout: layout,
|
||||
},
|
||||
};
|
||||
}),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export function deserializeTabsLayout(
|
||||
layout: DashboardV2Spec['layout'],
|
||||
elements: DashboardV2Spec['elements'],
|
||||
preload: boolean
|
||||
): TabsLayoutManager {
|
||||
if (layout.kind !== 'TabsLayout') {
|
||||
throw new Error('Invalid layout kind');
|
||||
}
|
||||
|
||||
deserialize(
|
||||
layout: DashboardV2Spec['layout'],
|
||||
elements: DashboardV2Spec['elements'],
|
||||
preload: boolean
|
||||
): TabsLayoutManager {
|
||||
if (layout.kind !== 'TabsLayout') {
|
||||
throw new Error('Invalid layout kind');
|
||||
}
|
||||
const tabs = layout.spec.tabs.map((tab) => {
|
||||
const layout = tab.spec.layout;
|
||||
return new TabItem({
|
||||
title: tab.spec.title,
|
||||
layout: layoutSerializerRegistry.get(layout.kind).serializer.deserialize(layout, elements, preload),
|
||||
});
|
||||
const tabs = layout.spec.tabs.map((tab) => {
|
||||
const layout = tab.spec.layout;
|
||||
return new TabItem({
|
||||
title: tab.spec.title,
|
||||
layout: layoutDeserializerRegistry.get(layout.kind).deserialize(layout, elements, preload),
|
||||
});
|
||||
return new TabsLayoutManager({ tabs });
|
||||
}
|
||||
});
|
||||
return new TabsLayoutManager({ tabs });
|
||||
}
|
||||
|
||||
+32
-11
@@ -1,22 +1,43 @@
|
||||
import { Registry, RegistryItem } from '@grafana/data';
|
||||
import { DashboardV2Spec } from '@grafana/schema/dist/esm/schema/dashboard/v2alpha0';
|
||||
|
||||
import { LayoutManagerSerializer } from '../../scene/types/DashboardLayoutManager';
|
||||
import { DashboardLayoutManager } from '../../scene/types/DashboardLayoutManager';
|
||||
|
||||
import { DefaultGridLayoutManagerSerializer } from './DefaultGridLayoutSerializer';
|
||||
import { AutoGridLayoutSerializer } from './ResponsiveGridLayoutSerializer';
|
||||
import { RowsLayoutSerializer } from './RowsLayoutSerializer';
|
||||
import { TabsLayoutSerializer } from './TabsLayoutSerializer';
|
||||
import { deserializeDefaultGridLayout } from './DefaultGridLayoutSerializer';
|
||||
import { deserializeAutoGridLayout } from './ResponsiveGridLayoutSerializer';
|
||||
import { deserializeRowsLayout } from './RowsLayoutSerializer';
|
||||
import { deserializeTabsLayout } from './TabsLayoutSerializer';
|
||||
|
||||
interface LayoutSerializerRegistryItem extends RegistryItem {
|
||||
serializer: LayoutManagerSerializer;
|
||||
deserialize: (
|
||||
layout: DashboardV2Spec['layout'],
|
||||
elements: DashboardV2Spec['elements'],
|
||||
preload: boolean
|
||||
) => DashboardLayoutManager;
|
||||
}
|
||||
|
||||
export const layoutSerializerRegistry: Registry<LayoutSerializerRegistryItem> =
|
||||
export const layoutDeserializerRegistry: Registry<LayoutSerializerRegistryItem> =
|
||||
new Registry<LayoutSerializerRegistryItem>(() => {
|
||||
return [
|
||||
{ id: 'GridLayout', name: 'Grid Layout', serializer: new DefaultGridLayoutManagerSerializer() },
|
||||
{ id: 'AutoGridLayout', name: 'Auto Grid Layout', serializer: new AutoGridLayoutSerializer() },
|
||||
{ id: 'RowsLayout', name: 'Rows Layout', serializer: new RowsLayoutSerializer() },
|
||||
{ id: 'TabsLayout', name: 'Tabs Layout', serializer: new TabsLayoutSerializer() },
|
||||
{
|
||||
id: 'GridLayout',
|
||||
name: 'Grid Layout',
|
||||
deserialize: deserializeDefaultGridLayout,
|
||||
},
|
||||
{
|
||||
id: 'AutoGridLayout',
|
||||
name: 'Auto Grid Layout',
|
||||
deserialize: deserializeAutoGridLayout,
|
||||
},
|
||||
{
|
||||
id: 'RowsLayout',
|
||||
name: 'Rows Layout',
|
||||
deserialize: deserializeRowsLayout,
|
||||
},
|
||||
{
|
||||
id: 'TabsLayout',
|
||||
name: 'Tabs Layout',
|
||||
deserialize: deserializeTabsLayout,
|
||||
},
|
||||
];
|
||||
});
|
||||
|
||||
@@ -36,8 +36,6 @@ import { DashboardLayoutManager } from '../../scene/types/DashboardLayoutManager
|
||||
import { getVizPanelKeyForPanelId } from '../../utils/utils';
|
||||
import { transformMappingsToV1 } from '../transformToV1TypesUtils';
|
||||
|
||||
import { layoutSerializerRegistry } from './layoutSerializerRegistry';
|
||||
|
||||
export function buildVizPanel(panel: PanelKind): VizPanel {
|
||||
const titleItems: SceneObject[] = [];
|
||||
|
||||
@@ -227,12 +225,7 @@ function panelQueryKindToSceneQuery(query: PanelQueryKind): SceneDataQuery {
|
||||
}
|
||||
|
||||
export function getLayout(sceneState: DashboardLayoutManager): DashboardV2Spec['layout'] {
|
||||
const registryItem = layoutSerializerRegistry.get(sceneState.descriptor.kind ?? '');
|
||||
if (!registryItem) {
|
||||
throw new Error(`Layout serializer not found for kind: ${sceneState.descriptor.kind}`);
|
||||
}
|
||||
|
||||
return registryItem.serializer.serialize(sceneState);
|
||||
return sceneState.serialize();
|
||||
}
|
||||
|
||||
export function getConditionalRendering(item: RowsLayoutRowKind | AutoGridLayoutItemKind): ConditionalRendering {
|
||||
|
||||
+5
-5
@@ -527,7 +527,7 @@ describe('transformSaveModelSchemaV2ToScene', () => {
|
||||
};
|
||||
const scene = transformSaveModelSchemaV2ToScene(dashboard);
|
||||
const layoutManager = scene.state.body as AutoGridLayoutManager;
|
||||
expect(layoutManager.descriptor.kind).toBe('AutoGridLayout');
|
||||
expect(layoutManager.descriptor.id).toBe('auto-grid');
|
||||
expect(layoutManager.state.maxColumnCount).toBe(4);
|
||||
expect(layoutManager.state.columnWidth).toBe(100);
|
||||
expect(layoutManager.state.rowHeight).toBe('standard');
|
||||
@@ -572,7 +572,7 @@ describe('transformSaveModelSchemaV2ToScene', () => {
|
||||
};
|
||||
const scene = transformSaveModelSchemaV2ToScene(dashboard);
|
||||
const layoutManager = scene.state.body as TabsLayoutManager;
|
||||
expect(layoutManager.descriptor.kind).toBe('TabsLayout');
|
||||
expect(layoutManager.descriptor.id).toBe('tabs-layout');
|
||||
expect(layoutManager.state.tabs.length).toBe(1);
|
||||
expect(layoutManager.state.tabs[0].state.title).toBe('tab1');
|
||||
const gridLayoutManager = layoutManager.state.tabs[0].state.layout as AutoGridLayoutManager;
|
||||
@@ -648,10 +648,10 @@ describe('transformSaveModelSchemaV2ToScene', () => {
|
||||
};
|
||||
const scene = transformSaveModelSchemaV2ToScene(dashboard);
|
||||
const layoutManager = scene.state.body as RowsLayoutManager;
|
||||
expect(layoutManager.descriptor.kind).toBe('RowsLayout');
|
||||
expect(layoutManager.descriptor.id).toBe('rows-layout');
|
||||
expect(layoutManager.state.rows.length).toBe(2);
|
||||
const row1Manager = layoutManager.state.rows[0].state.layout as AutoGridLayoutManager;
|
||||
expect(row1Manager.descriptor.kind).toBe('AutoGridLayout');
|
||||
expect(row1Manager.descriptor.id).toBe('auto-grid');
|
||||
expect(row1Manager.state.maxColumnCount).toBe(4);
|
||||
expect(row1Manager.state.columnWidth).toBe('standard');
|
||||
expect(row1Manager.state.rowHeight).toBe('standard');
|
||||
@@ -659,7 +659,7 @@ describe('transformSaveModelSchemaV2ToScene', () => {
|
||||
expect(row1GridItem.state.body.state.key).toBe('panel-1');
|
||||
|
||||
const row2Manager = layoutManager.state.rows[1].state.layout as DefaultGridLayoutManager;
|
||||
expect(row2Manager.descriptor.kind).toBe('GridLayout');
|
||||
expect(row2Manager.descriptor.id).toBe('default-grid');
|
||||
const row2GridItem = row2Manager.state.grid.state.children[0] as SceneGridItem;
|
||||
expect(row2GridItem.state.body!.state.key).toBe('panel-2');
|
||||
});
|
||||
|
||||
+3
-3
@@ -63,7 +63,7 @@ import { preserveDashboardSceneStateInLocalStorage } from '../utils/dashboardSes
|
||||
import { getIntervalsFromQueryString } from '../utils/utils';
|
||||
|
||||
import { SnapshotVariable } from './custom-variables/SnapshotVariable';
|
||||
import { layoutSerializerRegistry } from './layoutSerializers/layoutSerializerRegistry';
|
||||
import { layoutDeserializerRegistry } from './layoutSerializers/layoutSerializerRegistry';
|
||||
import { getRuntimeVariableDataSource } from './layoutSerializers/utils';
|
||||
import { registerPanelInteractionsReporter } from './transformSaveModelToScene';
|
||||
import {
|
||||
@@ -142,9 +142,9 @@ export function transformSaveModelSchemaV2ToScene(dto: DashboardWithAccessInfo<D
|
||||
meta.canSave = false;
|
||||
}
|
||||
|
||||
const layoutManager: DashboardLayoutManager = layoutSerializerRegistry
|
||||
const layoutManager: DashboardLayoutManager = layoutDeserializerRegistry
|
||||
.get(dashboard.layout.kind)
|
||||
.serializer.deserialize(dashboard.layout, dashboard.elements, dashboard.preload);
|
||||
.deserialize(dashboard.layout, dashboard.elements, dashboard.preload);
|
||||
|
||||
//createLayoutManager(dashboard);
|
||||
|
||||
|
||||
+1
-2
@@ -52,7 +52,6 @@ import { dashboardSceneGraph } from '../utils/dashboardSceneGraph';
|
||||
import { getLibraryPanelBehavior, getPanelIdForVizPanel, getQueryRunnerFor, isLibraryPanel } from '../utils/utils';
|
||||
|
||||
import { DSReferencesMapping } from './DashboardSceneSerializer';
|
||||
import { getLayout } from './layoutSerializers/utils';
|
||||
import { sceneVariablesSetToSchemaV2Variables } from './sceneVariablesSetToVariables';
|
||||
import { colorIdEnumToColorIdV2, transformCursorSynctoEnum } from './transformToV2TypesUtils';
|
||||
|
||||
@@ -112,7 +111,7 @@ export function transformSceneToSaveModelSchemaV2(scene: DashboardScene, isSnaps
|
||||
// EOF annotations
|
||||
|
||||
// layout
|
||||
layout: getLayout(sceneDash.body),
|
||||
layout: sceneDash.body.serialize(),
|
||||
// EOF layout
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user