diff --git a/public/app/features/dashboard-scene/scene/DashboardControls.test.tsx b/public/app/features/dashboard-scene/scene/DashboardControls.test.tsx
index 878f6cc5e87..dc4c492bf92 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 { SceneDataLayerControls, SceneVariableSet, TextBoxVariable, VariableValueSelectors } from '@grafana/scenes';
+import { SceneVariableSet, TextBoxVariable } from '@grafana/scenes';
import { DashboardControls, DashboardControlsState } from './DashboardControls';
import { DashboardScene } from './DashboardScene';
@@ -10,7 +10,6 @@ describe('DashboardControls', () => {
describe('Given a standard scene', () => {
it('should initialize with default values', () => {
const scene = buildTestScene();
- expect(scene.state.variableControls).toEqual([]);
expect(scene.state.timePicker).toBeDefined();
expect(scene.state.refreshPicker).toBeDefined();
});
@@ -38,9 +37,7 @@ describe('DashboardControls', () => {
});
it('should render visible controls', async () => {
- const scene = buildTestScene({
- variableControls: [new VariableValueSelectors({}), new SceneDataLayerControls()],
- });
+ const scene = buildTestScene({});
const renderer = render();
expect(await renderer.findByTestId(selectors.pages.Dashboard.Controls)).toBeInTheDocument();
@@ -55,7 +52,6 @@ describe('DashboardControls', () => {
hideTimeControls: true,
hideVariableControls: true,
hideLinksControls: true,
- variableControls: [new VariableValueSelectors({}), new SceneDataLayerControls()],
});
const renderer = render();
diff --git a/public/app/features/dashboard-scene/scene/DashboardControls.tsx b/public/app/features/dashboard-scene/scene/DashboardControls.tsx
index 9b1f95097d0..423d3e3e054 100644
--- a/public/app/features/dashboard-scene/scene/DashboardControls.tsx
+++ b/public/app/features/dashboard-scene/scene/DashboardControls.tsx
@@ -4,7 +4,6 @@ import { GrafanaTheme2, VariableHide } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
import {
SceneObjectState,
- SceneObject,
SceneObjectBase,
SceneComponentProps,
SceneTimePicker,
@@ -22,9 +21,10 @@ import { PanelEditControls } from '../panel-edit/PanelEditControls';
import { getDashboardSceneFor } from '../utils/utils';
import { DashboardLinksControls } from './DashboardLinksControls';
+import { DashboardScene } from './DashboardScene';
+import { VariableControls } from './VariableControls';
export interface DashboardControlsState extends SceneObjectState {
- variableControls: SceneObject[];
timePicker: SceneTimePicker;
refreshPicker: SceneRefreshPicker;
hideTimeControls?: boolean;
@@ -73,7 +73,6 @@ export class DashboardControls extends SceneObjectBase {
public constructor(state: Partial) {
super({
- variableControls: [],
timePicker: state.timePicker ?? new SceneTimePicker({}),
refreshPicker: state.refreshPicker ?? new SceneRefreshPicker({}),
...state,
@@ -119,8 +118,7 @@ export class DashboardControls extends SceneObjectBase {
}
function DashboardControlsRenderer({ model }: SceneComponentProps) {
- const { variableControls, refreshPicker, timePicker, hideTimeControls, hideVariableControls, hideLinksControls } =
- model.useState();
+ const { refreshPicker, timePicker, hideTimeControls, hideVariableControls, hideLinksControls } = model.useState();
const dashboard = getDashboardSceneFor(model);
const { links, editPanel } = dashboard.useState();
const styles = useStyles2(getStyles);
@@ -137,7 +135,12 @@ function DashboardControlsRenderer({ model }: SceneComponentProps
- {!hideVariableControls && variableControls.map((c) => )}
+ {!hideVariableControls && (
+ <>
+
+
+ >
+ )}
{!hideLinksControls && !editPanel && }
{editPanel && }
@@ -153,6 +156,18 @@ function DashboardControlsRenderer({ model }: SceneComponentProps
+ {layers.map((layer) => (
+
+ ))}
+ >
+ );
+}
+
function getStyles(theme: GrafanaTheme2) {
return {
controls: css({
diff --git a/public/app/features/dashboard-scene/scene/VariableControls.tsx b/public/app/features/dashboard-scene/scene/VariableControls.tsx
new file mode 100644
index 00000000000..dc4dc9653a5
--- /dev/null
+++ b/public/app/features/dashboard-scene/scene/VariableControls.tsx
@@ -0,0 +1,70 @@
+import { css } from '@emotion/css';
+
+import { VariableHide } from '@grafana/data';
+import { selectors } from '@grafana/e2e-selectors';
+import { sceneGraph, useSceneObjectState, SceneVariable, SceneVariableState, ControlsLabel } from '@grafana/scenes';
+
+import { DashboardScene } from './DashboardScene';
+
+export function VariableControls({ dashboard }: { dashboard: DashboardScene }) {
+ const variables = sceneGraph.getVariables(dashboard)!.useState();
+
+ return (
+ <>
+ {variables.variables.map((variable) => (
+
+ ))}
+ >
+ );
+}
+
+interface VariableSelectProps {
+ variable: SceneVariable;
+}
+
+export function VariableValueSelectWrapper({ variable }: VariableSelectProps) {
+ const state = useSceneObjectState(variable, { shouldActivateOrKeepAlive: true });
+
+ if (state.hide === VariableHide.hideVariable) {
+ return null;
+ }
+
+ return (
+
+
+
+
+ );
+}
+
+function VariableLabel({ variable }: VariableSelectProps) {
+ const { state } = variable;
+
+ if (variable.state.hide === VariableHide.hideLabel) {
+ return null;
+ }
+
+ const labelOrName = state.label || state.name;
+ const elementId = `var-${state.key}`;
+
+ return (
+ variable.onCancel?.()}
+ label={labelOrName}
+ error={state.error}
+ layout={'horizontal'}
+ description={state.description ?? undefined}
+ />
+ );
+}
+
+const containerStyle = css({
+ display: 'flex',
+ // No border for second element (inputs) as label and input border is shared
+ '> :nth-child(2)': css({
+ borderTopLeftRadius: 0,
+ borderBottomLeftRadius: 0,
+ }),
+});
diff --git a/public/app/features/dashboard-scene/serialization/transformSaveModelSchemaV2ToScene.ts b/public/app/features/dashboard-scene/serialization/transformSaveModelSchemaV2ToScene.ts
index 6cb7c7462c1..10ccc34252f 100644
--- a/public/app/features/dashboard-scene/serialization/transformSaveModelSchemaV2ToScene.ts
+++ b/public/app/features/dashboard-scene/serialization/transformSaveModelSchemaV2ToScene.ts
@@ -10,14 +10,12 @@ import {
GroupByVariable,
IntervalVariable,
QueryVariable,
- SceneDataLayerControls,
SceneRefreshPicker,
SceneTimePicker,
SceneTimeRange,
SceneVariable,
SceneVariableSet,
TextBoxVariable,
- VariableValueSelectors,
} from '@grafana/scenes';
import {
AdhocVariableKind,
@@ -191,7 +189,6 @@ export function transformSaveModelSchemaV2ToScene(dto: DashboardWithAccessInfo {
const scene = transformSaveModelToScene({ dashboard: dashboard_to_load1 as DashboardDataDTO, meta: {} });
expect(scene.state.$data).toBeInstanceOf(DashboardDataLayerSet);
- expect(scene.state.controls!.state.variableControls[1]).toBeInstanceOf(SceneDataLayerControls);
const dataLayers = scene.state.$data as DashboardDataLayerSet;
expect(dataLayers.state.annotationLayers).toHaveLength(4);
@@ -864,7 +862,6 @@ describe('transformSaveModelToScene', () => {
const scene = transformSaveModelToScene({ dashboard: dashboard_to_load1 as DashboardDataDTO, meta: {} });
expect(scene.state.$data).toBeInstanceOf(DashboardDataLayerSet);
- expect(scene.state.controls!.state.variableControls[1]).toBeInstanceOf(SceneDataLayerControls);
const dataLayers = scene.state.$data as DashboardDataLayerSet;
expect(dataLayers.state.alertStatesLayer).toBeDefined();
@@ -877,7 +874,6 @@ describe('transformSaveModelToScene', () => {
const scene = transformSaveModelToScene({ dashboard: dashboard_to_load1 as DashboardDataDTO, meta: {} });
expect(scene.state.$data).toBeInstanceOf(DashboardDataLayerSet);
- expect(scene.state.controls!.state.variableControls[1]).toBeInstanceOf(SceneDataLayerControls);
const dataLayers = scene.state.$data as DashboardDataLayerSet;
expect(dataLayers.state.alertStatesLayer).toBeDefined();
diff --git a/public/app/features/dashboard-scene/serialization/transformSaveModelToScene.ts b/public/app/features/dashboard-scene/serialization/transformSaveModelToScene.ts
index aaed4127842..0b7435c1fe9 100644
--- a/public/app/features/dashboard-scene/serialization/transformSaveModelToScene.ts
+++ b/public/app/features/dashboard-scene/serialization/transformSaveModelToScene.ts
@@ -9,7 +9,6 @@ import {
SceneGridRow,
SceneTimeRange,
SceneVariableSet,
- VariableValueSelectors,
SceneRefreshPicker,
SceneObject,
VizPanelMenu,
@@ -17,7 +16,6 @@ import {
VizPanelState,
SceneGridItemLike,
SceneDataLayerProvider,
- SceneDataLayerControls,
UserActionEvent,
SceneInteractionProfileEvent,
SceneObjectState,
@@ -278,7 +276,6 @@ export function createDashboardSceneFromDashboardModel(oldModel: DashboardModel,
$behaviors: behaviorList,
$data: new DashboardDataLayerSet({ annotationLayers, alertStatesLayer }),
controls: new DashboardControls({
- variableControls: [new VariableValueSelectors({}), new SceneDataLayerControls()],
timePicker: new SceneTimePicker({
quickRanges: oldModel.timepicker.quick_ranges,
}),