mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Dashboard: Fix panel edits for repeats (#100658)
This commit is contained in:
parent
d0394bfa7e
commit
6bd1041cda
@ -22,7 +22,7 @@ describe('Solo Route', () => {
|
|||||||
cy.contains('uplot-main-div').should('not.exist');
|
cy.contains('uplot-main-div').should('not.exist');
|
||||||
});
|
});
|
||||||
|
|
||||||
/*it('Can view solo repeated panel in scenes', () => {
|
it('Can view solo repeated panel in scenes', () => {
|
||||||
// open Panel Tests - Graph NG
|
// open Panel Tests - Graph NG
|
||||||
e2e.pages.SoloPanel.visit(
|
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-0&__feature.dashboardSceneSolo=true'
|
||||||
@ -30,7 +30,7 @@ describe('Solo Route', () => {
|
|||||||
|
|
||||||
e2e.components.Panels.Panel.title('server=A').should('exist');
|
e2e.components.Panels.Panel.title('server=A').should('exist');
|
||||||
cy.contains('uplot-main-div').should('not.exist');
|
cy.contains('uplot-main-div').should('not.exist');
|
||||||
});*/
|
});
|
||||||
|
|
||||||
it('Can view solo in repeated row and panel in scenes', () => {
|
it('Can view solo in repeated row and panel in scenes', () => {
|
||||||
// open Panel Tests - Graph NG
|
// open Panel Tests - Graph NG
|
||||||
|
@ -5,7 +5,7 @@ import { SHARED_DASHBOARD_QUERY } from 'app/plugins/datasource/dashboard/constan
|
|||||||
import { MIXED_DATASOURCE_NAME } from 'app/plugins/datasource/mixed/MixedDataSource';
|
import { MIXED_DATASOURCE_NAME } from 'app/plugins/datasource/mixed/MixedDataSource';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
findVizPanelByKey,
|
findOriginalVizPanelByKey,
|
||||||
getDashboardSceneFor,
|
getDashboardSceneFor,
|
||||||
getLibraryPanelBehavior,
|
getLibraryPanelBehavior,
|
||||||
getQueryRunnerFor,
|
getQueryRunnerFor,
|
||||||
@ -53,7 +53,8 @@ export class DashboardDatasourceBehaviour extends SceneObjectBase<DashboardDatas
|
|||||||
// find the source panel referenced in the the dashboard ds query
|
// find the source panel referenced in the the dashboard ds query
|
||||||
const panelId = dashboardQuery.panelId;
|
const panelId = dashboardQuery.panelId;
|
||||||
const vizKey = getVizPanelKeyForPanelId(panelId);
|
const vizKey = getVizPanelKeyForPanelId(panelId);
|
||||||
const sourcePanel = findVizPanelByKey(dashboard, vizKey);
|
// We're trying to find the original panel, not a cloned one, since `panelId` alone cannot resolve clones
|
||||||
|
const sourcePanel = findOriginalVizPanelByKey(dashboard, vizKey);
|
||||||
|
|
||||||
if (!(sourcePanel instanceof VizPanel)) {
|
if (!(sourcePanel instanceof VizPanel)) {
|
||||||
return;
|
return;
|
||||||
|
@ -13,7 +13,7 @@ import { createDashboardEditViewFor } from '../settings/utils';
|
|||||||
import { ShareDrawer } from '../sharing/ShareDrawer/ShareDrawer';
|
import { ShareDrawer } from '../sharing/ShareDrawer/ShareDrawer';
|
||||||
import { ShareModal } from '../sharing/ShareModal';
|
import { ShareModal } from '../sharing/ShareModal';
|
||||||
import { containsCloneKey } from '../utils/clone';
|
import { containsCloneKey } from '../utils/clone';
|
||||||
import { findVizPanelByKey, getLibraryPanelBehavior } from '../utils/utils';
|
import { findEditPanel, findVizPanelByKey, getLibraryPanelBehavior } from '../utils/utils';
|
||||||
|
|
||||||
import { DashboardScene, DashboardSceneState } from './DashboardScene';
|
import { DashboardScene, DashboardSceneState } from './DashboardScene';
|
||||||
import { LibraryPanelBehavior } from './LibraryPanelBehavior';
|
import { LibraryPanelBehavior } from './LibraryPanelBehavior';
|
||||||
@ -124,7 +124,7 @@ export class DashboardSceneUrlSync implements SceneObjectUrlSyncHandler {
|
|||||||
|
|
||||||
// Handle edit panel state
|
// Handle edit panel state
|
||||||
if (typeof values.editPanel === 'string') {
|
if (typeof values.editPanel === 'string') {
|
||||||
const panel = findVizPanelByKey(this._scene, values.editPanel);
|
const panel = findEditPanel(this._scene, values.editPanel);
|
||||||
|
|
||||||
if (!panel) {
|
if (!panel) {
|
||||||
console.warn(`Panel ${values.editPanel} not found`);
|
console.warn(`Panel ${values.editPanel} not found`);
|
||||||
|
@ -21,6 +21,7 @@ import {
|
|||||||
joinCloneKeys,
|
joinCloneKeys,
|
||||||
getCloneKey,
|
getCloneKey,
|
||||||
isClonedKey,
|
isClonedKey,
|
||||||
|
getOriginalKey,
|
||||||
} from '../../utils/clone';
|
} from '../../utils/clone';
|
||||||
import { getMultiVariableValues } from '../../utils/utils';
|
import { getMultiVariableValues } from '../../utils/utils';
|
||||||
import { DashboardRepeatsProcessedEvent } from '../types/DashboardRepeatsProcessedEvent';
|
import { DashboardRepeatsProcessedEvent } from '../types/DashboardRepeatsProcessedEvent';
|
||||||
@ -257,7 +258,9 @@ function getRowContentHeight(panels: SceneGridItemLike[]): number {
|
|||||||
|
|
||||||
function updateLayout(layout: SceneGridLayout, rows: SceneGridRow[], maxYOfRows: number, rowKey: string) {
|
function updateLayout(layout: SceneGridLayout, rows: SceneGridRow[], maxYOfRows: number, rowKey: string) {
|
||||||
const allChildren = getLayoutChildrenFilterOutRepeatClones(layout, rowKey);
|
const allChildren = getLayoutChildrenFilterOutRepeatClones(layout, rowKey);
|
||||||
const index = allChildren.findIndex((child) => child.state.key!.includes(rowKey));
|
const index = allChildren.findIndex(
|
||||||
|
(child) => child instanceof SceneGridRow && getOriginalKey(child.state.key!) === getOriginalKey(rowKey)
|
||||||
|
);
|
||||||
|
|
||||||
if (index === -1) {
|
if (index === -1) {
|
||||||
throw new Error('RowRepeaterBehavior: Parent row not found in layout children');
|
throw new Error('RowRepeaterBehavior: Parent row not found in layout children');
|
||||||
@ -286,7 +289,9 @@ function updateLayout(layout: SceneGridLayout, rows: SceneGridRow[], maxYOfRows:
|
|||||||
}
|
}
|
||||||
|
|
||||||
function getLayoutChildrenFilterOutRepeatClones(layout: SceneGridLayout, rowKey: string) {
|
function getLayoutChildrenFilterOutRepeatClones(layout: SceneGridLayout, rowKey: string) {
|
||||||
return layout.state.children.filter((child) => !isClonedKeyOf(child.state.key!, rowKey));
|
return layout.state.children.filter(
|
||||||
|
(child) => !(child instanceof SceneGridRow) || !isClonedKeyOf(getLastKeyFromClone(child.state.key!), rowKey)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function ensureUniqueKeys(item: SceneGridItemLike, ancestors: string) {
|
function ensureUniqueKeys(item: SceneGridItemLike, ancestors: string) {
|
||||||
|
@ -21,7 +21,7 @@ import { panelMenuBehavior } from '../scene/PanelMenuBehavior';
|
|||||||
import { DashboardGridItem } from '../scene/layout-default/DashboardGridItem';
|
import { DashboardGridItem } from '../scene/layout-default/DashboardGridItem';
|
||||||
import { DashboardLayoutManager, isDashboardLayoutManager } from '../scene/types/DashboardLayoutManager';
|
import { DashboardLayoutManager, isDashboardLayoutManager } from '../scene/types/DashboardLayoutManager';
|
||||||
|
|
||||||
import { getOriginalKey, isClonedKey } from './clone';
|
import { containsCloneKey, getLastKeyFromClone, getOriginalKey, isInCloneChain } from './clone';
|
||||||
|
|
||||||
export const NEW_PANEL_HEIGHT = 8;
|
export const NEW_PANEL_HEIGHT = 8;
|
||||||
export const NEW_PANEL_WIDTH = 12;
|
export const NEW_PANEL_WIDTH = 12;
|
||||||
@ -68,12 +68,63 @@ function findVizPanelInternal(scene: SceneObject, key: string | undefined): VizP
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// It might be possible to have the keys changed in the meantime from `panel-2` to `panel-2-clone-0`
|
if (!(obj instanceof VizPanel)) {
|
||||||
// We need to check this as well
|
return false;
|
||||||
const originalObjectKey = !isClonedKey(objKey) ? getOriginalKey(objKey) : objKey;
|
}
|
||||||
const originalKey = !isClonedKey(key) ? getOriginalKey(key) : key;
|
|
||||||
|
|
||||||
if (originalObjectKey === originalKey) {
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (panel) {
|
||||||
|
if (panel instanceof VizPanel) {
|
||||||
|
return panel;
|
||||||
|
} else {
|
||||||
|
throw new Error(`Found panel with key ${key} but it was not a VizPanel`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function findOriginalVizPanelByKey(scene: SceneObject, key: string | undefined): VizPanel | null {
|
||||||
|
if (!key) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
let panel: VizPanel | null = findOriginalVizPanelInternal(scene, key);
|
||||||
|
|
||||||
|
if (panel) {
|
||||||
|
return panel;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Also try to find by panel id
|
||||||
|
const id = parseInt(key, 10);
|
||||||
|
if (isNaN(id)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const panelId = getVizPanelKeyForPanelId(id);
|
||||||
|
panel = findVizPanelInternal(scene, panelId);
|
||||||
|
|
||||||
|
if (panel) {
|
||||||
|
return panel;
|
||||||
|
}
|
||||||
|
|
||||||
|
panel = findOriginalVizPanelInternal(scene, panelId);
|
||||||
|
|
||||||
|
return panel;
|
||||||
|
}
|
||||||
|
|
||||||
|
function findOriginalVizPanelInternal(scene: SceneObject, key: string | undefined): VizPanel | null {
|
||||||
|
if (!key) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const panel = sceneGraph.findObject(scene, (obj) => {
|
||||||
|
const objKey = obj.state.key!;
|
||||||
|
|
||||||
|
// Compare the original keys
|
||||||
|
if (objKey === key || (!isInCloneChain(objKey) && getOriginalKey(objKey) === getOriginalKey(key))) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -95,6 +146,48 @@ function findVizPanelInternal(scene: SceneObject, key: string | undefined): VizP
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function findEditPanel(scene: SceneObject, key: string | undefined): VizPanel | null {
|
||||||
|
if (!key) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// First we try to find the non-cloned panel
|
||||||
|
// This means it is either in not in a repeat chain or every item in the chain is not a clone
|
||||||
|
let panel: SceneObject | null = findOriginalVizPanelByKey(scene, key);
|
||||||
|
if (!panel || !panel.state.key) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the actual panel key, without any of the ancestors
|
||||||
|
const panelKey = getLastKeyFromClone(panel.state.key);
|
||||||
|
|
||||||
|
// If the panel contains clone in the key, this means it's a repeated panel, and we need to find the original panel
|
||||||
|
if (containsCloneKey(panelKey)) {
|
||||||
|
// Get the original key of the panel that we are looking for
|
||||||
|
const originalPanelKey = getOriginalKey(panelKey);
|
||||||
|
// Start the search from the parent to avoid unnecessary checks
|
||||||
|
// The parent usually is the grid item where the referenced panel is also located
|
||||||
|
panel = sceneGraph.findObject(panel.parent ?? scene, (sceneObject) => {
|
||||||
|
if (!sceneObject.state.key || isInCloneChain(sceneObject.state.key)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const currentLastKey = getLastKeyFromClone(sceneObject.state.key);
|
||||||
|
if (containsCloneKey(currentLastKey)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return getOriginalKey(currentLastKey) === originalPanelKey;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(panel instanceof VizPanel)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return panel;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Force re-render children. This is useful in some edge case scenarios when
|
* Force re-render children. This is useful in some edge case scenarios when
|
||||||
* children deep down the scene graph needs to be re-rendered when some parent state change.
|
* children deep down the scene graph needs to be re-rendered when some parent state change.
|
||||||
|
@ -15,7 +15,7 @@ import {
|
|||||||
import { SceneDataProvider, SceneDataTransformer, SceneObject } from '@grafana/scenes';
|
import { SceneDataProvider, SceneDataTransformer, SceneObject } from '@grafana/scenes';
|
||||||
import {
|
import {
|
||||||
activateSceneObjectAndParentTree,
|
activateSceneObjectAndParentTree,
|
||||||
findVizPanelByKey,
|
findOriginalVizPanelByKey,
|
||||||
getVizPanelKeyForPanelId,
|
getVizPanelKeyForPanelId,
|
||||||
} from 'app/features/dashboard-scene/utils/utils';
|
} from 'app/features/dashboard-scene/utils/utils';
|
||||||
|
|
||||||
@ -109,7 +109,8 @@ export class DashboardDatasource extends DataSourceApi<DashboardQuery> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private findSourcePanel(scene: SceneObject, panelId: number) {
|
private findSourcePanel(scene: SceneObject, panelId: number) {
|
||||||
return findVizPanelByKey(scene, getVizPanelKeyForPanelId(panelId));
|
// We're trying to find the original panel, not a cloned one, since `panelId` alone cannot resolve clones
|
||||||
|
return findOriginalVizPanelByKey(scene, getVizPanelKeyForPanelId(panelId));
|
||||||
}
|
}
|
||||||
|
|
||||||
private emitFirstLoadedDataIfMixedDS(
|
private emitFirstLoadedDataIfMixedDS(
|
||||||
|
Loading…
Reference in New Issue
Block a user