Dashboard: Fix panel edits for repeats (#100658)

pull/100749/head
Bogdan Matei 3 months ago committed by GitHub
parent d0394bfa7e
commit 6bd1041cda
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 4
      e2e/various-suite/solo-route.spec.ts
  2. 5
      public/app/features/dashboard-scene/scene/DashboardDatasourceBehaviour.tsx
  3. 4
      public/app/features/dashboard-scene/scene/DashboardSceneUrlSync.ts
  4. 9
      public/app/features/dashboard-scene/scene/layout-default/RowRepeaterBehavior.ts
  5. 105
      public/app/features/dashboard-scene/utils/utils.ts
  6. 5
      public/app/plugins/datasource/dashboard/datasource.ts

@ -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;
}
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`);
}
}
if (originalObjectKey === originalKey) {
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…
Cancel
Save