diff --git a/public/app/features/dashboard-scene/scene/DashboardControls.test.tsx b/public/app/features/dashboard-scene/scene/DashboardControls.test.tsx index c01808f411e..c13e65574be 100644 --- a/public/app/features/dashboard-scene/scene/DashboardControls.test.tsx +++ b/public/app/features/dashboard-scene/scene/DashboardControls.test.tsx @@ -1,7 +1,7 @@ import { render } from '@testing-library/react'; import { selectors } from '@grafana/e2e-selectors'; -import { SceneVariableSet, TextBoxVariable } from '@grafana/scenes'; +import { SceneVariableSet, ScopesVariable, TextBoxVariable } from '@grafana/scenes'; import { DashboardControls, DashboardControlsState } from './DashboardControls'; import { DashboardScene } from './DashboardScene'; @@ -97,6 +97,47 @@ describe('DashboardControls', () => { expect(renderer.queryByTestId(selectors.pages.Dashboard.Controls)).not.toBeInTheDocument(); }); + + it('should render ScopesVariable Component even when hidden', () => { + const scopeVariable = new ScopesVariable({ + enable: true, + }); + + const dashboard = new DashboardScene({ + uid: 'test-dashboard', + $variables: new SceneVariableSet({ + variables: [scopeVariable], + }), + controls: new DashboardControls({ + hideTimeControls: true, + hideVariableControls: true, + hideLinksControls: true, + hideDashboardControls: true, + }), + }); + + dashboard.activate(); + + const controls = dashboard.state.controls as DashboardControls; + + // Mock the Component getter - use 'as any' to bypass TypeScript's getter checking + // Return a component function (not JSX directly) that renders our test element + // eslint-disable-next-line @typescript-eslint/no-explicit-any + jest.spyOn(scopeVariable as any, 'Component', 'get').mockReturnValue(() => { + return
Mocked Component
; + }); + + const renderer = render(); + + // Verify UNSAFE_renderAsHidden is set (required for renderHiddenVariables to include it) + expect(scopeVariable.UNSAFE_renderAsHidden).toBe(true); + + // Check that the mocked component is rendered - this proves renderHiddenVariables + // accessed the Component getter and rendered it + expect(renderer.getByText('Mocked Component')).toBeInTheDocument(); + + jest.restoreAllMocks(); + }); }); describe('UrlSync', () => { diff --git a/public/app/features/dashboard-scene/scene/DashboardControls.tsx b/public/app/features/dashboard-scene/scene/DashboardControls.tsx index e6a8e7ab8a0..921874732eb 100644 --- a/public/app/features/dashboard-scene/scene/DashboardControls.tsx +++ b/public/app/features/dashboard-scene/scene/DashboardControls.tsx @@ -153,7 +153,8 @@ function DashboardControlsRenderer({ model }: SceneComponentProps; + + return {renderHiddenVariables(dashboard)}; } return ( @@ -200,6 +201,21 @@ function DataLayerControls({ dashboard }: { dashboard: DashboardScene }) { ); } +function renderHiddenVariables(dashboard: DashboardScene) { + const { variables } = sceneGraph.getVariables(dashboard).useState(); + const renderAsHiddenVariables = variables.filter((v) => v.UNSAFE_renderAsHidden); + if (renderAsHiddenVariables && renderAsHiddenVariables.length > 0) { + return ( + <> + {renderAsHiddenVariables.map((v) => ( + + ))} + + ); + } + return null; +} + function getStyles(theme: GrafanaTheme2) { return { controls: css({