mirror of
https://github.com/grafana/grafana.git
synced 2025-08-01 18:13:09 +08:00
Dashboards: Tabs layout persistence (#100485)
* Tabs layout persistence * fix lint issue * Add tests, add tabs serializer to registry * Fix deserialize tabs * more tests * tab item title optional * change TabItemKind -> TabLayoutTabKind * add tests for tabs serializer * fix name in test * Fix test after renaming tabs
This commit is contained in:
@ -22,7 +22,7 @@ DashboardV2Spec: {
|
|||||||
|
|
||||||
elements: [ElementReference.name]: Element
|
elements: [ElementReference.name]: Element
|
||||||
|
|
||||||
layout: GridLayoutKind | RowsLayoutKind | ResponsiveGridLayoutKind
|
layout: GridLayoutKind | RowsLayoutKind | ResponsiveGridLayoutKind | TabsLayoutKind
|
||||||
|
|
||||||
// Links with references to other dashboards or external websites.
|
// Links with references to other dashboards or external websites.
|
||||||
links: [...DashboardLink]
|
links: [...DashboardLink]
|
||||||
@ -553,7 +553,7 @@ RowsLayoutRowSpec: {
|
|||||||
title?: string
|
title?: string
|
||||||
collapsed: bool
|
collapsed: bool
|
||||||
repeat?: RowRepeatOptions
|
repeat?: RowRepeatOptions
|
||||||
layout: GridLayoutKind | ResponsiveGridLayoutKind
|
layout: GridLayoutKind | ResponsiveGridLayoutKind | TabsLayoutKind
|
||||||
}
|
}
|
||||||
|
|
||||||
ResponsiveGridLayoutKind: {
|
ResponsiveGridLayoutKind: {
|
||||||
@ -576,6 +576,25 @@ ResponsiveGridLayoutItemSpec: {
|
|||||||
element: ElementReference
|
element: ElementReference
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TabsLayoutKind: {
|
||||||
|
kind: "TabsLayout"
|
||||||
|
spec: TabsLayoutSpec
|
||||||
|
}
|
||||||
|
|
||||||
|
TabsLayoutSpec: {
|
||||||
|
tabs: [...TabsLayoutTabKind]
|
||||||
|
}
|
||||||
|
|
||||||
|
TabsLayoutTabKind: {
|
||||||
|
kind: "TabsLayoutTab"
|
||||||
|
spec: TabsLayoutTabSpec
|
||||||
|
}
|
||||||
|
|
||||||
|
TabsLayoutTabSpec: {
|
||||||
|
title?: string
|
||||||
|
layout: GridLayoutKind | RowsLayoutKind | ResponsiveGridLayoutKind
|
||||||
|
}
|
||||||
|
|
||||||
PanelSpec: {
|
PanelSpec: {
|
||||||
id: number
|
id: number
|
||||||
title: string
|
title: string
|
||||||
|
@ -16,7 +16,7 @@ export interface DashboardV2Spec {
|
|||||||
// Whether a dashboard is editable or not.
|
// Whether a dashboard is editable or not.
|
||||||
editable?: boolean;
|
editable?: boolean;
|
||||||
elements: Record<string, Element>;
|
elements: Record<string, Element>;
|
||||||
layout: GridLayoutKind | RowsLayoutKind | ResponsiveGridLayoutKind;
|
layout: GridLayoutKind | RowsLayoutKind | ResponsiveGridLayoutKind | TabsLayoutKind;
|
||||||
// Links with references to other dashboards or external websites.
|
// Links with references to other dashboards or external websites.
|
||||||
links: DashboardLink[];
|
links: DashboardLink[];
|
||||||
// When set to true, the dashboard will redraw panels at an interval matching the pixel width.
|
// When set to true, the dashboard will redraw panels at an interval matching the pixel width.
|
||||||
@ -825,7 +825,7 @@ export interface RowsLayoutRowSpec {
|
|||||||
title?: string;
|
title?: string;
|
||||||
collapsed: boolean;
|
collapsed: boolean;
|
||||||
repeat?: RowRepeatOptions;
|
repeat?: RowRepeatOptions;
|
||||||
layout: GridLayoutKind | ResponsiveGridLayoutKind;
|
layout: GridLayoutKind | ResponsiveGridLayoutKind | TabsLayoutKind;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const defaultRowsLayoutRowSpec = (): RowsLayoutRowSpec => ({
|
export const defaultRowsLayoutRowSpec = (): RowsLayoutRowSpec => ({
|
||||||
@ -873,6 +873,43 @@ export const defaultResponsiveGridLayoutItemSpec = (): ResponsiveGridLayoutItemS
|
|||||||
element: defaultElementReference(),
|
element: defaultElementReference(),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export interface TabsLayoutKind {
|
||||||
|
kind: "TabsLayout";
|
||||||
|
spec: TabsLayoutSpec;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const defaultTabsLayoutKind = (): TabsLayoutKind => ({
|
||||||
|
kind: "TabsLayout",
|
||||||
|
spec: defaultTabsLayoutSpec(),
|
||||||
|
});
|
||||||
|
|
||||||
|
export interface TabsLayoutSpec {
|
||||||
|
tabs: TabsLayoutTabKind[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export const defaultTabsLayoutSpec = (): TabsLayoutSpec => ({
|
||||||
|
tabs: [],
|
||||||
|
});
|
||||||
|
|
||||||
|
export interface TabsLayoutTabKind {
|
||||||
|
kind: "TabsLayoutTab";
|
||||||
|
spec: TabsLayoutTabSpec;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const defaultTabsLayoutTabKind = (): TabsLayoutTabKind => ({
|
||||||
|
kind: "TabsLayoutTab",
|
||||||
|
spec: defaultTabsLayoutTabSpec(),
|
||||||
|
});
|
||||||
|
|
||||||
|
export interface TabsLayoutTabSpec {
|
||||||
|
title?: string;
|
||||||
|
layout: GridLayoutKind | RowsLayoutKind | ResponsiveGridLayoutKind;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const defaultTabsLayoutTabSpec = (): TabsLayoutTabSpec => ({
|
||||||
|
layout: defaultGridLayoutKind(),
|
||||||
|
});
|
||||||
|
|
||||||
export interface PanelSpec {
|
export interface PanelSpec {
|
||||||
id: number;
|
id: number;
|
||||||
title: string;
|
title: string;
|
||||||
|
@ -2,6 +2,7 @@ import { SceneObjectBase, SceneObjectState, VizPanel } from '@grafana/scenes';
|
|||||||
import { t } from 'app/core/internationalization';
|
import { t } from 'app/core/internationalization';
|
||||||
|
|
||||||
import { DashboardLayoutManager } from '../types/DashboardLayoutManager';
|
import { DashboardLayoutManager } from '../types/DashboardLayoutManager';
|
||||||
|
import { LayoutRegistryItem } from '../types/LayoutRegistryItem';
|
||||||
|
|
||||||
import { TabItem } from './TabItem';
|
import { TabItem } from './TabItem';
|
||||||
import { TabsLayoutManagerRenderer } from './TabsLayoutManagerRenderer';
|
import { TabsLayoutManagerRenderer } from './TabsLayoutManagerRenderer';
|
||||||
@ -16,7 +17,7 @@ export class TabsLayoutManager extends SceneObjectBase<TabsLayoutManagerState> i
|
|||||||
|
|
||||||
public readonly isDashboardLayoutManager = true;
|
public readonly isDashboardLayoutManager = true;
|
||||||
|
|
||||||
public static readonly descriptor = {
|
public static readonly descriptor: LayoutRegistryItem = {
|
||||||
get name() {
|
get name() {
|
||||||
return t('dashboard.tabs-layout.name', 'Tabs');
|
return t('dashboard.tabs-layout.name', 'Tabs');
|
||||||
},
|
},
|
||||||
@ -25,6 +26,8 @@ export class TabsLayoutManager extends SceneObjectBase<TabsLayoutManagerState> i
|
|||||||
},
|
},
|
||||||
id: 'tabs-layout',
|
id: 'tabs-layout',
|
||||||
createFromLayout: TabsLayoutManager.createFromLayout,
|
createFromLayout: TabsLayoutManager.createFromLayout,
|
||||||
|
|
||||||
|
kind: 'TabsLayout',
|
||||||
};
|
};
|
||||||
|
|
||||||
public readonly descriptor = TabsLayoutManager.descriptor;
|
public readonly descriptor = TabsLayoutManager.descriptor;
|
||||||
|
@ -0,0 +1,92 @@
|
|||||||
|
import { DashboardV2Spec } from '@grafana/schema/dist/esm/schema/dashboard/v2alpha0';
|
||||||
|
|
||||||
|
import { DefaultGridLayoutManager } from '../../scene/layout-default/DefaultGridLayoutManager';
|
||||||
|
import { ResponsiveGridLayoutManager } from '../../scene/layout-responsive-grid/ResponsiveGridLayoutManager';
|
||||||
|
import { RowsLayoutManager } from '../../scene/layout-rows/RowsLayoutManager';
|
||||||
|
import { TabsLayoutManager } from '../../scene/layout-tabs/TabsLayoutManager';
|
||||||
|
|
||||||
|
import { TabsLayoutSerializer } from './TabsLayoutSerializer';
|
||||||
|
|
||||||
|
describe('deserialization', () => {
|
||||||
|
it('should deserialize tabs layout with row child', () => {
|
||||||
|
const layout: DashboardV2Spec['layout'] = {
|
||||||
|
kind: 'TabsLayout',
|
||||||
|
spec: {
|
||||||
|
tabs: [{ kind: 'TabsLayoutTab', spec: { title: 'Tab 1', layout: { kind: 'RowsLayout', spec: { rows: [] } } } }],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const serializer = new TabsLayoutSerializer();
|
||||||
|
const deserialized = serializer.deserialize(layout, {}, false);
|
||||||
|
expect(deserialized).toBeInstanceOf(TabsLayoutManager);
|
||||||
|
expect(deserialized.state.tabs[0].state.layout).toBeInstanceOf(RowsLayoutManager);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should deserialize tabs layout with responsive grid child', () => {
|
||||||
|
const layout: DashboardV2Spec['layout'] = {
|
||||||
|
kind: 'TabsLayout',
|
||||||
|
spec: {
|
||||||
|
tabs: [
|
||||||
|
{
|
||||||
|
kind: 'TabsLayoutTab',
|
||||||
|
spec: { title: 'Tab 1', layout: { kind: 'ResponsiveGridLayout', spec: { row: '', col: '', items: [] } } },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const serializer = new TabsLayoutSerializer();
|
||||||
|
const deserialized = serializer.deserialize(layout, {}, false);
|
||||||
|
expect(deserialized).toBeInstanceOf(TabsLayoutManager);
|
||||||
|
expect(deserialized.state.tabs[0].state.layout).toBeInstanceOf(ResponsiveGridLayoutManager);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should deserialize tabs layout with default grid child', () => {
|
||||||
|
const layout: DashboardV2Spec['layout'] = {
|
||||||
|
kind: 'TabsLayout',
|
||||||
|
spec: {
|
||||||
|
tabs: [
|
||||||
|
{
|
||||||
|
kind: 'TabsLayoutTab',
|
||||||
|
spec: { title: 'Tab 1', layout: { kind: 'GridLayout', spec: { items: [] } } },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const serializer = new TabsLayoutSerializer();
|
||||||
|
const deserialized = serializer.deserialize(layout, {}, false);
|
||||||
|
expect(deserialized).toBeInstanceOf(TabsLayoutManager);
|
||||||
|
expect(deserialized.state.tabs[0].state.layout).toBeInstanceOf(DefaultGridLayoutManager);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should handle multiple tabs', () => {
|
||||||
|
const layout: DashboardV2Spec['layout'] = {
|
||||||
|
kind: 'TabsLayout',
|
||||||
|
spec: {
|
||||||
|
tabs: [
|
||||||
|
{
|
||||||
|
kind: 'TabsLayoutTab',
|
||||||
|
spec: { title: 'Tab 1', layout: { kind: 'ResponsiveGridLayout', spec: { row: '', col: '', items: [] } } },
|
||||||
|
},
|
||||||
|
{ kind: 'TabsLayoutTab', spec: { title: 'Tab 2', layout: { kind: 'GridLayout', spec: { items: [] } } } },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const serializer = new TabsLayoutSerializer();
|
||||||
|
const deserialized = serializer.deserialize(layout, {}, false);
|
||||||
|
expect(deserialized).toBeInstanceOf(TabsLayoutManager);
|
||||||
|
expect(deserialized.state.tabs[0].state.layout).toBeInstanceOf(ResponsiveGridLayoutManager);
|
||||||
|
expect(deserialized.state.tabs[1].state.layout).toBeInstanceOf(DefaultGridLayoutManager);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should handle 0 tabs', () => {
|
||||||
|
const layout: DashboardV2Spec['layout'] = {
|
||||||
|
kind: 'TabsLayout',
|
||||||
|
spec: {
|
||||||
|
tabs: [],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const serializer = new TabsLayoutSerializer();
|
||||||
|
const deserialized = serializer.deserialize(layout, {}, false);
|
||||||
|
expect(deserialized).toBeInstanceOf(TabsLayoutManager);
|
||||||
|
expect(deserialized.state.tabs).toHaveLength(0);
|
||||||
|
});
|
||||||
|
});
|
@ -0,0 +1,49 @@
|
|||||||
|
import { DashboardV2Spec } from '@grafana/schema/dist/esm/schema/dashboard/v2alpha0';
|
||||||
|
|
||||||
|
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';
|
||||||
|
|
||||||
|
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);
|
||||||
|
if (layout.kind === 'TabsLayout') {
|
||||||
|
throw new Error('Nested TabsLayout is not supported');
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
kind: 'TabsLayoutTab',
|
||||||
|
spec: {
|
||||||
|
title: tab.state.title,
|
||||||
|
layout: layout,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
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),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return new TabsLayoutManager({ tabs, currentTab: tabs[0] });
|
||||||
|
}
|
||||||
|
}
|
@ -5,6 +5,7 @@ import { LayoutManagerSerializer } from '../../scene/types/DashboardLayoutManage
|
|||||||
import { DefaultGridLayoutManagerSerializer } from './DefaultGridLayoutSerializer';
|
import { DefaultGridLayoutManagerSerializer } from './DefaultGridLayoutSerializer';
|
||||||
import { ResponsiveGridLayoutSerializer } from './ResponsiveGridLayoutSerializer';
|
import { ResponsiveGridLayoutSerializer } from './ResponsiveGridLayoutSerializer';
|
||||||
import { RowsLayoutSerializer } from './RowsLayoutSerializer';
|
import { RowsLayoutSerializer } from './RowsLayoutSerializer';
|
||||||
|
import { TabsLayoutSerializer } from './TabsLayoutSerializer';
|
||||||
|
|
||||||
interface LayoutSerializerRegistryItem extends RegistryItem {
|
interface LayoutSerializerRegistryItem extends RegistryItem {
|
||||||
serializer: LayoutManagerSerializer;
|
serializer: LayoutManagerSerializer;
|
||||||
@ -16,5 +17,6 @@ export const layoutSerializerRegistry: Registry<LayoutSerializerRegistryItem> =
|
|||||||
{ id: 'GridLayout', name: 'Grid Layout', serializer: new DefaultGridLayoutManagerSerializer() },
|
{ id: 'GridLayout', name: 'Grid Layout', serializer: new DefaultGridLayoutManagerSerializer() },
|
||||||
{ id: 'ResponsiveGridLayout', name: 'Responsive Grid Layout', serializer: new ResponsiveGridLayoutSerializer() },
|
{ id: 'ResponsiveGridLayout', name: 'Responsive Grid Layout', serializer: new ResponsiveGridLayoutSerializer() },
|
||||||
{ id: 'RowsLayout', name: 'Rows Layout', serializer: new RowsLayoutSerializer() },
|
{ id: 'RowsLayout', name: 'Rows Layout', serializer: new RowsLayoutSerializer() },
|
||||||
|
{ id: 'TabsLayout', name: 'Tabs Layout', serializer: new TabsLayoutSerializer() },
|
||||||
];
|
];
|
||||||
});
|
});
|
||||||
|
@ -38,6 +38,7 @@ import { DefaultGridLayoutManager } from '../scene/layout-default/DefaultGridLay
|
|||||||
import { ResponsiveGridItem } from '../scene/layout-responsive-grid/ResponsiveGridItem';
|
import { ResponsiveGridItem } from '../scene/layout-responsive-grid/ResponsiveGridItem';
|
||||||
import { ResponsiveGridLayoutManager } from '../scene/layout-responsive-grid/ResponsiveGridLayoutManager';
|
import { ResponsiveGridLayoutManager } from '../scene/layout-responsive-grid/ResponsiveGridLayoutManager';
|
||||||
import { RowsLayoutManager } from '../scene/layout-rows/RowsLayoutManager';
|
import { RowsLayoutManager } from '../scene/layout-rows/RowsLayoutManager';
|
||||||
|
import { TabsLayoutManager } from '../scene/layout-tabs/TabsLayoutManager';
|
||||||
import { DashboardLayoutManager } from '../scene/types/DashboardLayoutManager';
|
import { DashboardLayoutManager } from '../scene/types/DashboardLayoutManager';
|
||||||
import { dashboardSceneGraph } from '../utils/dashboardSceneGraph';
|
import { dashboardSceneGraph } from '../utils/dashboardSceneGraph';
|
||||||
import { getQueryRunnerFor } from '../utils/utils';
|
import { getQueryRunnerFor } from '../utils/utils';
|
||||||
@ -533,6 +534,52 @@ describe('transformSaveModelSchemaV2ToScene', () => {
|
|||||||
expect(gridItem.state.body.state.key).toBe('panel-1');
|
expect(gridItem.state.body.state.key).toBe('panel-1');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should build a dashboard scene with a tabs layout', () => {
|
||||||
|
const dashboard = cloneDeep(defaultDashboard);
|
||||||
|
dashboard.spec.layout = {
|
||||||
|
kind: 'TabsLayout',
|
||||||
|
spec: {
|
||||||
|
tabs: [
|
||||||
|
{
|
||||||
|
kind: 'TabsLayoutTab',
|
||||||
|
spec: {
|
||||||
|
title: 'tab1',
|
||||||
|
layout: {
|
||||||
|
kind: 'ResponsiveGridLayout',
|
||||||
|
spec: {
|
||||||
|
col: 'colString',
|
||||||
|
row: 'rowString',
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
kind: 'ResponsiveGridLayoutItem',
|
||||||
|
spec: {
|
||||||
|
element: {
|
||||||
|
kind: 'ElementReference',
|
||||||
|
name: 'panel-1',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const scene = transformSaveModelSchemaV2ToScene(dashboard);
|
||||||
|
const layoutManager = scene.state.body as TabsLayoutManager;
|
||||||
|
expect(layoutManager.descriptor.kind).toBe('TabsLayout');
|
||||||
|
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 ResponsiveGridLayoutManager;
|
||||||
|
expect(gridLayoutManager.state.layout.state.templateColumns).toBe('colString');
|
||||||
|
expect(gridLayoutManager.state.layout.state.autoRows).toBe('rowString');
|
||||||
|
expect(gridLayoutManager.state.layout.state.children.length).toBe(1);
|
||||||
|
const gridItem = gridLayoutManager.state.layout.state.children[0] as ResponsiveGridItem;
|
||||||
|
expect(gridItem.state.body.state.key).toBe('panel-1');
|
||||||
|
});
|
||||||
|
|
||||||
it('should build a dashboard scene with rows layout', () => {
|
it('should build a dashboard scene with rows layout', () => {
|
||||||
const dashboard = cloneDeep(defaultDashboard);
|
const dashboard = cloneDeep(defaultDashboard);
|
||||||
dashboard.spec.layout = {
|
dashboard.spec.layout = {
|
||||||
|
@ -26,8 +26,10 @@ import {
|
|||||||
} from '@grafana/schema/dist/esm/index.gen';
|
} from '@grafana/schema/dist/esm/index.gen';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
GridLayoutSpec,
|
||||||
ResponsiveGridLayoutSpec,
|
ResponsiveGridLayoutSpec,
|
||||||
RowsLayoutSpec,
|
RowsLayoutSpec,
|
||||||
|
TabsLayoutSpec,
|
||||||
} from '../../../../../packages/grafana-schema/src/schema/dashboard/v2alpha0';
|
} from '../../../../../packages/grafana-schema/src/schema/dashboard/v2alpha0';
|
||||||
import { DashboardEditPane } from '../edit-pane/DashboardEditPane';
|
import { DashboardEditPane } from '../edit-pane/DashboardEditPane';
|
||||||
import { DashboardAnnotationsDataLayer } from '../scene/DashboardAnnotationsDataLayer';
|
import { DashboardAnnotationsDataLayer } from '../scene/DashboardAnnotationsDataLayer';
|
||||||
@ -42,6 +44,8 @@ import { ResponsiveGridItem } from '../scene/layout-responsive-grid/ResponsiveGr
|
|||||||
import { ResponsiveGridLayoutManager } from '../scene/layout-responsive-grid/ResponsiveGridLayoutManager';
|
import { ResponsiveGridLayoutManager } from '../scene/layout-responsive-grid/ResponsiveGridLayoutManager';
|
||||||
import { RowItem } from '../scene/layout-rows/RowItem';
|
import { RowItem } from '../scene/layout-rows/RowItem';
|
||||||
import { RowsLayoutManager } from '../scene/layout-rows/RowsLayoutManager';
|
import { RowsLayoutManager } from '../scene/layout-rows/RowsLayoutManager';
|
||||||
|
import { TabItem } from '../scene/layout-tabs/TabItem';
|
||||||
|
import { TabsLayoutManager } from '../scene/layout-tabs/TabsLayoutManager';
|
||||||
import { DashboardLayoutManager } from '../scene/types/DashboardLayoutManager';
|
import { DashboardLayoutManager } from '../scene/types/DashboardLayoutManager';
|
||||||
|
|
||||||
import { transformSceneToSaveModelSchemaV2 } from './transformSceneToSaveModelSchemaV2';
|
import { transformSceneToSaveModelSchemaV2 } from './transformSceneToSaveModelSchemaV2';
|
||||||
@ -492,10 +496,12 @@ describe('dynamic layouts', () => {
|
|||||||
expect(rowsLayout.rows.length).toBe(2);
|
expect(rowsLayout.rows.length).toBe(2);
|
||||||
expect(rowsLayout.rows[0].kind).toBe('RowsLayoutRow');
|
expect(rowsLayout.rows[0].kind).toBe('RowsLayoutRow');
|
||||||
expect(rowsLayout.rows[0].spec.layout.kind).toBe('ResponsiveGridLayout');
|
expect(rowsLayout.rows[0].spec.layout.kind).toBe('ResponsiveGridLayout');
|
||||||
expect(rowsLayout.rows[0].spec.layout.spec.items[0].kind).toBe('ResponsiveGridLayoutItem');
|
const layout1 = rowsLayout.rows[0].spec.layout.spec as ResponsiveGridLayoutSpec;
|
||||||
|
expect(layout1.items[0].kind).toBe('ResponsiveGridLayoutItem');
|
||||||
|
|
||||||
expect(rowsLayout.rows[1].spec.layout.kind).toBe('GridLayout');
|
expect(rowsLayout.rows[1].spec.layout.kind).toBe('GridLayout');
|
||||||
expect(rowsLayout.rows[1].spec.layout.spec.items[0].kind).toBe('GridLayoutItem');
|
const layout2 = rowsLayout.rows[1].spec.layout.spec as GridLayoutSpec;
|
||||||
|
expect(layout2.items[0].kind).toBe('GridLayoutItem');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should transform scene with responsive grid layout to schema v2', () => {
|
it('should transform scene with responsive grid layout to schema v2', () => {
|
||||||
@ -525,6 +531,39 @@ describe('dynamic layouts', () => {
|
|||||||
expect(respGridLayout.items.length).toBe(2);
|
expect(respGridLayout.items.length).toBe(2);
|
||||||
expect(respGridLayout.items[0].kind).toBe('ResponsiveGridLayoutItem');
|
expect(respGridLayout.items[0].kind).toBe('ResponsiveGridLayoutItem');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should transform scene with tabs layout to schema v2', () => {
|
||||||
|
const tabs = [
|
||||||
|
new TabItem({
|
||||||
|
layout: new DefaultGridLayoutManager({
|
||||||
|
grid: new SceneGridLayout({
|
||||||
|
children: [
|
||||||
|
new DashboardGridItem({
|
||||||
|
y: 0,
|
||||||
|
height: 10,
|
||||||
|
body: new VizPanel({}),
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
];
|
||||||
|
|
||||||
|
const scene = setupDashboardScene(
|
||||||
|
getMinimalSceneState(
|
||||||
|
new TabsLayoutManager({
|
||||||
|
currentTab: tabs[0],
|
||||||
|
tabs,
|
||||||
|
})
|
||||||
|
)
|
||||||
|
);
|
||||||
|
const result = transformSceneToSaveModelSchemaV2(scene);
|
||||||
|
expect(result.layout.kind).toBe('TabsLayout');
|
||||||
|
const tabsLayout = result.layout.spec as TabsLayoutSpec;
|
||||||
|
expect(tabsLayout.tabs.length).toBe(1);
|
||||||
|
expect(tabsLayout.tabs[0].kind).toBe('TabsLayoutTab');
|
||||||
|
expect(tabsLayout.tabs[0].spec.layout.kind).toBe('GridLayout');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
const annotationLayer1 = new DashboardAnnotationsDataLayer({
|
const annotationLayer1 = new DashboardAnnotationsDataLayer({
|
||||||
|
Reference in New Issue
Block a user