diff --git a/public/app/features/dashboard-scene/scene/DashboardScene.test.tsx b/public/app/features/dashboard-scene/scene/DashboardScene.test.tsx index e34bab0ca21..480712a15d4 100644 --- a/public/app/features/dashboard-scene/scene/DashboardScene.test.tsx +++ b/public/app/features/dashboard-scene/scene/DashboardScene.test.tsx @@ -12,6 +12,8 @@ import appEvents from 'app/core/app_events'; import { getDashboardSrv } from 'app/features/dashboard/services/DashboardSrv'; import { VariablesChanged } from 'app/features/variables/types'; +import { djb2Hash } from '../utils/djb2Hash'; + import { DashboardScene, DashboardSceneState } from './DashboardScene'; describe('DashboardScene', () => { @@ -68,6 +70,12 @@ describe('DashboardScene', () => { panelId: 1, }); }); + + it('Should hash the key of the cloned panels and set it as panelId', () => { + const queryRunner = sceneGraph.findObject(scene, (o) => o.state.key === 'data-query-runner2')!; + const expectedPanelId = djb2Hash('panel-2-clone-1'); + expect(scene.enrichDataRequest(queryRunner).panelId).toEqual(expectedPanelId); + }); }); describe('When variables change', () => { @@ -112,6 +120,14 @@ function buildTestScene(overrides?: Partial) { pluginId: 'table', }), }), + new SceneGridItem({ + body: new VizPanel({ + title: 'Panel B', + key: 'panel-2-clone-1', + pluginId: 'table', + $data: new SceneQueryRunner({ key: 'data-query-runner2', queries: [{ refId: 'A' }] }), + }), + }), ], }), ...overrides, diff --git a/public/app/features/dashboard-scene/scene/DashboardScene.tsx b/public/app/features/dashboard-scene/scene/DashboardScene.tsx index a016017c91d..e35f44c3ff2 100644 --- a/public/app/features/dashboard-scene/scene/DashboardScene.tsx +++ b/public/app/features/dashboard-scene/scene/DashboardScene.tsx @@ -27,8 +27,9 @@ import { DashboardSceneRenderer } from '../scene/DashboardSceneRenderer'; import { SaveDashboardDrawer } from '../serialization/SaveDashboardDrawer'; import { DashboardEditView } from '../settings/utils'; import { DashboardModelCompatibilityWrapper } from '../utils/DashboardModelCompatibilityWrapper'; +import { djb2Hash } from '../utils/djb2Hash'; import { getDashboardUrl } from '../utils/urlBuilders'; -import { forceRenderChildren, getClosestVizPanel, getPanelIdForVizPanel } from '../utils/utils'; +import { forceRenderChildren, getClosestVizPanel, getPanelIdForVizPanel, isPanelClone } from '../utils/utils'; import { DashboardSceneUrlSync } from './DashboardSceneUrlSync'; import { ViewPanelScene } from './ViewPanelScene'; @@ -279,11 +280,20 @@ export class DashboardScene extends SceneObjectBase { */ public enrichDataRequest(sceneObject: SceneObject): Partial { const panel = getClosestVizPanel(sceneObject); + let panelId = 0; + + if (panel && panel.state.key) { + if (isPanelClone(panel.state.key)) { + panelId = djb2Hash(panel?.state.key); + } else { + panelId = getPanelIdForVizPanel(panel); + } + } return { app: CoreApp.Dashboard, dashboardUID: this.state.uid, - panelId: (panel && getPanelIdForVizPanel(panel)) ?? 0, + panelId, }; } diff --git a/public/app/features/dashboard-scene/scene/DashboardSceneUrlSync.ts b/public/app/features/dashboard-scene/scene/DashboardSceneUrlSync.ts index 95436611062..25902b406b1 100644 --- a/public/app/features/dashboard-scene/scene/DashboardSceneUrlSync.ts +++ b/public/app/features/dashboard-scene/scene/DashboardSceneUrlSync.ts @@ -7,7 +7,7 @@ import appEvents from 'app/core/app_events'; import { PanelInspectDrawer } from '../inspect/PanelInspectDrawer'; import { createDashboardEditViewFor } from '../settings/utils'; -import { findVizPanelByKey } from '../utils/utils'; +import { findVizPanelByKey, isPanelClone } from '../utils/utils'; import { DashboardScene, DashboardSceneState } from './DashboardScene'; import { ViewPanelScene } from './ViewPanelScene'; @@ -69,7 +69,7 @@ export class DashboardSceneUrlSync implements SceneObjectUrlSyncHandler { const panel = findVizPanelByKey(this._scene, values.viewPanel); if (!panel) { // // If we are trying to view a repeat clone that can't be found it might be that the repeats have not been processed yet - if (values.viewPanel.indexOf('clone')) { + if (isPanelClone(values.viewPanel)) { this._handleViewRepeatClone(values.viewPanel); return; } diff --git a/public/app/features/dashboard-scene/utils/djb2Hash.ts b/public/app/features/dashboard-scene/utils/djb2Hash.ts new file mode 100644 index 00000000000..6eb571fbef0 --- /dev/null +++ b/public/app/features/dashboard-scene/utils/djb2Hash.ts @@ -0,0 +1,12 @@ +/** + * Hashes a string using the DJB2 algorithm. + */ +export function djb2Hash(str: string): number { + let hash = 5381; + + for (let i = 0; i < str.length; i++) { + hash = (hash * 33) ^ str.charCodeAt(i); + } + + return hash >>> 0; // Ensure the result is an unsigned 32-bit integer +} diff --git a/public/app/features/dashboard-scene/utils/utils.ts b/public/app/features/dashboard-scene/utils/utils.ts index 1a9e8cb76b6..6cfa50f696c 100644 --- a/public/app/features/dashboard-scene/utils/utils.ts +++ b/public/app/features/dashboard-scene/utils/utils.ts @@ -182,3 +182,7 @@ export function getClosestVizPanel(sceneObject: SceneObject): VizPanel | null { return null; } + +export function isPanelClone(key: string) { + return key.includes('clone'); +}