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');
|
||||
});
|
||||
|
||||
/*it('Can view solo repeated panel in scenes', () => {
|
||||
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'
|
||||
@ -30,7 +30,7 @@ describe('Solo Route', () => {
|
||||
|
||||
e2e.components.Panels.Panel.title('server=A').should('exist');
|
||||
cy.contains('uplot-main-div').should('not.exist');
|
||||
});*/
|
||||
});
|
||||
|
||||
it('Can view solo in repeated row and panel in scenes', () => {
|
||||
// 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 {
|
||||
findVizPanelByKey,
|
||||
findOriginalVizPanelByKey,
|
||||
getDashboardSceneFor,
|
||||
getLibraryPanelBehavior,
|
||||
getQueryRunnerFor,
|
||||
@ -53,7 +53,8 @@ export class DashboardDatasourceBehaviour extends SceneObjectBase<DashboardDatas
|
||||
// find the source panel referenced in the the dashboard ds query
|
||||
const panelId = dashboardQuery.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)) {
|
||||
return;
|
||||
|
@ -13,7 +13,7 @@ import { createDashboardEditViewFor } from '../settings/utils';
|
||||
import { ShareDrawer } from '../sharing/ShareDrawer/ShareDrawer';
|
||||
import { ShareModal } from '../sharing/ShareModal';
|
||||
import { containsCloneKey } from '../utils/clone';
|
||||
import { findVizPanelByKey, getLibraryPanelBehavior } from '../utils/utils';
|
||||
import { findEditPanel, findVizPanelByKey, getLibraryPanelBehavior } from '../utils/utils';
|
||||
|
||||
import { DashboardScene, DashboardSceneState } from './DashboardScene';
|
||||
import { LibraryPanelBehavior } from './LibraryPanelBehavior';
|
||||
@ -124,7 +124,7 @@ export class DashboardSceneUrlSync implements SceneObjectUrlSyncHandler {
|
||||
|
||||
// Handle edit panel state
|
||||
if (typeof values.editPanel === 'string') {
|
||||
const panel = findVizPanelByKey(this._scene, values.editPanel);
|
||||
const panel = findEditPanel(this._scene, values.editPanel);
|
||||
|
||||
if (!panel) {
|
||||
console.warn(`Panel ${values.editPanel} not found`);
|
||||
|
@ -21,6 +21,7 @@ import {
|
||||
joinCloneKeys,
|
||||
getCloneKey,
|
||||
isClonedKey,
|
||||
getOriginalKey,
|
||||
} from '../../utils/clone';
|
||||
import { getMultiVariableValues } from '../../utils/utils';
|
||||
import { DashboardRepeatsProcessedEvent } from '../types/DashboardRepeatsProcessedEvent';
|
||||
@ -257,7 +258,9 @@ function getRowContentHeight(panels: SceneGridItemLike[]): number {
|
||||
|
||||
function updateLayout(layout: SceneGridLayout, rows: SceneGridRow[], maxYOfRows: number, rowKey: string) {
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
|
@ -21,7 +21,7 @@ import { panelMenuBehavior } from '../scene/PanelMenuBehavior';
|
||||
import { DashboardGridItem } from '../scene/layout-default/DashboardGridItem';
|
||||
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_WIDTH = 12;
|
||||
@ -68,12 +68,63 @@ function findVizPanelInternal(scene: SceneObject, key: string | undefined): VizP
|
||||
return true;
|
||||
}
|
||||
|
||||
// It might be possible to have the keys changed in the meantime from `panel-2` to `panel-2-clone-0`
|
||||
// We need to check this as well
|
||||
const originalObjectKey = !isClonedKey(objKey) ? getOriginalKey(objKey) : objKey;
|
||||
const originalKey = !isClonedKey(key) ? getOriginalKey(key) : key;
|
||||
if (!(obj instanceof VizPanel)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@ -95,6 +146,48 @@ function findVizPanelInternal(scene: SceneObject, key: string | undefined): VizP
|
||||
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
|
||||
* 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 {
|
||||
activateSceneObjectAndParentTree,
|
||||
findVizPanelByKey,
|
||||
findOriginalVizPanelByKey,
|
||||
getVizPanelKeyForPanelId,
|
||||
} from 'app/features/dashboard-scene/utils/utils';
|
||||
|
||||
@ -109,7 +109,8 @@ export class DashboardDatasource extends DataSourceApi<DashboardQuery> {
|
||||
}
|
||||
|
||||
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(
|
||||
|
Loading…
Reference in New Issue
Block a user