diff --git a/.betterer.results b/.betterer.results index c69a0a8a2dc..583c2b24e30 100644 --- a/.betterer.results +++ b/.betterer.results @@ -2466,6 +2466,12 @@ exports[`better eslint`] = { [0, 0, 0, "Do not use any type assertions.", "4"], [0, 0, 0, "Do not use any type assertions.", "5"] ], + "public/app/features/dashboard-scene/settings/variables/components/VariableSelectField.tsx:5381": [ + [0, 0, 0, "Unexpected any. Specify a different type.", "0"] + ], + "public/app/features/dashboard-scene/settings/variables/utils.ts:5381": [ + [0, 0, 0, "Unexpected any. Specify a different type.", "0"] + ], "public/app/features/dashboard-scene/utils/DashboardModelCompatibilityWrapper.ts:5381": [ [0, 0, 0, "Do not use any type assertions.", "0"], [0, 0, 0, "Do not use any type assertions.", "1"], @@ -4559,16 +4565,6 @@ exports[`better eslint`] = { [0, 0, 0, "Styles should be written using objects.", "9"], [0, 0, 0, "Styles should be written using objects.", "10"] ], - "public/app/features/variables/editor/VariableSelectField.tsx:5381": [ - [0, 0, 0, "Unexpected any. Specify a different type.", "0"], - [0, 0, 0, "Styles should be written using objects.", "1"] - ], - "public/app/features/variables/editor/VariableTextAreaField.tsx:5381": [ - [0, 0, 0, "Styles should be written using objects.", "0"] - ], - "public/app/features/variables/editor/VariableValuesPreview.tsx:5381": [ - [0, 0, 0, "Use data-testid for E2E selectors instead of aria-label", "0"] - ], "public/app/features/variables/editor/getVariableQueryEditor.tsx:5381": [ [0, 0, 0, "Unexpected any. Specify a different type.", "0"], [0, 0, 0, "Unexpected any. Specify a different type.", "1"] diff --git a/packages/grafana-e2e-selectors/src/selectors/pages.ts b/packages/grafana-e2e-selectors/src/selectors/pages.ts index 8f2255ebc49..e4064f6bdda 100644 --- a/packages/grafana-e2e-selectors/src/selectors/pages.ts +++ b/packages/grafana-e2e-selectors/src/selectors/pages.ts @@ -141,7 +141,7 @@ export const Pages = { selectionOptionsIncludeAllSwitch: 'Variable editor Form IncludeAll switch', selectionOptionsCustomAllInput: 'Variable editor Form IncludeAll field', selectionOptionsCustomAllInputV2: 'data-testid Variable editor Form IncludeAll field', - previewOfValuesOption: 'Variable editor Preview of Values option', + previewOfValuesOption: 'data-testid Variable editor Preview of Values option', submitButton: 'Variable editor Submit button', applyButton: 'data-testid Variable editor Apply button', }, diff --git a/public/app/features/dashboard-scene/settings/EditListViewSceneUrlSync.ts b/public/app/features/dashboard-scene/settings/EditListViewSceneUrlSync.ts index 0184e4b645f..a81fda1cb6b 100644 --- a/public/app/features/dashboard-scene/settings/EditListViewSceneUrlSync.ts +++ b/public/app/features/dashboard-scene/settings/EditListViewSceneUrlSync.ts @@ -1,9 +1,12 @@ import { SceneObjectUrlSyncHandler, SceneObjectUrlValues } from '@grafana/scenes'; import { DashboardLinksEditView, DashboardLinksEditViewState } from './DashboardLinksEditView'; +import { VariablesEditView, VariablesEditViewState } from './VariablesEditView'; +type EditListViewUrlSync = DashboardLinksEditView | VariablesEditView; +type EditListViewState = DashboardLinksEditViewState | VariablesEditViewState; export class EditListViewSceneUrlSync implements SceneObjectUrlSyncHandler { - constructor(private _scene: DashboardLinksEditView) {} + constructor(private _scene: EditListViewUrlSync) {} getKeys(): string[] { return ['editIndex']; @@ -17,7 +20,7 @@ export class EditListViewSceneUrlSync implements SceneObjectUrlSyncHandler { } updateFromUrl(values: SceneObjectUrlValues): void { - let update: Partial = {}; + let update: Partial = {}; if (typeof values.editIndex === 'string') { update = { editIndex: Number(values.editIndex) }; } else { diff --git a/public/app/features/dashboard-scene/settings/VariablesEditView.test.tsx b/public/app/features/dashboard-scene/settings/VariablesEditView.test.tsx index 1e71389e8a3..f1acd4eb418 100644 --- a/public/app/features/dashboard-scene/settings/VariablesEditView.test.tsx +++ b/public/app/features/dashboard-scene/settings/VariablesEditView.test.tsx @@ -1,10 +1,17 @@ -import { SceneVariableSet, CustomVariable, SceneGridItem, SceneGridLayout } from '@grafana/scenes'; +import { getPanelPlugin } from '@grafana/data/test/__mocks__/pluginMocks'; +import { setPluginImportUtils } from '@grafana/runtime'; +import { SceneVariableSet, CustomVariable, SceneGridItem, SceneGridLayout, VizPanel } from '@grafana/scenes'; import { DashboardScene } from '../scene/DashboardScene'; import { activateFullSceneTree } from '../utils/test-utils'; import { VariablesEditView } from './VariablesEditView'; +setPluginImportUtils({ + importPanelPlugin: (id: string) => Promise.resolve(getPanelPlugin({})), + getPanelPluginFromCache: (id: string) => undefined, +}); + describe('VariablesEditView', () => { describe('Dashboard Variables state', () => { let dashboard: DashboardScene; @@ -35,7 +42,7 @@ describe('VariablesEditView', () => { { type: 'custom', name: 'customVar2', - query: 'test3, test4', + query: 'test3, test4, $customVar', value: 'test3', }, ]; @@ -99,6 +106,114 @@ describe('VariablesEditView', () => { errorSpy.mockRestore(); }); + + it('should change the variable type creating a new variable object', () => { + const previousVariable = variableView.getVariables()[1] as CustomVariable; + variableView.onEdit('customVar2'); + + variableView.onTypeChange('constant'); + expect(variableView.getVariables()).toHaveLength(2); + const variable = variableView.getVariables()[1]; + expect(variable).not.toBe(previousVariable); + expect(variable.state.type).toBe('constant'); + + // Values to be kept between the old and new variable + expect(variable.state.name).toEqual(previousVariable.state.name); + expect(variable.state.label).toEqual(previousVariable.state.label); + }); + + it('should reset editing variable when going back', () => { + variableView.onEdit('customVar2'); + expect(variableView.state.editIndex).toBe(1); + + variableView.onGoBack(); + expect(variableView.state.editIndex).toBeUndefined(); + }); + + it('should reset editing variable when discarding changes', () => { + variableView.onEdit('customVar2'); + const editIndex = variableView.state.editIndex!; + const variable = variableView.getVariables()[editIndex]; + const originalState = { ...variable.state }; + + variable.setState({ name: 'newName' }); + variableView.onDiscardChanges(); + + const newVariable = variableView.getVariables()[editIndex]; + expect(newVariable.state).toEqual(originalState); + }); + + it('should reset editing variable when discarding changes after the type being changed', () => { + variableView.onEdit('customVar2'); + const editIndex = variableView.state.editIndex!; + const variable = variableView.getVariables()[editIndex]; + const originalState = { ...variable.state }; + + variableView.onTypeChange('constant'); + variableView.onDiscardChanges(); + + const newVariable = variableView.getVariables()[editIndex]; + expect(newVariable.state).toEqual(originalState); + }); + + it('should go back when discarding changes', () => { + variableView.onEdit('customVar2'); + const editIndex = variableView.state.editIndex!; + expect(editIndex).toBeDefined(); + + variableView.onDiscardChanges(); + + expect(variableView.state.editIndex).toBeUndefined(); + }); + }); + + describe('Dashboard Variables dependencies', () => { + let variableView: VariablesEditView; + let dashboard: DashboardScene; + + beforeEach(async () => { + const result = await buildTestScene(); + variableView = result.variableView; + dashboard = result.dashboard; + }); + + // FIXME: This is not working because the variable is replaced or it is not resolved yet + it.skip('should keep dependencies between variables the type is changed so the variable is replaced', () => { + // Uses function to avoid store reference to previous existing variables + const getSourceVariable = () => variableView.getVariables()[0] as CustomVariable; + const getDependantVariable = () => variableView.getVariables()[1] as CustomVariable; + + expect(getSourceVariable().getValue()).toBe('test'); + // Using getOptionsForSelect to get the interpolated values + expect(getDependantVariable().getOptionsForSelect()[2].label).toBe('test'); + + variableView.onEdit(getSourceVariable().state.name); + // Simulating changing the type and update the value + variableView.onTypeChange('constant'); + getSourceVariable().setState({ value: 'newValue' }); + + expect(getSourceVariable().getValue()).toBe('newValue'); + expect(getDependantVariable().getOptionsForSelect()[2].label).toBe('newValue'); + }); + + it('should keep dependencies with panels when the type is changed so the variable is replaced', async () => { + // Uses function to avoid store reference to previous existing variables + const getSourceVariable = () => variableView.getVariables()[0] as CustomVariable; + const getDependantPanel = () => + ((dashboard.state.body as SceneGridLayout).state.children[0] as SceneGridItem).state.body as VizPanel; + + expect(getSourceVariable().getValue()).toBe('test'); + // Using description to get the interpolated value + expect(getDependantPanel().getDescription()).toContain('Panel A depends on customVar with current value test'); + + variableView.onEdit(getSourceVariable().state.name); + // Simulating changing the type and update the value + variableView.onTypeChange('constant'); + getSourceVariable().setState({ value: 'newValue' }); + + expect(getSourceVariable().getValue()).toBe('newValue'); + expect(getDependantPanel().getDescription()).toContain('newValue'); + }); }); }); @@ -115,10 +230,14 @@ async function buildTestScene() { new CustomVariable({ name: 'customVar', query: 'test, test2', + value: 'test', + text: 'test', }), new CustomVariable({ name: 'customVar2', - query: 'test3, test4', + query: 'test3, test4, $customVar', + value: '$customVar', + text: '$customVar', }), ], }), @@ -127,10 +246,12 @@ async function buildTestScene() { new SceneGridItem({ key: 'griditem-1', x: 0, - y: 0, - width: 10, - height: 12, - body: undefined, + body: new VizPanel({ + title: 'Panel A', + description: 'Panel A depends on customVar with current value $customVar', + key: 'panel-1', + pluginId: 'table', + }), }), ], }), diff --git a/public/app/features/dashboard-scene/settings/VariablesEditView.tsx b/public/app/features/dashboard-scene/settings/VariablesEditView.tsx index 7f9999ad1b7..48ede5a45c3 100644 --- a/public/app/features/dashboard-scene/settings/VariablesEditView.tsx +++ b/public/app/features/dashboard-scene/settings/VariablesEditView.tsx @@ -1,16 +1,30 @@ import React from 'react'; -import { PageLayoutType } from '@grafana/data'; -import { SceneComponentProps, SceneObjectBase, SceneVariables, sceneGraph } from '@grafana/scenes'; +import { NavModel, NavModelItem, PageLayoutType } from '@grafana/data'; +import { + SceneComponentProps, + SceneObjectBase, + SceneVariable, + SceneVariableState, + SceneVariables, + sceneGraph, + AdHocFilterSet, +} from '@grafana/scenes'; import { Page } from 'app/core/components/Page/Page'; import { DashboardScene } from '../scene/DashboardScene'; import { NavToolbarActions } from '../scene/NavToolbarActions'; import { getDashboardSceneFor } from '../utils/utils'; +import { EditListViewSceneUrlSync } from './EditListViewSceneUrlSync'; import { DashboardEditView, DashboardEditViewState, useDashboardEditPageNav } from './utils'; +import { VariableEditorForm } from './variables/VariableEditorForm'; import { VariableEditorList } from './variables/VariableEditorList'; -export interface VariablesEditViewState extends DashboardEditViewState {} +import { EditableVariableType, getVariableScene, isEditableVariableType } from './variables/utils'; +export interface VariablesEditViewState extends DashboardEditViewState { + editIndex?: number | undefined; + originalVariableState?: SceneVariableState; +} export class VariablesEditView extends SceneObjectBase implements DashboardEditView { public static Component = VariableEditorSettingsListView; @@ -19,6 +33,8 @@ export class VariablesEditView extends SceneObjectBase i return 'variables'; } + protected _urlSync = new EditListViewSceneUrlSync(this); + public getDashboard(): DashboardScene { return getDashboardSceneFor(this); } @@ -32,6 +48,32 @@ export class VariablesEditView extends SceneObjectBase i return variables.findIndex((variable) => variable.state.name === identifier); }; + private replaceEditVariable = (newVariable: SceneVariable | AdHocFilterSet) => { + // Find the index of the variable to be deleted + const variableIndex = this.state.editIndex ?? -1; + const { variables } = this.getVariableSet().state; + const variable = variables[variableIndex]; + + if (!variable) { + // Handle the case where the variable is not found + console.error('Variable not found'); + return; + } + + if (newVariable instanceof AdHocFilterSet) { + // TODO: Update controls in adding this fiter set to the dashboard + } else { + const updatedVariables = [ + ...variables.slice(0, variableIndex), + newVariable, + ...variables.slice(variableIndex + 1), + ]; + + // Update the state or the variables array + this.getVariableSet().setState({ variables: updatedVariables }); + } + }; + public onDelete = (identifier: string) => { // Find the index of the variable to be deleted const variableIndex = this.getVariableIndex(identifier); @@ -106,7 +148,56 @@ export class VariablesEditView extends SceneObjectBase i }; public onEdit = (identifier: string) => { - return 'not implemented'; + const variableIndex = this.getVariableIndex(identifier); + if (variableIndex === -1) { + console.error('Variable not found'); + return; + } + this.setState({ editIndex: variableIndex, originalVariableState: { ...this.getVariables()[variableIndex].state } }); + }; + + public onTypeChange = (type: EditableVariableType) => { + // Find the index of the variable to be deleted + const variableIndex = this.state.editIndex ?? -1; + const { variables } = this.getVariableSet().state; + const variable = variables[variableIndex]; + + if (!variable) { + // Handle the case where the variable is not found + console.error('Variable not found'); + return; + } + + const { name, label } = variable.state; + const newVariable = getVariableScene(type, { name, label }); + this.replaceEditVariable(newVariable); + }; + + public onGoBack = () => { + this.setState({ editIndex: undefined }); + }; + + public onDiscardChanges: () => void = () => { + const variables = this.getVariableSet().state.variables; + const { editIndex, originalVariableState } = this.state; + if (editIndex === undefined || !originalVariableState) { + return; + } + const variable = variables[editIndex]; + if (!variable) { + return; + } + if (isEditableVariableType(originalVariableState.type)) { + const newVariable = getVariableScene(originalVariableState.type, originalVariableState); + if (newVariable instanceof AdHocFilterSet) { + // TODO: Update controls in adding this fiter set to the dashboard + } else { + const updatedVariables = [...variables.slice(0, editIndex), newVariable, ...variables.slice(editIndex + 1)]; + this.getVariableSet().setState({ variables: updatedVariables }); + } + } + + this.setState({ editIndex: undefined, originalVariableState: undefined }); }; } @@ -114,8 +205,26 @@ function VariableEditorSettingsListView({ model }: SceneComponentProps + ); + } + } return ( @@ -131,3 +240,43 @@ function VariableEditorSettingsListView({ model }: SceneComponentProps ); } + +interface VariableEditorSettingsEditViewProps { + variable: SceneVariable; + pageNav: NavModelItem; + navModel: NavModel; + dashboard: DashboardScene; + onTypeChange: (variableType: EditableVariableType) => void; + onGoBack: () => void; + onDiscardChanges: () => void; +} + +function VariableEditorSettingsView({ + variable, + pageNav, + navModel, + dashboard, + onTypeChange, + onGoBack, + onDiscardChanges, +}: VariableEditorSettingsEditViewProps) { + const parentTab = pageNav.children!.find((p) => p.active)!; + parentTab.parentItem = pageNav; + const { name } = variable.useState(); + + const editVariablePageNav = { + text: name, + parentItem: parentTab, + }; + return ( + + + + + ); +} diff --git a/public/app/features/dashboard-scene/settings/variables/VariableEditorForm.tsx b/public/app/features/dashboard-scene/settings/variables/VariableEditorForm.tsx new file mode 100644 index 00000000000..175a1728733 --- /dev/null +++ b/public/app/features/dashboard-scene/settings/variables/VariableEditorForm.tsx @@ -0,0 +1,128 @@ +import React from 'react'; + +import { SelectableValue } from '@grafana/data'; +import { selectors } from '@grafana/e2e-selectors'; +import { SceneVariable } from '@grafana/scenes'; +import { VariableHide, defaultVariableModel } from '@grafana/schema'; +import { HorizontalGroup, Button } from '@grafana/ui'; +import { VariableHideSelect } from 'app/features/dashboard-scene/settings/variables/components/VariableHideSelect'; +import { VariableLegend } from 'app/features/dashboard-scene/settings/variables/components/VariableLegend'; +import { VariableTextAreaField } from 'app/features/dashboard-scene/settings/variables/components/VariableTextAreaField'; +import { VariableTextField } from 'app/features/dashboard-scene/settings/variables/components/VariableTextField'; +import { VariableValuesPreview } from 'app/features/dashboard-scene/settings/variables/components/VariableValuesPreview'; +import { ConfirmDeleteModal } from 'app/features/variables/editor/ConfirmDeleteModal'; +import { VariableNameConstraints } from 'app/features/variables/editor/types'; + +import { VariableTypeSelect } from './components/VariableTypeSelect'; +import { EditableVariableType, getVariableEditor, hasVariableOptions, isEditableVariableType } from './utils'; + +interface VariableEditorFormProps { + variable: SceneVariable; + onTypeChange: (type: EditableVariableType) => void; + onGoBack: () => void; + onDiscardChanges: () => void; +} + +export function VariableEditorForm({ variable, onTypeChange, onGoBack, onDiscardChanges }: VariableEditorFormProps) { + const { name: initialName, type, label: initialLabel, description: initialDescription, hide } = variable.useState(); + const EditorToRender = isEditableVariableType(type) ? getVariableEditor(type) : undefined; + const [name, setName] = React.useState(initialName ?? ''); + const [label, setLabel] = React.useState(initialLabel ?? ''); + const [description, setDescription] = React.useState(initialDescription ?? ''); + + const onVariableTypeChange = (option: SelectableValue) => { + if (option.value) { + onTypeChange(option.value); + } + }; + + const onNameChange = (e: React.FormEvent) => setName(e.currentTarget.value); + const onLabelChange = (e: React.FormEvent) => setLabel(e.currentTarget.value); + const onDescriptionChange = (e: React.FormEvent) => setDescription(e.currentTarget.value); + + const onNameBlur = () => variable.setState({ name }); + const onLabelBlur = () => variable.setState({ label }); + const onDescriptionBlur = () => variable.setState({ description }); + const onHideChange = (hide: VariableHide) => variable.setState({ hide }); + + return ( + <> +
+ + + General + + + + + + + {EditorToRender && } + + {hasVariableOptions(variable) && } + +
+ + {/* */} + {/* */} + + + +
+ + console.log('needs implementation')} + onDismiss={() => console.log('needs implementation')} + /> + + ); +} diff --git a/public/app/features/variables/editor/VariableCheckboxField.tsx b/public/app/features/dashboard-scene/settings/variables/components/VariableCheckboxField.tsx similarity index 100% rename from public/app/features/variables/editor/VariableCheckboxField.tsx rename to public/app/features/dashboard-scene/settings/variables/components/VariableCheckboxField.tsx diff --git a/public/app/features/variables/editor/VariableHideSelect.tsx b/public/app/features/dashboard-scene/settings/variables/components/VariableHideSelect.tsx similarity index 100% rename from public/app/features/variables/editor/VariableHideSelect.tsx rename to public/app/features/dashboard-scene/settings/variables/components/VariableHideSelect.tsx diff --git a/public/app/features/variables/editor/VariableLegend.tsx b/public/app/features/dashboard-scene/settings/variables/components/VariableLegend.tsx similarity index 100% rename from public/app/features/variables/editor/VariableLegend.tsx rename to public/app/features/dashboard-scene/settings/variables/components/VariableLegend.tsx diff --git a/public/app/features/variables/editor/VariableSelectField.tsx b/public/app/features/dashboard-scene/settings/variables/components/VariableSelectField.tsx similarity index 94% rename from public/app/features/variables/editor/VariableSelectField.tsx rename to public/app/features/dashboard-scene/settings/variables/components/VariableSelectField.tsx index d1cc5bf017b..88c53385747 100644 --- a/public/app/features/variables/editor/VariableSelectField.tsx +++ b/public/app/features/dashboard-scene/settings/variables/components/VariableSelectField.tsx @@ -45,8 +45,8 @@ export function VariableSelectField({ function getStyles(theme: GrafanaTheme2) { return { - selectContainer: css` - margin-right: ${theme.spacing(0.5)}; - `, + selectContainer: css({ + marginRight: theme.spacing(0.5), + }), }; } diff --git a/public/app/features/variables/editor/VariableTextAreaField.tsx b/public/app/features/dashboard-scene/settings/variables/components/VariableTextAreaField.tsx similarity index 78% rename from public/app/features/variables/editor/VariableTextAreaField.tsx rename to public/app/features/dashboard-scene/settings/variables/components/VariableTextAreaField.tsx index 73027027c55..b4abcf943c1 100644 --- a/public/app/features/variables/editor/VariableTextAreaField.tsx +++ b/public/app/features/dashboard-scene/settings/variables/components/VariableTextAreaField.tsx @@ -9,7 +9,7 @@ interface VariableTextAreaFieldProps { name: string; value: string; placeholder: string; - onChange: (event: FormEvent) => void; + onChange?: (event: FormEvent) => void; width: number; ariaLabel?: string; required?: boolean; @@ -54,17 +54,17 @@ export function VariableTextAreaField({ export function getStyles(theme: GrafanaTheme2) { return { - textarea: css` - white-space: pre-wrap; - min-height: ${theme.spacing(4)}; - height: auto; - overflow: auto; - padding: ${theme.spacing(0.75, 1)}; - width: inherit; + textarea: css({ + whiteSpace: 'pre-wrap', + minHeight: theme.spacing(4), + height: 'auto', + overflow: 'auto', + padding: `${theme.spacing(0.75)} ${theme.spacing(1)}`, + width: 'inherit', - ${theme.breakpoints.down('sm')} { - width: 100%; - } - `, + [theme.breakpoints.down('sm')]: { + width: '100%', + }, + }), }; } diff --git a/public/app/features/variables/editor/VariableTextField.tsx b/public/app/features/dashboard-scene/settings/variables/components/VariableTextField.tsx similarity index 95% rename from public/app/features/variables/editor/VariableTextField.tsx rename to public/app/features/dashboard-scene/settings/variables/components/VariableTextField.tsx index 86890acf7c9..b06ddee1fc2 100644 --- a/public/app/features/variables/editor/VariableTextField.tsx +++ b/public/app/features/dashboard-scene/settings/variables/components/VariableTextField.tsx @@ -7,7 +7,7 @@ interface VariableTextFieldProps { value: string; name: string; placeholder?: string; - onChange: (event: FormEvent) => void; + onChange?: (event: FormEvent) => void; testId?: string; required?: boolean; width?: number; diff --git a/public/app/features/dashboard-scene/settings/variables/components/VariableTypeSelect.tsx b/public/app/features/dashboard-scene/settings/variables/components/VariableTypeSelect.tsx new file mode 100644 index 00000000000..06235597388 --- /dev/null +++ b/public/app/features/dashboard-scene/settings/variables/components/VariableTypeSelect.tsx @@ -0,0 +1,30 @@ +import React, { PropsWithChildren, useMemo } from 'react'; + +import { SelectableValue, VariableType } from '@grafana/data'; +import { selectors } from '@grafana/e2e-selectors'; +import { VariableSelectField } from 'app/features/dashboard-scene/settings/variables/components/VariableSelectField'; + +import { EditableVariableType, getVariableTypeSelectOptions } from '../utils'; + +interface Props { + onChange: (option: SelectableValue) => void; + type: VariableType; +} + +export function VariableTypeSelect({ onChange, type }: PropsWithChildren) { + const options = useMemo(() => getVariableTypeSelectOptions(), []); + const value = useMemo( + () => options.find((o: SelectableValue) => o.value === type) ?? options[0], + [options, type] + ); + + return ( + + ); +} diff --git a/public/app/features/variables/editor/VariableValuesPreview.tsx b/public/app/features/dashboard-scene/settings/variables/components/VariableValuesPreview.tsx similarity index 81% rename from public/app/features/variables/editor/VariableValuesPreview.tsx rename to public/app/features/dashboard-scene/settings/variables/components/VariableValuesPreview.tsx index 2c04e68198d..0265144ba53 100644 --- a/public/app/features/variables/editor/VariableValuesPreview.tsx +++ b/public/app/features/dashboard-scene/settings/variables/components/VariableValuesPreview.tsx @@ -3,17 +3,16 @@ import React, { MouseEvent, useCallback, useEffect, useState } from 'react'; import { GrafanaTheme2 } from '@grafana/data'; import { selectors } from '@grafana/e2e-selectors'; +import { VariableValueOption } from '@grafana/scenes'; import { Button, InlineFieldRow, InlineLabel, useStyles2 } from '@grafana/ui'; -import { VariableOption, VariableWithOptions } from '../types'; - export interface VariableValuesPreviewProps { - variable: VariableWithOptions; + options: VariableValueOption[]; } -export const VariableValuesPreview = ({ variable: { options } }: VariableValuesPreviewProps) => { +export const VariableValuesPreview = ({ options }: VariableValuesPreviewProps) => { const [previewLimit, setPreviewLimit] = useState(20); - const [previewOptions, setPreviewOptions] = useState([]); + const [previewOptions, setPreviewOptions] = useState([]); const showMoreOptions = useCallback( (event: MouseEvent) => { event.preventDefault(); @@ -34,8 +33,8 @@ export const VariableValuesPreview = ({ variable: { options } }: VariableValuesP {previewOptions.map((o, index) => ( - -
{o.text}
+ +
{o.label}
))} diff --git a/public/app/features/dashboard-scene/settings/variables/editors/AdHocFiltersVariableEditor.tsx b/public/app/features/dashboard-scene/settings/variables/editors/AdHocFiltersVariableEditor.tsx new file mode 100644 index 00000000000..15a50cffbfc --- /dev/null +++ b/public/app/features/dashboard-scene/settings/variables/editors/AdHocFiltersVariableEditor.tsx @@ -0,0 +1,12 @@ +import React from 'react'; + +import { AdHocFiltersVariable } from '@grafana/scenes'; + +interface AdHocFiltersVariableEditorProps { + variable: AdHocFiltersVariable; + onChange: (variable: AdHocFiltersVariable) => void; +} + +export function AdHocFiltersVariableEditor(props: AdHocFiltersVariableEditorProps) { + return
AdHocFiltersVariableEditor
; +} diff --git a/public/app/features/dashboard-scene/settings/variables/editors/ConstantVariableEditor.tsx b/public/app/features/dashboard-scene/settings/variables/editors/ConstantVariableEditor.tsx new file mode 100644 index 00000000000..be96dacdb61 --- /dev/null +++ b/public/app/features/dashboard-scene/settings/variables/editors/ConstantVariableEditor.tsx @@ -0,0 +1,12 @@ +import React from 'react'; + +import { ConstantVariable } from '@grafana/scenes'; + +interface ConstantVariableEditorProps { + variable: ConstantVariable; + onChange: (variable: ConstantVariable) => void; +} + +export function ConstantVariableEditor(props: ConstantVariableEditorProps) { + return
ConstantVariableEditor
; +} diff --git a/public/app/features/dashboard-scene/settings/variables/editors/CustomVariableEditor.tsx b/public/app/features/dashboard-scene/settings/variables/editors/CustomVariableEditor.tsx new file mode 100644 index 00000000000..10dae8142fe --- /dev/null +++ b/public/app/features/dashboard-scene/settings/variables/editors/CustomVariableEditor.tsx @@ -0,0 +1,11 @@ +import React from 'react'; + +import { CustomVariable } from '@grafana/scenes'; + +interface CustomVariableEditorProps { + variable: CustomVariable; +} + +export function CustomVariableEditor(props: CustomVariableEditorProps) { + return
CustomVariableEditor
; +} diff --git a/public/app/features/dashboard-scene/settings/variables/editors/DataSourceVariableEditor.tsx b/public/app/features/dashboard-scene/settings/variables/editors/DataSourceVariableEditor.tsx new file mode 100644 index 00000000000..6dc5099dc28 --- /dev/null +++ b/public/app/features/dashboard-scene/settings/variables/editors/DataSourceVariableEditor.tsx @@ -0,0 +1,12 @@ +import React from 'react'; + +import { DataSourceVariable } from '@grafana/scenes'; + +interface DataSourceVariableEditorProps { + variable: DataSourceVariable; + onChange: (variable: DataSourceVariable) => void; +} + +export function DataSourceVariableEditor(props: DataSourceVariableEditorProps) { + return
DataSourceVariableEditor
; +} diff --git a/public/app/features/dashboard-scene/settings/variables/editors/IntervalVariableEditor.tsx b/public/app/features/dashboard-scene/settings/variables/editors/IntervalVariableEditor.tsx new file mode 100644 index 00000000000..524ef32c41a --- /dev/null +++ b/public/app/features/dashboard-scene/settings/variables/editors/IntervalVariableEditor.tsx @@ -0,0 +1,12 @@ +import React from 'react'; + +import { IntervalVariable } from '@grafana/scenes'; + +interface IntervalVariableEditorProps { + variable: IntervalVariable; + onChange: (variable: IntervalVariable) => void; +} + +export function IntervalVariableEditor(props: IntervalVariableEditorProps) { + return
IntervalVariableEditor
; +} diff --git a/public/app/features/dashboard-scene/settings/variables/editors/QueryVariableEditor.tsx b/public/app/features/dashboard-scene/settings/variables/editors/QueryVariableEditor.tsx new file mode 100644 index 00000000000..57cf0b39ef4 --- /dev/null +++ b/public/app/features/dashboard-scene/settings/variables/editors/QueryVariableEditor.tsx @@ -0,0 +1,12 @@ +import React from 'react'; + +import { QueryVariable } from '@grafana/scenes'; + +interface QueryVariableEditorProps { + variable: QueryVariable; + onChange: (variable: QueryVariable) => void; +} + +export function QueryVariableEditor(props: QueryVariableEditorProps) { + return
QueryVariableEditor
; +} diff --git a/public/app/features/dashboard-scene/settings/variables/editors/TextBoxVariableEditor.tsx b/public/app/features/dashboard-scene/settings/variables/editors/TextBoxVariableEditor.tsx new file mode 100644 index 00000000000..3eb6289eb3f --- /dev/null +++ b/public/app/features/dashboard-scene/settings/variables/editors/TextBoxVariableEditor.tsx @@ -0,0 +1,12 @@ +import React from 'react'; + +import { TextBoxVariable } from '@grafana/scenes'; + +interface TextBoxVariableEditorProps { + variable: TextBoxVariable; + onChange: (variable: TextBoxVariable) => void; +} + +export function TextBoxVariableEditor(props: TextBoxVariableEditorProps) { + return
TextBoxVariableEditor
; +} diff --git a/public/app/features/dashboard-scene/settings/variables/utils.test.ts b/public/app/features/dashboard-scene/settings/variables/utils.test.ts new file mode 100644 index 00000000000..35a55444ed2 --- /dev/null +++ b/public/app/features/dashboard-scene/settings/variables/utils.test.ts @@ -0,0 +1,140 @@ +import { setTemplateSrv, TemplateSrv } from '@grafana/runtime'; +import { + CustomVariable, + ConstantVariable, + IntervalVariable, + QueryVariable, + DataSourceVariable, + AdHocFiltersVariable, + TextBoxVariable, +} from '@grafana/scenes'; +import { VariableType } from '@grafana/schema'; + +import { AdHocFiltersVariableEditor } from './editors/AdHocFiltersVariableEditor'; +import { ConstantVariableEditor } from './editors/ConstantVariableEditor'; +import { CustomVariableEditor } from './editors/CustomVariableEditor'; +import { DataSourceVariableEditor } from './editors/DataSourceVariableEditor'; +import { IntervalVariableEditor } from './editors/IntervalVariableEditor'; +import { QueryVariableEditor } from './editors/QueryVariableEditor'; +import { TextBoxVariableEditor } from './editors/TextBoxVariableEditor'; +import { + isEditableVariableType, + EDITABLE_VARIABLES, + EDITABLE_VARIABLES_SELECT_ORDER, + getVariableTypeSelectOptions, + getVariableEditor, + getVariableScene, + hasVariableOptions, + EditableVariableType, +} from './utils'; + +const templateSrv = { + getAdhocFilters: jest.fn().mockReturnValue([{ key: 'origKey', operator: '=', value: '' }]), +} as unknown as TemplateSrv; + +describe('isEditableVariableType', () => { + it('should return true for editable variable types', () => { + const editableTypes: VariableType[] = ['custom', 'query', 'constant', 'interval', 'datasource', 'adhoc', 'textbox']; + editableTypes.forEach((type) => { + expect(isEditableVariableType(type)).toBe(true); + }); + }); + + it('should return false for non-editable variable types', () => { + const nonEditableTypes: VariableType[] = ['system']; + nonEditableTypes.forEach((type) => { + expect(isEditableVariableType(type)).toBe(false); + }); + }); +}); + +describe('getVariableTypeSelectOptions', () => { + it('should contain all editable variable types', () => { + const options = getVariableTypeSelectOptions(); + expect(options).toHaveLength(Object.keys(EDITABLE_VARIABLES).length); + + EDITABLE_VARIABLES_SELECT_ORDER.forEach((type) => { + expect(EDITABLE_VARIABLES).toHaveProperty(type); + }); + }); + + it('should return an array of selectable values for editable variable types', () => { + const options = getVariableTypeSelectOptions(); + expect(options).toHaveLength(7); + + options.forEach((option, index) => { + const editableType = EDITABLE_VARIABLES_SELECT_ORDER[index]; + const variableTypeConfig = EDITABLE_VARIABLES[editableType]; + + expect(option.value).toBe(editableType); + expect(option.label).toBe(variableTypeConfig.name); + expect(option.description).toBe(variableTypeConfig.description); + }); + }); +}); + +describe('getVariableEditor', () => { + it.each(Object.keys(EDITABLE_VARIABLES) as EditableVariableType[])( + 'should define an editor for every variable type', + (type) => { + const editor = getVariableEditor(type); + expect(editor).toBeDefined(); + } + ); + + it.each([ + ['custom', CustomVariableEditor], + ['query', QueryVariableEditor], + ['constant', ConstantVariableEditor], + ['interval', IntervalVariableEditor], + ['datasource', DataSourceVariableEditor], + ['adhoc', AdHocFiltersVariableEditor], + ['textbox', TextBoxVariableEditor], + ])('should return the correct editor for each variable type', (type, ExpectedVariableEditor) => { + expect(getVariableEditor(type as EditableVariableType)).toBe(ExpectedVariableEditor); + }); +}); + +describe('getVariableScene', () => { + beforeAll(() => { + setTemplateSrv(templateSrv); + }); + + it.each(Object.keys(EDITABLE_VARIABLES) as EditableVariableType[])( + 'should define a scene object for every variable type', + (type) => { + const variable = getVariableScene(type, { name: 'foo' }); + expect(variable).toBeDefined(); + } + ); + + it.each([ + ['custom', CustomVariable], + ['query', QueryVariable], + ['constant', ConstantVariable], + ['interval', IntervalVariable], + ['datasource', DataSourceVariable], + ['adhoc', AdHocFiltersVariable], + ['textbox', TextBoxVariable], + ])('should return the scene variable instance for the given editable variable type', () => { + const initialState = { name: 'MyVariable' }; + const sceneVariable = getVariableScene('custom', initialState); + expect(sceneVariable).toBeInstanceOf(CustomVariable); + expect(sceneVariable.state.name).toBe(initialState.name); + }); +}); + +describe('hasVariableOptions', () => { + it('should return true for scene variables with options property', () => { + const variableWithOptions = new CustomVariable({ + name: 'MyVariable', + options: [{ value: 'option1', label: 'Option 1' }], + }); + expect(hasVariableOptions(variableWithOptions)).toBe(true); + }); + + it('should return false for scene variables without options property', () => { + const variableWithoutOptions = new ConstantVariable({ name: 'MyVariable' }); + expect(hasVariableOptions(variableWithoutOptions)).toBe(false); + }); +}); diff --git a/public/app/features/dashboard-scene/settings/variables/utils.ts b/public/app/features/dashboard-scene/settings/variables/utils.ts new file mode 100644 index 00000000000..f8c8885c473 --- /dev/null +++ b/public/app/features/dashboard-scene/settings/variables/utils.ts @@ -0,0 +1,124 @@ +import { SelectableValue } from '@grafana/data'; +import { + ConstantVariable, + CustomVariable, + DataSourceVariable, + IntervalVariable, + TextBoxVariable, + QueryVariable, + AdHocFilterSet, + SceneVariable, + VariableValueOption, +} from '@grafana/scenes'; +import { VariableType } from '@grafana/schema'; + +import { AdHocFiltersVariableEditor } from './editors/AdHocFiltersVariableEditor'; +import { ConstantVariableEditor } from './editors/ConstantVariableEditor'; +import { CustomVariableEditor } from './editors/CustomVariableEditor'; +import { DataSourceVariableEditor } from './editors/DataSourceVariableEditor'; +import { IntervalVariableEditor } from './editors/IntervalVariableEditor'; +import { QueryVariableEditor } from './editors/QueryVariableEditor'; +import { TextBoxVariableEditor } from './editors/TextBoxVariableEditor'; + +interface EditableVariableConfig { + name: string; + description: string; + editor: React.ComponentType; +} + +export type EditableVariableType = Exclude; + +export function isEditableVariableType(type: VariableType): type is EditableVariableType { + return type !== 'system'; +} + +export const EDITABLE_VARIABLES: Record = { + custom: { + name: 'Custom', + description: 'Define variable values manually', + editor: CustomVariableEditor, + }, + query: { + name: 'Query', + description: 'Variable values are fetched from a datasource query', + editor: QueryVariableEditor, + }, + constant: { + name: 'Constant', + description: 'Define a hidden constant variable, useful for metric prefixes in dashboards you want to share', + editor: ConstantVariableEditor, + }, + interval: { + name: 'Interval', + description: 'Define a timespan interval (ex 1m, 1h, 1d)', + editor: IntervalVariableEditor, + }, + datasource: { + name: 'Data source', + description: 'Enables you to dynamically switch the data source for multiple panels', + editor: DataSourceVariableEditor, + }, + adhoc: { + name: 'Ad hoc filters', + description: 'Add key/value filters on the fly', + editor: AdHocFiltersVariableEditor, + }, + textbox: { + name: 'Textbox', + description: 'Define a textbox variable, where users can enter any arbitrary string', + editor: TextBoxVariableEditor, + }, +}; + +export const EDITABLE_VARIABLES_SELECT_ORDER: EditableVariableType[] = [ + 'query', + 'custom', + 'textbox', + 'constant', + 'datasource', + 'interval', + 'adhoc', +]; + +export function getVariableTypeSelectOptions(): Array> { + return EDITABLE_VARIABLES_SELECT_ORDER.map((variableType) => ({ + label: EDITABLE_VARIABLES[variableType].name, + value: variableType, + description: EDITABLE_VARIABLES[variableType].description, + })); +} + +export function getVariableEditor(type: EditableVariableType) { + return EDITABLE_VARIABLES[type].editor; +} + +interface CommonVariableProperties { + name: string; + label?: string; +} + +export function getVariableScene(type: EditableVariableType, initialState: CommonVariableProperties) { + switch (type) { + case 'custom': + return new CustomVariable(initialState); + case 'query': + return new QueryVariable(initialState); + case 'constant': + return new ConstantVariable(initialState); + case 'interval': + return new IntervalVariable(initialState); + case 'datasource': + return new DataSourceVariable(initialState); + case 'adhoc': + // TODO: Initialize properly AdHocFilterSet with initialState + return new AdHocFilterSet({ name: initialState.name }); + case 'textbox': + return new TextBoxVariable(initialState); + } +} + +export function hasVariableOptions( + variable: SceneVariable +): variable is SceneVariable & { options: VariableValueOption[] } { + return 'options' in variable.state; +} diff --git a/public/app/features/variables/adhoc/AdHocVariableEditor.tsx b/public/app/features/variables/adhoc/AdHocVariableEditor.tsx index 1b466c93591..ac079a2d787 100644 --- a/public/app/features/variables/adhoc/AdHocVariableEditor.tsx +++ b/public/app/features/variables/adhoc/AdHocVariableEditor.tsx @@ -6,7 +6,7 @@ import { Alert, Field } from '@grafana/ui'; import { DataSourcePicker } from 'app/features/datasources/components/picker/DataSourcePicker'; import { StoreState } from 'app/types'; -import { VariableLegend } from '../editor/VariableLegend'; +import { VariableLegend } from '../../dashboard-scene/settings/variables/components/VariableLegend'; import { initialVariableEditorState } from '../editor/reducer'; import { getAdhocVariableEditorState } from '../editor/selectors'; import { VariableEditorProps } from '../editor/types'; diff --git a/public/app/features/variables/constant/ConstantVariableEditor.tsx b/public/app/features/variables/constant/ConstantVariableEditor.tsx index abb49bbd8b8..a73d1e4fa1d 100644 --- a/public/app/features/variables/constant/ConstantVariableEditor.tsx +++ b/public/app/features/variables/constant/ConstantVariableEditor.tsx @@ -2,8 +2,8 @@ import React, { FormEvent, PureComponent } from 'react'; import { selectors } from '@grafana/e2e-selectors'; -import { VariableLegend } from '../editor/VariableLegend'; -import { VariableTextField } from '../editor/VariableTextField'; +import { VariableLegend } from '../../dashboard-scene/settings/variables/components/VariableLegend'; +import { VariableTextField } from '../../dashboard-scene/settings/variables/components/VariableTextField'; import { VariableEditorProps } from '../editor/types'; import { ConstantVariableModel } from '../types'; diff --git a/public/app/features/variables/custom/CustomVariableEditor.tsx b/public/app/features/variables/custom/CustomVariableEditor.tsx index c64c5a29fe1..bbf43309ca6 100644 --- a/public/app/features/variables/custom/CustomVariableEditor.tsx +++ b/public/app/features/variables/custom/CustomVariableEditor.tsx @@ -5,9 +5,9 @@ import { selectors } from '@grafana/e2e-selectors'; import { connectWithStore } from 'app/core/utils/connectWithReduxStore'; import { StoreState } from 'app/types'; +import { VariableLegend } from '../../dashboard-scene/settings/variables/components/VariableLegend'; +import { VariableTextAreaField } from '../../dashboard-scene/settings/variables/components/VariableTextAreaField'; import { SelectionOptionsEditor } from '../editor/SelectionOptionsEditor'; -import { VariableLegend } from '../editor/VariableLegend'; -import { VariableTextAreaField } from '../editor/VariableTextAreaField'; import { OnPropChangeArguments, VariableEditorProps } from '../editor/types'; import { changeVariableMultiValue } from '../state/actions'; import { CustomVariableModel, VariableWithMultiSupport } from '../types'; diff --git a/public/app/features/variables/datasource/DataSourceVariableEditor.tsx b/public/app/features/variables/datasource/DataSourceVariableEditor.tsx index 6185d257e9f..a7ac33bfd93 100644 --- a/public/app/features/variables/datasource/DataSourceVariableEditor.tsx +++ b/public/app/features/variables/datasource/DataSourceVariableEditor.tsx @@ -5,10 +5,10 @@ import { SelectableValue } from '@grafana/data'; import { selectors } from '@grafana/e2e-selectors'; import { StoreState } from '../../../types'; +import { VariableLegend } from '../../dashboard-scene/settings/variables/components/VariableLegend'; +import { VariableSelectField } from '../../dashboard-scene/settings/variables/components/VariableSelectField'; +import { VariableTextField } from '../../dashboard-scene/settings/variables/components/VariableTextField'; import { SelectionOptionsEditor } from '../editor/SelectionOptionsEditor'; -import { VariableLegend } from '../editor/VariableLegend'; -import { VariableSelectField } from '../editor/VariableSelectField'; -import { VariableTextField } from '../editor/VariableTextField'; import { initialVariableEditorState } from '../editor/reducer'; import { getDatasourceVariableEditorState } from '../editor/selectors'; import { OnPropChangeArguments, VariableEditorProps } from '../editor/types'; diff --git a/public/app/features/variables/editor/LegacyVariableQueryEditor.tsx b/public/app/features/variables/editor/LegacyVariableQueryEditor.tsx index 53e6b2226e9..069aed31fb0 100644 --- a/public/app/features/variables/editor/LegacyVariableQueryEditor.tsx +++ b/public/app/features/variables/editor/LegacyVariableQueryEditor.tsx @@ -4,10 +4,9 @@ import React, { useCallback, useState } from 'react'; import { selectors } from '@grafana/e2e-selectors'; import { TextArea, useStyles2 } from '@grafana/ui'; +import { getStyles } from '../../dashboard-scene/settings/variables/components/VariableTextAreaField'; import { VariableQueryEditorProps } from '../types'; -import { getStyles } from './VariableTextAreaField'; - export const LEGACY_VARIABLE_QUERY_EDITOR_NAME = 'Grafana-LegacyVariableQueryEditor'; export const LegacyVariableQueryEditor = ({ onChange, query }: VariableQueryEditorProps) => { diff --git a/public/app/features/variables/editor/SelectionOptionsEditor.tsx b/public/app/features/variables/editor/SelectionOptionsEditor.tsx index 06cf1525b71..3f0e51b567f 100644 --- a/public/app/features/variables/editor/SelectionOptionsEditor.tsx +++ b/public/app/features/variables/editor/SelectionOptionsEditor.tsx @@ -3,12 +3,12 @@ import React, { ChangeEvent, FormEvent, useCallback } from 'react'; import { selectors } from '@grafana/e2e-selectors'; import { VerticalGroup } from '@grafana/ui'; +import { VariableCheckboxField } from '../../dashboard-scene/settings/variables/components/VariableCheckboxField'; +import { VariableTextField } from '../../dashboard-scene/settings/variables/components/VariableTextField'; import { KeyedVariableIdentifier } from '../state/types'; import { VariableWithMultiSupport } from '../types'; import { toKeyedVariableIdentifier } from '../utils'; -import { VariableCheckboxField } from './VariableCheckboxField'; -import { VariableTextField } from './VariableTextField'; import { VariableEditorProps } from './types'; export interface SelectionOptionsEditorProps diff --git a/public/app/features/variables/editor/VariableEditorEditor.tsx b/public/app/features/variables/editor/VariableEditorEditor.tsx index 5ebb4ce7ebd..5cb9a53d5f3 100644 --- a/public/app/features/variables/editor/VariableEditorEditor.tsx +++ b/public/app/features/variables/editor/VariableEditorEditor.tsx @@ -8,6 +8,11 @@ import { locationService } from '@grafana/runtime'; import { Button, HorizontalGroup, Icon } from '@grafana/ui'; import { StoreState, ThunkDispatch } from '../../../types'; +import { VariableHideSelect } from '../../dashboard-scene/settings/variables/components/VariableHideSelect'; +import { VariableLegend } from '../../dashboard-scene/settings/variables/components/VariableLegend'; +import { VariableTextAreaField } from '../../dashboard-scene/settings/variables/components/VariableTextAreaField'; +import { VariableTextField } from '../../dashboard-scene/settings/variables/components/VariableTextField'; +import { VariableValuesPreview } from '../../dashboard-scene/settings/variables/components/VariableValuesPreview'; import { variableAdapters } from '../adapters'; import { hasOptions } from '../guard'; import { updateOptions } from '../state/actions'; @@ -19,12 +24,7 @@ import { VariableHide } from '../types'; import { toKeyedVariableIdentifier, toVariablePayload } from '../utils'; import { ConfirmDeleteModal } from './ConfirmDeleteModal'; -import { VariableHideSelect } from './VariableHideSelect'; -import { VariableLegend } from './VariableLegend'; -import { VariableTextAreaField } from './VariableTextAreaField'; -import { VariableTextField } from './VariableTextField'; import { VariableTypeSelect } from './VariableTypeSelect'; -import { VariableValuesPreview } from './VariableValuesPreview'; import { changeVariableName, variableEditorMount, variableEditorUnMount } from './actions'; import { OnPropChangeArguments, VariableNameConstraints } from './types'; @@ -138,6 +138,14 @@ export class VariableEditorEditorUnConnected extends PureComponent locationService.partial({ editIndex: null }); }; + getVariableOptions = () => { + const { variable } = this.props; + if (!hasOptions(variable)) { + return []; + } + return variable.options.map((option) => ({ label: String(option.text), value: String(option.value) })); + }; + render() { const { variable } = this.props; const EditorToRender = variableAdapters.get(this.props.variable.type).editor; @@ -188,7 +196,7 @@ export class VariableEditorEditorUnConnected extends PureComponent {EditorToRender && } - {hasOptions(this.props.variable) ? : null} + {hasOptions(this.props.variable) ? : null}
diff --git a/public/app/features/variables/editor/VariableTypeSelect.tsx b/public/app/features/variables/editor/VariableTypeSelect.tsx index 1963e23dc5e..65d80f7d83e 100644 --- a/public/app/features/variables/editor/VariableTypeSelect.tsx +++ b/public/app/features/variables/editor/VariableTypeSelect.tsx @@ -3,7 +3,7 @@ import React, { PropsWithChildren, useMemo } from 'react'; import { SelectableValue, VariableType } from '@grafana/data'; import { selectors } from '@grafana/e2e-selectors'; -import { VariableSelectField } from '../editor/VariableSelectField'; +import { VariableSelectField } from '../../dashboard-scene/settings/variables/components/VariableSelectField'; import { getVariableTypes } from '../utils'; interface Props { diff --git a/public/app/features/variables/interval/IntervalVariableEditor.tsx b/public/app/features/variables/interval/IntervalVariableEditor.tsx index 0aae4badf2f..d9e46c29462 100644 --- a/public/app/features/variables/interval/IntervalVariableEditor.tsx +++ b/public/app/features/variables/interval/IntervalVariableEditor.tsx @@ -5,10 +5,10 @@ import { GrafanaTheme2, IntervalVariableModel, SelectableValue } from '@grafana/ import { selectors } from '@grafana/e2e-selectors'; import { useStyles2 } from '@grafana/ui'; -import { VariableCheckboxField } from '../editor/VariableCheckboxField'; -import { VariableLegend } from '../editor/VariableLegend'; -import { VariableSelectField } from '../editor/VariableSelectField'; -import { VariableTextField } from '../editor/VariableTextField'; +import { VariableCheckboxField } from '../../dashboard-scene/settings/variables/components/VariableCheckboxField'; +import { VariableLegend } from '../../dashboard-scene/settings/variables/components/VariableLegend'; +import { VariableSelectField } from '../../dashboard-scene/settings/variables/components/VariableSelectField'; +import { VariableTextField } from '../../dashboard-scene/settings/variables/components/VariableTextField'; import { VariableEditorProps } from '../editor/types'; const STEP_OPTIONS = [1, 2, 3, 4, 5, 10, 20, 30, 40, 50, 100, 200, 300, 400, 500].map((count) => ({ diff --git a/public/app/features/variables/query/QueryVariableEditor.tsx b/public/app/features/variables/query/QueryVariableEditor.tsx index d3a3d6fe350..8cdea8c630d 100644 --- a/public/app/features/variables/query/QueryVariableEditor.tsx +++ b/public/app/features/variables/query/QueryVariableEditor.tsx @@ -9,9 +9,9 @@ import { DataSourcePicker } from 'app/features/datasources/components/picker/Dat import { StoreState } from '../../../types'; import { getTimeSrv } from '../../dashboard/services/TimeSrv'; +import { VariableLegend } from '../../dashboard-scene/settings/variables/components/VariableLegend'; +import { VariableTextAreaField } from '../../dashboard-scene/settings/variables/components/VariableTextAreaField'; import { SelectionOptionsEditor } from '../editor/SelectionOptionsEditor'; -import { VariableLegend } from '../editor/VariableLegend'; -import { VariableTextAreaField } from '../editor/VariableTextAreaField'; import { initialVariableEditorState } from '../editor/reducer'; import { getQueryVariableEditorState } from '../editor/selectors'; import { OnPropChangeArguments, VariableEditorProps } from '../editor/types'; diff --git a/public/app/features/variables/query/QueryVariableSortSelect.tsx b/public/app/features/variables/query/QueryVariableSortSelect.tsx index c6d0bc38cdb..34ccadd5b4c 100644 --- a/public/app/features/variables/query/QueryVariableSortSelect.tsx +++ b/public/app/features/variables/query/QueryVariableSortSelect.tsx @@ -3,7 +3,7 @@ import React, { PropsWithChildren, useMemo } from 'react'; import { SelectableValue } from '@grafana/data'; import { selectors } from '@grafana/e2e-selectors'; -import { VariableSelectField } from '../editor/VariableSelectField'; +import { VariableSelectField } from '../../dashboard-scene/settings/variables/components/VariableSelectField'; import { VariableSort } from '../types'; interface Props { diff --git a/public/app/features/variables/textbox/TextBoxVariableEditor.tsx b/public/app/features/variables/textbox/TextBoxVariableEditor.tsx index 7c5b262fe4f..4ec385d370c 100644 --- a/public/app/features/variables/textbox/TextBoxVariableEditor.tsx +++ b/public/app/features/variables/textbox/TextBoxVariableEditor.tsx @@ -2,8 +2,8 @@ import React, { FormEvent, ReactElement, useCallback } from 'react'; import { selectors } from '@grafana/e2e-selectors'; -import { VariableLegend } from '../editor/VariableLegend'; -import { VariableTextField } from '../editor/VariableTextField'; +import { VariableLegend } from '../../dashboard-scene/settings/variables/components/VariableLegend'; +import { VariableTextField } from '../../dashboard-scene/settings/variables/components/VariableTextField'; import { VariableEditorProps } from '../editor/types'; import { TextBoxVariableModel } from '../types';