mirror of
https://github.com/grafana/grafana.git
synced 2025-09-16 05:29:06 +08:00
Repeating: Minor refactoring and unification for DashboardGridItem and AutoGridItem (#109723)
* Repeating: Refactoring and unification * Update * update * fix e2e * fixes * Update * adjust e2e test --------- Co-authored-by: Sergej-Vlasov <sergej.s.vlasov@gmail.com>
This commit is contained in:
@ -35,12 +35,12 @@ test.describe(
|
||||
test('Can view solo repeated panel in scenes', async ({ page, selectors }) => {
|
||||
// open Panel Tests - Graph NG
|
||||
const soloPanelUrl = selectors.pages.SoloPanel.url(
|
||||
'templating-repeating-panels/templating-repeating-panels?orgId=1&from=1699934989607&to=1699956589607&panelId=panel-2-clone-0&__feature.dashboardSceneSolo=true'
|
||||
'templating-repeating-panels/templating-repeating-panels?orgId=1&from=1699934989607&to=1699956589607&panelId=panel-2-clone-1&__feature.dashboardSceneSolo=true'
|
||||
);
|
||||
await page.goto(soloPanelUrl);
|
||||
|
||||
// Check that the panel title exists
|
||||
const panelTitle = page.getByTestId(selectors.components.Panels.Panel.title('server=A'));
|
||||
const panelTitle = page.getByTestId(selectors.components.Panels.Panel.title('server=B'));
|
||||
await expect(panelTitle).toBeVisible();
|
||||
|
||||
// Check that uplot-main-div does not exist
|
||||
|
@ -25,10 +25,10 @@ describe('Solo Route', () => {
|
||||
it('Can view solo repeated panel in scenes', () => {
|
||||
// open Panel Tests - Graph NG
|
||||
e2e.pages.SoloPanel.visit(
|
||||
'templating-repeating-panels/templating-repeating-panels?orgId=1&from=1699934989607&to=1699956589607&panelId=panel-2-clone-0&__feature.dashboardSceneSolo=true'
|
||||
'templating-repeating-panels/templating-repeating-panels?orgId=1&from=1699934989607&to=1699956589607&panelId=panel-2-clone-1&__feature.dashboardSceneSolo=true'
|
||||
);
|
||||
|
||||
e2e.components.Panels.Panel.title('server=A').should('exist');
|
||||
e2e.components.Panels.Panel.title('server=B').should('exist');
|
||||
cy.contains('uplot-main-div').should('not.exist');
|
||||
});
|
||||
|
||||
|
@ -25,10 +25,10 @@ describe('Solo Route', () => {
|
||||
it('Can view solo repeated panel in scenes', () => {
|
||||
// open Panel Tests - Graph NG
|
||||
e2e.pages.SoloPanel.visit(
|
||||
'templating-repeating-panels/templating-repeating-panels?orgId=1&from=1699934989607&to=1699956589607&panelId=panel-2-clone-0&__feature.dashboardSceneSolo=true'
|
||||
'templating-repeating-panels/templating-repeating-panels?orgId=1&from=1699934989607&to=1699956589607&panelId=panel-2-clone-1&__feature.dashboardSceneSolo=true'
|
||||
);
|
||||
|
||||
e2e.components.Panels.Panel.title('server=A').should('exist');
|
||||
e2e.components.Panels.Panel.title('server=B').should('exist');
|
||||
cy.contains('uplot-main-div').should('not.exist');
|
||||
});
|
||||
|
||||
|
@ -3,21 +3,18 @@ import React from 'react';
|
||||
|
||||
import {
|
||||
CustomVariable,
|
||||
LocalValueVariable,
|
||||
MultiValueVariable,
|
||||
sceneGraph,
|
||||
SceneObjectBase,
|
||||
SceneObjectState,
|
||||
SceneVariableSet,
|
||||
VariableDependencyConfig,
|
||||
VariableValueSingle,
|
||||
VizPanel,
|
||||
VizPanelState,
|
||||
} from '@grafana/scenes';
|
||||
import { OptionsPaneCategoryDescriptor } from 'app/features/dashboard/components/PanelEditor/OptionsPaneCategoryDescriptor';
|
||||
|
||||
import { ConditionalRendering } from '../../conditional-rendering/ConditionalRendering';
|
||||
import { getCloneKey } from '../../utils/clone';
|
||||
import { getCloneKey, getLocalVariableValueSet } from '../../utils/clone';
|
||||
import { getMultiVariableValues } from '../../utils/utils';
|
||||
import { scrollCanvasElementIntoView } from '../layouts-shared/scrollCanvasElementIntoView';
|
||||
import { DashboardLayoutItem } from '../types/DashboardLayoutItem';
|
||||
@ -113,21 +110,19 @@ export class AutoGridItem extends SceneObjectBase<AutoGridItemState> implements
|
||||
|
||||
const variableValues = values.length ? values : emptyVariablePlaceholderOption.values;
|
||||
const variableTexts = texts.length ? texts : emptyVariablePlaceholderOption.texts;
|
||||
|
||||
// Loop through variable values and create repeats
|
||||
for (let index = 0; index < variableValues.length; index++) {
|
||||
const cloneState: Partial<VizPanelState> = {
|
||||
$variables: new SceneVariableSet({
|
||||
variables: [
|
||||
new LocalValueVariable({
|
||||
name: variable.state.name,
|
||||
value: variableValues[index],
|
||||
text: String(variableTexts[index]),
|
||||
}),
|
||||
],
|
||||
}),
|
||||
key: getCloneKey(panelToRepeat.state.key!, index),
|
||||
};
|
||||
const clone = panelToRepeat.clone(cloneState);
|
||||
repeatedPanels.push(clone);
|
||||
const isSource = index === 0;
|
||||
const clone = isSource
|
||||
? panelToRepeat
|
||||
: panelToRepeat.clone({ key: getCloneKey(panelToRepeat.state.key!, index) });
|
||||
|
||||
clone.setState({ $variables: getLocalVariableValueSet(variable, variableValues[index], variableTexts[index]) });
|
||||
|
||||
if (index > 0) {
|
||||
repeatedPanels.push(clone);
|
||||
}
|
||||
}
|
||||
|
||||
this.setState({ repeatedPanels });
|
||||
@ -136,6 +131,10 @@ export class AutoGridItem extends SceneObjectBase<AutoGridItemState> implements
|
||||
this.publishEvent(new DashboardRepeatsProcessedEvent({ source: this }), true);
|
||||
}
|
||||
|
||||
public getPanelCount() {
|
||||
return (this.state.repeatedPanels?.length ?? 0) + 1;
|
||||
}
|
||||
|
||||
public setRepeatByVariable(variableName: string | undefined) {
|
||||
const stateUpdate: Partial<AutoGridItemState> = { variableName };
|
||||
|
||||
@ -172,13 +171,6 @@ export class AutoGridItem extends SceneObjectBase<AutoGridItemState> implements
|
||||
if (!this.state.variableName) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ((this.state.repeatedPanels?.length ?? 0) > 1) {
|
||||
this.state.body.setState({
|
||||
$variables: this.state.repeatedPanels![0].state.$variables?.clone(),
|
||||
$data: this.state.repeatedPanels![0].state.$data?.clone(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public editingCompleted(withChanges: boolean) {
|
||||
|
@ -13,7 +13,7 @@ import { AutoGridItem } from './AutoGridItem';
|
||||
import { DRAGGED_ITEM_HEIGHT, DRAGGED_ITEM_LEFT, DRAGGED_ITEM_TOP, DRAGGED_ITEM_WIDTH } from './const';
|
||||
|
||||
export function AutoGridItemRenderer({ model }: SceneComponentProps<AutoGridItem>) {
|
||||
const { body, repeatedPanels, key } = model.useState();
|
||||
const { body, repeatedPanels = [], key } = model.useState();
|
||||
const { draggingKey } = model.getParentGrid().useState();
|
||||
const { isEditing, preload } = useDashboardState(model);
|
||||
const [isConditionallyHidden, conditionalRenderingClass, conditionalRenderingOverlay] =
|
||||
@ -69,20 +69,19 @@ export function AutoGridItemRenderer({ model }: SceneComponentProps<AutoGridItem
|
||||
const isDragging = !!draggingKey;
|
||||
const isDragged = draggingKey === key;
|
||||
|
||||
return repeatedPanels ? (
|
||||
return (
|
||||
<>
|
||||
{repeatedPanels.map((item, index) => (
|
||||
<Wrapper item={body} addDndContainer={true} key={body.state.key!} isDragged={isDragged} isDragging={isDragging} />
|
||||
{repeatedPanels.map((item) => (
|
||||
<Wrapper
|
||||
item={item}
|
||||
addDndContainer={index === 0}
|
||||
addDndContainer={false}
|
||||
key={item.state.key!}
|
||||
isDragged={isDragged}
|
||||
isDragging={isDragging}
|
||||
/>
|
||||
))}
|
||||
</>
|
||||
) : (
|
||||
<Wrapper item={body} addDndContainer key={body.state.key!} isDragged={isDragged} isDragging={isDragging} />
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -32,17 +32,17 @@ describe('PanelRepeaterGridItem', () => {
|
||||
|
||||
activateFullSceneTree(scene);
|
||||
|
||||
expect(repeater.state.repeatedPanels?.length).toBe(5);
|
||||
expect(repeater.state.repeatedPanels?.length).toBe(4);
|
||||
|
||||
const panel1 = repeater.state.repeatedPanels![0];
|
||||
const panel2 = repeater.state.repeatedPanels![1];
|
||||
const panel1 = repeater.state.body;
|
||||
const panel2 = repeater.state.repeatedPanels![0];
|
||||
|
||||
// Panels should have scoped variables
|
||||
expect(panel1.state.$variables?.state.variables[0].getValue()).toBe('1');
|
||||
expect(panel1.state.$variables?.state.variables[0].getValueText?.()).toBe('A');
|
||||
expect(panel2.state.$variables?.state.variables[0].getValue()).toBe('2');
|
||||
|
||||
expect(isInCloneChain(panel1.state.key!)).toBe(false);
|
||||
expect(panel1.state.key).toBe('panel-1');
|
||||
expect(isInCloneChain(panel2.state.key!)).toBe(true);
|
||||
});
|
||||
|
||||
@ -55,7 +55,7 @@ describe('PanelRepeaterGridItem', () => {
|
||||
|
||||
await new Promise((r) => setTimeout(r, 10));
|
||||
|
||||
expect(repeater.state.repeatedPanels?.length).toBe(5);
|
||||
expect(repeater.state.repeatedPanels?.length).toBe(4);
|
||||
});
|
||||
|
||||
it('Should pass isMulti/includeAll values if variable is multi variable and has them set', async () => {
|
||||
@ -67,7 +67,7 @@ describe('PanelRepeaterGridItem', () => {
|
||||
|
||||
await new Promise((r) => setTimeout(r, 10));
|
||||
|
||||
expect(repeater.state.repeatedPanels?.length).toBe(5);
|
||||
expect(repeater.state.repeatedPanels?.length).toBe(4);
|
||||
|
||||
// LocalValueVariableState is not exposed, so we build this type casting
|
||||
const variableState = repeater.state.repeatedPanels![0].state.$variables?.state.variables[0].state as {
|
||||
@ -79,18 +79,6 @@ describe('PanelRepeaterGridItem', () => {
|
||||
expect(variableState.includeAll).toBe(true);
|
||||
});
|
||||
|
||||
it('Should display a panel when there are no options', async () => {
|
||||
const { scene, repeater } = buildPanelRepeaterScene({ variableQueryTime: 1, numberOfOptions: 0 });
|
||||
|
||||
activateFullSceneTree(scene);
|
||||
|
||||
expect(repeater.state.repeatedPanels?.length).toBe(0);
|
||||
|
||||
await new Promise((r) => setTimeout(r, 100));
|
||||
|
||||
expect(repeater.state.repeatedPanels?.length).toBe(1);
|
||||
});
|
||||
|
||||
it('Should redo the repeat when editing panel and then returning to dashboard', async () => {
|
||||
const panel = new DashboardGridItem({
|
||||
variableName: 'server',
|
||||
@ -130,7 +118,7 @@ describe('PanelRepeaterGridItem', () => {
|
||||
|
||||
await new Promise((r) => setTimeout(r, 10));
|
||||
|
||||
expect(panel.state.repeatedPanels?.length).toBe(5);
|
||||
expect(panel.state.repeatedPanels?.length).toBe(4);
|
||||
|
||||
const vizPanel = panel.state.body as VizPanel;
|
||||
|
||||
@ -150,7 +138,7 @@ describe('PanelRepeaterGridItem', () => {
|
||||
|
||||
await new Promise((r) => setTimeout(r, 10));
|
||||
|
||||
expect(panel.state.repeatedPanels?.length).toBe(5);
|
||||
expect(panel.state.repeatedPanels?.length).toBe(4);
|
||||
expect((panel.state.repeatedPanels![0] as VizPanel).state.title).toBe('Changed');
|
||||
});
|
||||
|
||||
@ -203,7 +191,7 @@ describe('PanelRepeaterGridItem', () => {
|
||||
|
||||
await new Promise((r) => setTimeout(r, 10));
|
||||
|
||||
expect(panel.state.repeatedPanels?.length).toBe(5);
|
||||
expect(panel.state.repeatedPanels?.length).toBe(4);
|
||||
|
||||
const vizPanel = panel.state.body as VizPanel;
|
||||
|
||||
@ -226,27 +214,10 @@ describe('PanelRepeaterGridItem', () => {
|
||||
await new Promise((r) => setTimeout(r, 10));
|
||||
|
||||
expect(performRepeatMock).toHaveBeenCalledTimes(1); // only for the edited panel
|
||||
expect(panel.state.repeatedPanels?.length).toBe(5);
|
||||
expect(panel.state.repeatedPanels?.length).toBe(4);
|
||||
expect((panel.state.repeatedPanels![0] as VizPanel).state.title).toBe('Changed');
|
||||
});
|
||||
|
||||
it('Should display a panel when there are variable errors', () => {
|
||||
const { scene, repeater } = buildPanelRepeaterScene({
|
||||
variableQueryTime: 0,
|
||||
numberOfOptions: 0,
|
||||
throwError: 'Error',
|
||||
});
|
||||
|
||||
// we expect console.error when variable encounters an error
|
||||
const origError = console.error;
|
||||
console.error = jest.fn();
|
||||
|
||||
activateFullSceneTree(scene);
|
||||
|
||||
expect(repeater.state.repeatedPanels?.length).toBe(1);
|
||||
console.error = origError;
|
||||
});
|
||||
|
||||
it('Should display a panel when there are variable errors async query', async () => {
|
||||
const { scene, repeater } = buildPanelRepeaterScene({
|
||||
variableQueryTime: 1,
|
||||
@ -262,7 +233,7 @@ describe('PanelRepeaterGridItem', () => {
|
||||
|
||||
await new Promise((r) => setTimeout(r, 10));
|
||||
|
||||
expect(repeater.state.repeatedPanels?.length).toBe(1);
|
||||
expect(repeater.state.body.state.$variables?.state.variables[0].getValue()).toBe('');
|
||||
console.error = origError;
|
||||
});
|
||||
|
||||
@ -346,14 +317,14 @@ describe('PanelRepeaterGridItem', () => {
|
||||
|
||||
variable.changeValueTo(['1', '3'], ['A', 'C']);
|
||||
|
||||
expect(repeater.state.repeatedPanels?.length).toBe(2);
|
||||
expect(repeater.state.repeatedPanels?.length).toBe(1);
|
||||
});
|
||||
|
||||
it('Should fall back to default variable if specified variable cannot be found', () => {
|
||||
const { scene, repeater } = buildPanelRepeaterScene({ variableQueryTime: 0 });
|
||||
scene.setState({ $variables: undefined });
|
||||
activateFullSceneTree(scene);
|
||||
expect(repeater.state.repeatedPanels?.[0].state.$variables?.state.variables[0].state.name).toBe(
|
||||
expect(repeater.state.body.state.$variables?.state.variables[0].state.name).toBe(
|
||||
'_____default_sys_repeat_var_____'
|
||||
);
|
||||
});
|
||||
|
@ -6,20 +6,17 @@ import {
|
||||
VizPanel,
|
||||
SceneObjectBase,
|
||||
SceneGridLayout,
|
||||
SceneVariableSet,
|
||||
SceneGridItemStateLike,
|
||||
SceneGridItemLike,
|
||||
sceneGraph,
|
||||
MultiValueVariable,
|
||||
LocalValueVariable,
|
||||
CustomVariable,
|
||||
VizPanelState,
|
||||
VariableValueSingle,
|
||||
} from '@grafana/scenes';
|
||||
import { GRID_COLUMN_COUNT } from 'app/core/constants';
|
||||
import { OptionsPaneCategoryDescriptor } from 'app/features/dashboard/components/PanelEditor/OptionsPaneCategoryDescriptor';
|
||||
|
||||
import { getCloneKey } from '../../utils/clone';
|
||||
import { getCloneKey, getLocalVariableValueSet } from '../../utils/clone';
|
||||
import { getMultiVariableValues } from '../../utils/utils';
|
||||
import { scrollCanvasElementIntoView, scrollIntoView } from '../layouts-shared/scrollCanvasElementIntoView';
|
||||
import { DashboardLayoutItem } from '../types/DashboardLayoutItem';
|
||||
@ -86,13 +83,12 @@ export class DashboardGridItem
|
||||
return;
|
||||
}
|
||||
|
||||
const itemCount = this.state.repeatedPanels?.length ?? 1;
|
||||
const stateChange: Partial<DashboardGridItemState> = {};
|
||||
|
||||
if (this.getRepeatDirection() === 'v') {
|
||||
stateChange.itemHeight = Math.ceil(newState.height! / itemCount);
|
||||
stateChange.itemHeight = Math.ceil(newState.height! / this.getPanelCount());
|
||||
} else {
|
||||
const rowCount = Math.ceil(itemCount / this.getMaxPerRow());
|
||||
const rowCount = Math.ceil(this.getPanelCount() / this.getMaxPerRow());
|
||||
stateChange.itemHeight = Math.ceil(newState.height! / rowCount);
|
||||
}
|
||||
|
||||
@ -101,6 +97,10 @@ export class DashboardGridItem
|
||||
}
|
||||
}
|
||||
|
||||
public getPanelCount() {
|
||||
return (this.state.repeatedPanels?.length ?? 0) + 1;
|
||||
}
|
||||
|
||||
public getClassName(): string {
|
||||
return this.state.variableName ? 'panel-repeater-grid-item' : '';
|
||||
}
|
||||
@ -117,13 +117,6 @@ export class DashboardGridItem
|
||||
if (!this.state.variableName) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.state.repeatedPanels?.length ?? 0 > 1) {
|
||||
this.state.body.setState({
|
||||
$variables: this.state.repeatedPanels![0].state.$variables?.clone(),
|
||||
$data: this.state.repeatedPanels![0].state.$data?.clone(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public editingCompleted(withChanges: boolean) {
|
||||
@ -177,22 +170,16 @@ export class DashboardGridItem
|
||||
|
||||
// Loop through variable values and create repeats
|
||||
for (let index = 0; index < variableValues.length; index++) {
|
||||
const cloneState: Partial<VizPanelState> = {
|
||||
$variables: new SceneVariableSet({
|
||||
variables: [
|
||||
new LocalValueVariable({
|
||||
name: variable.state.name,
|
||||
value: variableValues[index],
|
||||
text: String(variableTexts[index]),
|
||||
isMulti: variable.state.isMulti,
|
||||
includeAll: variable.state.includeAll,
|
||||
}),
|
||||
],
|
||||
}),
|
||||
key: getCloneKey(panelToRepeat.state.key!, index),
|
||||
};
|
||||
const clone = panelToRepeat.clone(cloneState);
|
||||
repeatedPanels.push(clone);
|
||||
const isSource = index === 0;
|
||||
const clone = isSource
|
||||
? panelToRepeat
|
||||
: panelToRepeat.clone({ key: getCloneKey(panelToRepeat.state.key!, index) });
|
||||
|
||||
clone.setState({ $variables: getLocalVariableValueSet(variable, variableValues[index], variableTexts[index]) });
|
||||
|
||||
if (index > 0) {
|
||||
repeatedPanels.push(clone);
|
||||
}
|
||||
}
|
||||
|
||||
const direction = this.getRepeatDirection();
|
||||
@ -200,12 +187,13 @@ export class DashboardGridItem
|
||||
const itemHeight = this.state.itemHeight ?? 10;
|
||||
const prevHeight = this.state.height;
|
||||
const maxPerRow = this.getMaxPerRow();
|
||||
const panelCount = repeatedPanels.length + 1; // +1 for the source panel
|
||||
|
||||
if (direction === 'h') {
|
||||
const rowCount = Math.ceil(repeatedPanels.length / maxPerRow);
|
||||
const rowCount = Math.ceil(panelCount / maxPerRow);
|
||||
stateChange.height = rowCount * itemHeight;
|
||||
} else {
|
||||
stateChange.height = repeatedPanels.length * itemHeight;
|
||||
stateChange.height = panelCount * itemHeight;
|
||||
}
|
||||
|
||||
this.setState(stateChange);
|
||||
|
@ -2,32 +2,33 @@ import { css } from '@emotion/css';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
import { config } from '@grafana/runtime';
|
||||
import { SceneComponentProps, VizPanel } from '@grafana/scenes';
|
||||
import { SceneComponentProps } from '@grafana/scenes';
|
||||
import { GRID_CELL_HEIGHT, GRID_CELL_VMARGIN } from 'app/core/constants';
|
||||
|
||||
import { DashboardGridItem, RepeatDirection } from './DashboardGridItem';
|
||||
|
||||
export function DashboardGridItemRenderer({ model }: SceneComponentProps<DashboardGridItem>) {
|
||||
const { repeatedPanels, itemHeight, variableName, body } = model.useState();
|
||||
const itemCount = repeatedPanels?.length ?? 0;
|
||||
const layoutStyle = useLayoutStyle(model.getRepeatDirection(), itemCount, model.getMaxPerRow(), itemHeight ?? 10);
|
||||
const { repeatedPanels = [], itemHeight, variableName, body } = model.useState();
|
||||
const layoutStyle = useLayoutStyle(
|
||||
model.getRepeatDirection(),
|
||||
model.getPanelCount(),
|
||||
model.getMaxPerRow(),
|
||||
itemHeight ?? 10
|
||||
);
|
||||
|
||||
if (!variableName) {
|
||||
if (body instanceof VizPanel) {
|
||||
return (
|
||||
<div className={panelWrapper} ref={model.containerRef}>
|
||||
<body.Component model={body} key={body.state.key} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (!repeatedPanels) {
|
||||
return null;
|
||||
return (
|
||||
<div className={panelWrapper} ref={model.containerRef}>
|
||||
<body.Component model={body} key={body.state.key} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={layoutStyle} ref={model.containerRef}>
|
||||
<div className={panelWrapper} key={body.state.key}>
|
||||
<body.Component model={body} key={body.state.key} />
|
||||
</div>
|
||||
{repeatedPanels.map((panel) => (
|
||||
<div className={panelWrapper} key={panel.state.key}>
|
||||
<panel.Component model={panel} key={panel.state.key} />
|
||||
|
@ -1,7 +1,6 @@
|
||||
import { isEqual } from 'lodash';
|
||||
|
||||
import {
|
||||
LocalValueVariable,
|
||||
MultiValueVariable,
|
||||
sceneGraph,
|
||||
SceneGridItemLike,
|
||||
@ -9,7 +8,6 @@ import {
|
||||
SceneGridRow,
|
||||
SceneObjectBase,
|
||||
SceneObjectState,
|
||||
SceneVariableSet,
|
||||
VariableDependencyConfig,
|
||||
VariableValueSingle,
|
||||
} from '@grafana/scenes';
|
||||
@ -22,6 +20,7 @@ import {
|
||||
getCloneKey,
|
||||
isClonedKey,
|
||||
getOriginalKey,
|
||||
getLocalVariableValueSet,
|
||||
} from '../../utils/clone';
|
||||
import { getMultiVariableValues } from '../../utils/utils';
|
||||
import { DashboardRepeatsProcessedEvent } from '../types/DashboardRepeatsProcessedEvent';
|
||||
@ -173,17 +172,7 @@ export class RowRepeaterBehavior extends SceneObjectBase<RowRepeaterBehaviorStat
|
||||
|
||||
rowClone.setState({
|
||||
key: rowCloneKey,
|
||||
$variables: new SceneVariableSet({
|
||||
variables: [
|
||||
new LocalValueVariable({
|
||||
name: this.state.variableName,
|
||||
value: variableValues[rowIndex],
|
||||
text: String(variableTexts[rowIndex]),
|
||||
isMulti: variable.state.isMulti,
|
||||
includeAll: variable.state.includeAll,
|
||||
}),
|
||||
],
|
||||
}),
|
||||
$variables: getLocalVariableValueSet(variable, variableValues[rowIndex], variableTexts[rowIndex]),
|
||||
children: [],
|
||||
});
|
||||
|
||||
|
@ -1,17 +1,11 @@
|
||||
import { isEqual } from 'lodash';
|
||||
import { useEffect } from 'react';
|
||||
|
||||
import {
|
||||
MultiValueVariable,
|
||||
SceneVariableSet,
|
||||
LocalValueVariable,
|
||||
sceneGraph,
|
||||
VariableValueSingle,
|
||||
} from '@grafana/scenes';
|
||||
import { MultiValueVariable, sceneGraph, VariableValueSingle } from '@grafana/scenes';
|
||||
import { Spinner } from '@grafana/ui';
|
||||
|
||||
import { DashboardStateChangedEvent } from '../../edit-pane/shared';
|
||||
import { getCloneKey } from '../../utils/clone';
|
||||
import { getCloneKey, getLocalVariableValueSet } from '../../utils/clone';
|
||||
import { dashboardLog, getMultiVariableValues } from '../../utils/utils';
|
||||
import { DashboardRepeatsProcessedEvent } from '../types/DashboardRepeatsProcessedEvent';
|
||||
|
||||
@ -109,17 +103,7 @@ export function performRowRepeats(variable: MultiValueVariable, row: RowItem, co
|
||||
|
||||
rowClone.setState({
|
||||
key: rowCloneKey,
|
||||
$variables: new SceneVariableSet({
|
||||
variables: [
|
||||
new LocalValueVariable({
|
||||
name: variable.state.name,
|
||||
value: variableValues[rowIndex],
|
||||
text: String(variableTexts[rowIndex]),
|
||||
isMulti: variable.state.isMulti,
|
||||
includeAll: variable.state.includeAll,
|
||||
}),
|
||||
],
|
||||
}),
|
||||
$variables: getLocalVariableValueSet(variable, variableValues[rowIndex], variableTexts[rowIndex]),
|
||||
layout,
|
||||
});
|
||||
|
||||
|
@ -3,17 +3,11 @@ import { isEqual } from 'lodash';
|
||||
import { useEffect } from 'react';
|
||||
|
||||
import { t } from '@grafana/i18n';
|
||||
import {
|
||||
MultiValueVariable,
|
||||
SceneVariableSet,
|
||||
LocalValueVariable,
|
||||
sceneGraph,
|
||||
VariableValueSingle,
|
||||
} from '@grafana/scenes';
|
||||
import { MultiValueVariable, sceneGraph, VariableValueSingle } from '@grafana/scenes';
|
||||
import { Spinner, Tooltip, useStyles2 } from '@grafana/ui';
|
||||
|
||||
import { DashboardStateChangedEvent } from '../../edit-pane/shared';
|
||||
import { getCloneKey } from '../../utils/clone';
|
||||
import { getCloneKey, getLocalVariableValueSet } from '../../utils/clone';
|
||||
import { dashboardLog, getMultiVariableValues } from '../../utils/utils';
|
||||
import { DashboardRepeatsProcessedEvent } from '../types/DashboardRepeatsProcessedEvent';
|
||||
|
||||
@ -164,17 +158,7 @@ export function createTabRepeats({
|
||||
|
||||
tabClone.setState({
|
||||
key: tabCloneKey,
|
||||
$variables: new SceneVariableSet({
|
||||
variables: [
|
||||
new LocalValueVariable({
|
||||
name: variable.state.name,
|
||||
value: variableValues[tabIndex],
|
||||
text: String(variableTexts[tabIndex]),
|
||||
isMulti: variable.state.isMulti,
|
||||
includeAll: variable.state.includeAll,
|
||||
}),
|
||||
],
|
||||
}),
|
||||
$variables: getLocalVariableValueSet(variable, variableValues[tabIndex], variableTexts[tabIndex]),
|
||||
layout,
|
||||
});
|
||||
|
||||
|
@ -792,7 +792,7 @@ describe('transformSceneToSaveModel', () => {
|
||||
|
||||
activateFullSceneTree(scene);
|
||||
|
||||
expect(repeater.state.repeatedPanels?.length).toBe(2);
|
||||
expect(repeater.state.repeatedPanels?.length).toBe(1);
|
||||
const result = panelRepeaterToPanels(repeater, true);
|
||||
|
||||
expect(result).toHaveLength(2);
|
||||
|
@ -329,48 +329,46 @@ export function panelRepeaterToPanels(repeater: DashboardGridItem, isSnapshot =
|
||||
return [vizPanelToPanel(repeater.state.body, { x, y, w, h }, isSnapshot)];
|
||||
}
|
||||
|
||||
if (repeater.state.repeatedPanels) {
|
||||
const { h, w, columnCount } = calculateGridItemDimensions(repeater);
|
||||
const panels = repeater.state.repeatedPanels!.map((panel, index) => {
|
||||
let x = 0,
|
||||
y = 0;
|
||||
if (repeater.state.repeatDirection === 'v') {
|
||||
x = repeater.state.x!;
|
||||
y = index * h;
|
||||
} else {
|
||||
x = (index % columnCount) * w;
|
||||
y = repeater.state.y! + Math.floor(index / columnCount) * h;
|
||||
}
|
||||
const vizPanels = [repeater.state.body, ...(repeater.state.repeatedPanels ?? [])];
|
||||
|
||||
const gridPos = { x, y, w, h };
|
||||
const { h, w, columnCount } = calculateGridItemDimensions(repeater);
|
||||
const panels = vizPanels.map((panel, index) => {
|
||||
let x = 0,
|
||||
y = 0;
|
||||
if (repeater.state.repeatDirection === 'v') {
|
||||
x = repeater.state.x!;
|
||||
y = index * h;
|
||||
} else {
|
||||
x = (index % columnCount) * w;
|
||||
y = repeater.state.y! + Math.floor(index / columnCount) * h;
|
||||
}
|
||||
|
||||
const localVariable = panel.state.$variables!.getByName(repeater.state.variableName!) as LocalValueVariable;
|
||||
const gridPos = { x, y, w, h };
|
||||
|
||||
const result: Panel = {
|
||||
id: getPanelIdForVizPanel(panel),
|
||||
type: panel.state.pluginId,
|
||||
title: panel.state.title,
|
||||
gridPos,
|
||||
options: panel.state.options,
|
||||
fieldConfig: (panel.state.fieldConfig as FieldConfigSource) ?? { defaults: {}, overrides: [] },
|
||||
transformations: [],
|
||||
transparent: panel.state.displayMode === 'transparent',
|
||||
// @ts-expect-error scopedVars are runtime only properties, not part of the persisted Dashboardmodel
|
||||
scopedVars: {
|
||||
[repeater.state.variableName!]: {
|
||||
text: localVariable?.state.text,
|
||||
value: localVariable?.state.value,
|
||||
},
|
||||
const localVariable = panel.state.$variables!.getByName(repeater.state.variableName!) as LocalValueVariable;
|
||||
|
||||
const result: Panel = {
|
||||
id: getPanelIdForVizPanel(panel),
|
||||
type: panel.state.pluginId,
|
||||
title: panel.state.title,
|
||||
gridPos,
|
||||
options: panel.state.options,
|
||||
fieldConfig: (panel.state.fieldConfig as FieldConfigSource) ?? { defaults: {}, overrides: [] },
|
||||
transformations: [],
|
||||
transparent: panel.state.displayMode === 'transparent',
|
||||
// @ts-expect-error scopedVars are runtime only properties, not part of the persisted Dashboardmodel
|
||||
scopedVars: {
|
||||
[repeater.state.variableName!]: {
|
||||
text: localVariable?.state.text,
|
||||
value: localVariable?.state.value,
|
||||
},
|
||||
...vizPanelDataToPanel(panel, isSnapshot),
|
||||
};
|
||||
return result;
|
||||
});
|
||||
},
|
||||
...vizPanelDataToPanel(panel, isSnapshot),
|
||||
};
|
||||
return result;
|
||||
});
|
||||
|
||||
return panels;
|
||||
}
|
||||
|
||||
return [];
|
||||
return panels;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,11 @@
|
||||
import { SceneObject } from '@grafana/scenes';
|
||||
import {
|
||||
LocalValueVariable,
|
||||
MultiValueVariableState,
|
||||
SceneObject,
|
||||
SceneVariable,
|
||||
SceneVariableSet,
|
||||
VariableValueSingle,
|
||||
} from '@grafana/scenes';
|
||||
|
||||
import { DashboardScene } from '../scene/DashboardScene';
|
||||
|
||||
@ -100,3 +107,21 @@ export function useHasClonedParents(scene: SceneObject): boolean {
|
||||
|
||||
return useHasClonedParents(scene.parent);
|
||||
}
|
||||
|
||||
export function getLocalVariableValueSet(
|
||||
variable: SceneVariable<MultiValueVariableState>,
|
||||
value: VariableValueSingle,
|
||||
text: VariableValueSingle
|
||||
): SceneVariableSet {
|
||||
return new SceneVariableSet({
|
||||
variables: [
|
||||
new LocalValueVariable({
|
||||
name: variable.state.name,
|
||||
value,
|
||||
text,
|
||||
isMulti: variable.state.isMulti,
|
||||
includeAll: variable.state.includeAll,
|
||||
}),
|
||||
],
|
||||
});
|
||||
}
|
||||
|
@ -143,6 +143,7 @@ export function buildPanelRepeaterScene(options: SceneOptions, source?: VizPanel
|
||||
new VizPanel({
|
||||
title: 'Panel $server',
|
||||
pluginId: 'timeseries',
|
||||
key: 'panel-1',
|
||||
}),
|
||||
x: options.x || 0,
|
||||
y: options.y || 0,
|
||||
|
Reference in New Issue
Block a user