diff --git a/e2e/old-arch/various-suite/solo-route.spec.ts b/e2e/old-arch/various-suite/solo-route.spec.ts index 9717baf41bd..415257ead7c 100644 --- a/e2e/old-arch/various-suite/solo-route.spec.ts +++ b/e2e/old-arch/various-suite/solo-route.spec.ts @@ -25,7 +25,7 @@ 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-16-clone-0/grid-item-2/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' ); e2e.components.Panels.Panel.title('server=A').should('exist'); @@ -38,7 +38,7 @@ describe('Solo Route', () => { 'Repeating-rows-uid/repeating-rows?orgId=1&var-server=A&var-server=B&var-server=D&var-pod=1&var-pod=2&var-pod=3&panelId=panel-16-clone-1/grid-item-2/panel-2-clone-1&__feature.dashboardSceneSolo=true' ); - e2e.components.Panels.Panel.title('server = A, pod = Rob').should('exist'); + e2e.components.Panels.Panel.title('server = B, pod = Rob').should('exist'); cy.contains('uplot-main-div').should('not.exist'); }); }); diff --git a/e2e/various-suite/solo-route.spec.ts b/e2e/various-suite/solo-route.spec.ts index 9717baf41bd..415257ead7c 100644 --- a/e2e/various-suite/solo-route.spec.ts +++ b/e2e/various-suite/solo-route.spec.ts @@ -25,7 +25,7 @@ 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-16-clone-0/grid-item-2/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' ); e2e.components.Panels.Panel.title('server=A').should('exist'); @@ -38,7 +38,7 @@ describe('Solo Route', () => { 'Repeating-rows-uid/repeating-rows?orgId=1&var-server=A&var-server=B&var-server=D&var-pod=1&var-pod=2&var-pod=3&panelId=panel-16-clone-1/grid-item-2/panel-2-clone-1&__feature.dashboardSceneSolo=true' ); - e2e.components.Panels.Panel.title('server = A, pod = Rob').should('exist'); + e2e.components.Panels.Panel.title('server = B, pod = Rob').should('exist'); cy.contains('uplot-main-div').should('not.exist'); }); }); diff --git a/package.json b/package.json index 150751ba6e4..7e889ddedde 100644 --- a/package.json +++ b/package.json @@ -275,8 +275,8 @@ "@grafana/prometheus": "workspace:*", "@grafana/runtime": "workspace:*", "@grafana/saga-icons": "workspace:*", - "@grafana/scenes": "6.0.1", - "@grafana/scenes-react": "6.0.1", + "@grafana/scenes": "6.0.2", + "@grafana/scenes-react": "6.0.2", "@grafana/schema": "workspace:*", "@grafana/sql": "workspace:*", "@grafana/ui": "workspace:*", diff --git a/public/app/features/dashboard-scene/scene/DashboardSceneUrlSync.ts b/public/app/features/dashboard-scene/scene/DashboardSceneUrlSync.ts index 3493be625f9..cde4c8df0e0 100644 --- a/public/app/features/dashboard-scene/scene/DashboardSceneUrlSync.ts +++ b/public/app/features/dashboard-scene/scene/DashboardSceneUrlSync.ts @@ -22,7 +22,8 @@ import { DefaultGridLayoutManager } from './layout-default/DefaultGridLayoutMana import { DashboardRepeatsProcessedEvent } from './types/DashboardRepeatsProcessedEvent'; export class DashboardSceneUrlSync implements SceneObjectUrlSyncHandler { - private _eventSub?: Unsubscribable; + private _viewEventSub?: Unsubscribable; + private _inspectEventSub?: Unsubscribable; constructor(private _scene: DashboardScene) {} @@ -78,6 +79,14 @@ export class DashboardSceneUrlSync implements SceneObjectUrlSyncHandler { if (typeof values.inspect === 'string') { let panel = findVizPanelByKey(this._scene, values.inspect); 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 + // Here we check if the key contains the clone key so we force the repeat processing + // It doesn't matter if the element or the ancestors are clones or not, just that the key contains the clone key + if (containsCloneKey(values.inspect)) { + this._handleInspectRepeatClone(values.inspect); + return; + } + appEvents.emit(AppEvents.alertError, ['Panel not found']); locationService.partial({ inspect: null }); return; @@ -177,12 +186,27 @@ export class DashboardSceneUrlSync implements SceneObjectUrlSyncHandler { } } + private _handleInspectRepeatClone(inspect: string) { + if (!this._inspectEventSub) { + this._inspectEventSub = this._scene.subscribeToEvent(DashboardRepeatsProcessedEvent, () => { + const panel = findVizPanelByKey(this._scene, inspect); + if (panel) { + this._inspectEventSub?.unsubscribe(); + this._scene.setState({ + inspectPanelKey: inspect, + overlay: new PanelInspectDrawer({ panelRef: panel.getRef() }), + }); + } + }); + } + } + private _handleViewRepeatClone(viewPanel: string) { - if (!this._eventSub) { - this._eventSub = this._scene.subscribeToEvent(DashboardRepeatsProcessedEvent, () => { + if (!this._viewEventSub) { + this._viewEventSub = this._scene.subscribeToEvent(DashboardRepeatsProcessedEvent, () => { const panel = findVizPanelByKey(this._scene, viewPanel); if (panel) { - this._eventSub?.unsubscribe(); + this._viewEventSub?.unsubscribe(); this._scene.setState({ viewPanelScene: new ViewPanelScene({ panelRef: panel.getRef() }) }); } }); diff --git a/public/app/features/dashboard-scene/scene/layout-default/DefaultGridLayoutManager.tsx b/public/app/features/dashboard-scene/scene/layout-default/DefaultGridLayoutManager.tsx index 97b268757d9..bad747f55de 100644 --- a/public/app/features/dashboard-scene/scene/layout-default/DefaultGridLayoutManager.tsx +++ b/public/app/features/dashboard-scene/scene/layout-default/DefaultGridLayoutManager.tsx @@ -252,6 +252,14 @@ export class DefaultGridLayoutManager } public activateRepeaters() { + if (!this.isActive) { + this.activate(); + } + + if (!this.state.grid.isActive) { + this.state.grid.activate(); + } + this.state.grid.forEachChild((child) => { if (child instanceof DashboardGridItem && !child.isActive) { child.activate(); diff --git a/public/app/features/dashboard-scene/utils/clone.test.ts b/public/app/features/dashboard-scene/utils/clone.test.ts index 58dcef6fb38..97b0e377e6a 100644 --- a/public/app/features/dashboard-scene/utils/clone.test.ts +++ b/public/app/features/dashboard-scene/utils/clone.test.ts @@ -30,6 +30,8 @@ describe('clone', () => { expect(getOriginalKey('panel-clone-1')).toBe('panel'); expect(getOriginalKey('row-clone-1/panel-clone-2')).toBe('panel'); expect(getOriginalKey('tab-clone-0/row-clone-1/panel-clone-2')).toBe('panel'); + expect(getOriginalKey('panel-2-clone-3')).toBe('panel-2'); + expect(getOriginalKey('panel-2')).toBe('panel-2'); }); }); diff --git a/public/app/features/dashboard-scene/utils/utils.ts b/public/app/features/dashboard-scene/utils/utils.ts index 27ecaac2fe2..5e52a1d517f 100644 --- a/public/app/features/dashboard-scene/utils/utils.ts +++ b/public/app/features/dashboard-scene/utils/utils.ts @@ -21,7 +21,7 @@ import { panelMenuBehavior } from '../scene/PanelMenuBehavior'; import { DashboardGridItem } from '../scene/layout-default/DashboardGridItem'; import { DashboardLayoutManager, isDashboardLayoutManager } from '../scene/types/DashboardLayoutManager'; -import { getLastKeyFromClone, getOriginalKey } from './clone'; +import { getOriginalKey, isClonedKey } from './clone'; export const NEW_PANEL_HEIGHT = 8; export const NEW_PANEL_WIDTH = 12; @@ -64,7 +64,16 @@ function findVizPanelInternal(scene: SceneObject, key: string | undefined): VizP const panel = sceneGraph.findObject(scene, (obj) => { const objKey = obj.state.key!; - if (objKey === key || getLastKeyFromClone(objKey) === getLastKeyFromClone(key) || getOriginalKey(objKey) === key) { + if (objKey === key) { + 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 (originalObjectKey === originalKey) { return true; } diff --git a/yarn.lock b/yarn.lock index f1092de32f7..49162fcfe61 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3814,11 +3814,11 @@ __metadata: languageName: unknown linkType: soft -"@grafana/scenes-react@npm:6.0.1": - version: 6.0.1 - resolution: "@grafana/scenes-react@npm:6.0.1" +"@grafana/scenes-react@npm:6.0.2": + version: 6.0.2 + resolution: "@grafana/scenes-react@npm:6.0.2" dependencies: - "@grafana/scenes": "npm:6.0.1" + "@grafana/scenes": "npm:6.0.2" lru-cache: "npm:^10.2.2" react-use: "npm:^17.4.0" peerDependencies: @@ -3830,13 +3830,13 @@ __metadata: react: ^18.0.0 react-dom: ^18.0.0 react-router-dom: ^6.28.0 - checksum: 10/e4ad83cc628f17232fe9c8d74f641c65e2e289c177ce88a6990d00f6bea4e1a091115e7b98200de7bcff14ace0fe20eb816141fe533fee7d2ad5f7f665404d2c + checksum: 10/9744e01f2ff912229e43cedfa41d626ccdfd034f5b9718b57c593bc90edadade960f76baf1d8ad19eed03709c17c62397df1871b89acc635172aa14f6a20e096 languageName: node linkType: hard -"@grafana/scenes@npm:6.0.1": - version: 6.0.1 - resolution: "@grafana/scenes@npm:6.0.1" +"@grafana/scenes@npm:6.0.2": + version: 6.0.2 + resolution: "@grafana/scenes@npm:6.0.2" dependencies: "@floating-ui/react": "npm:^0.26.16" "@leeoniya/ufuzzy": "npm:^1.0.16" @@ -3854,7 +3854,7 @@ __metadata: react: ^18.0.0 react-dom: ^18.0.0 react-router-dom: ^6.28.0 - checksum: 10/6862e57358ba2e63f139e7f3bb977b19945f67eb070aa2c85c073a55dc460d3ccfeecfee22aea92c660a7632ac997e6cd945f9466b64103436a221979e6e8fcb + checksum: 10/2584f296db6299ef0a09d51f5c267ebcf7e44bd17b4d6516e38d3220f8f1d7aebc63c5fc6523979c4ac4d3f555416ca573e85e03bd36eb33a11941a5b3497149 languageName: node linkType: hard @@ -18151,8 +18151,8 @@ __metadata: "@grafana/prometheus": "workspace:*" "@grafana/runtime": "workspace:*" "@grafana/saga-icons": "workspace:*" - "@grafana/scenes": "npm:6.0.1" - "@grafana/scenes-react": "npm:6.0.1" + "@grafana/scenes": "npm:6.0.2" + "@grafana/scenes-react": "npm:6.0.2" "@grafana/schema": "workspace:*" "@grafana/sql": "workspace:*" "@grafana/tsconfig": "npm:^2.0.0"