DashboardControls: Render UNSAFE hidden dashboard controls (#113046)

* Render UNSAFE hidden dashboard controls

* Remove unused imports

* Extract to function and write test

* Remove unnecessary context from test

* Remove exclamation
This commit is contained in:
Tobias Skarhed
2025-10-29 08:33:48 -06:00
committed by GitHub
parent 87794bec12
commit 04ab552950
2 changed files with 59 additions and 2 deletions
@@ -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 <div>Mocked Component</div>;
});
const renderer = render(<controls.Component model={controls} />);
// 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', () => {
@@ -153,7 +153,8 @@ function DashboardControlsRenderer({ model }: SceneComponentProps<DashboardContr
if (!model.hasControls()) {
// To still have spacing when no controls are rendered
return <Box padding={1} />;
return <Box padding={1}>{renderHiddenVariables(dashboard)}</Box>;
}
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) => (
<v.Component model={v} key={v.state.key} />
))}
</>
);
}
return null;
}
function getStyles(theme: GrafanaTheme2) {
return {
controls: css({