mirror of https://github.com/grafana/grafana.git
EditVariable: Add base form to edit variables (#80172)
This commit is contained in:
parent
e69feef314
commit
e9f1b41d23
|
|
@ -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"]
|
||||
|
|
|
|||
|
|
@ -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',
|
||||
},
|
||||
|
|
|
|||
|
|
@ -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<DashboardLinksEditViewState> = {};
|
||||
let update: Partial<EditListViewState> = {};
|
||||
if (typeof values.editIndex === 'string') {
|
||||
update = { editIndex: Number(values.editIndex) };
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -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',
|
||||
}),
|
||||
}),
|
||||
],
|
||||
}),
|
||||
|
|
|
|||
|
|
@ -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<VariablesEditViewState> implements DashboardEditView {
|
||||
public static Component = VariableEditorSettingsListView;
|
||||
|
|
@ -19,6 +33,8 @@ export class VariablesEditView extends SceneObjectBase<VariablesEditViewState> i
|
|||
return 'variables';
|
||||
}
|
||||
|
||||
protected _urlSync = new EditListViewSceneUrlSync(this);
|
||||
|
||||
public getDashboard(): DashboardScene {
|
||||
return getDashboardSceneFor(this);
|
||||
}
|
||||
|
|
@ -32,6 +48,32 @@ export class VariablesEditView extends SceneObjectBase<VariablesEditViewState> 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<VariablesEditViewState> 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<Variables
|
|||
const dashboard = model.getDashboard();
|
||||
const { navModel, pageNav } = useDashboardEditPageNav(dashboard, model.getUrlKey());
|
||||
// get variables from dashboard state
|
||||
const { onDelete, onDuplicated, onOrderChanged, onEdit } = model;
|
||||
const { onDelete, onDuplicated, onOrderChanged, onEdit, onTypeChange, onGoBack, onDiscardChanges } = model;
|
||||
const { variables } = model.getVariableSet().useState();
|
||||
const { editIndex } = model.useState();
|
||||
|
||||
if (editIndex !== undefined && variables[editIndex]) {
|
||||
const variable = variables[editIndex];
|
||||
if (variable) {
|
||||
return (
|
||||
<VariableEditorSettingsView
|
||||
variable={variable}
|
||||
onTypeChange={onTypeChange}
|
||||
onGoBack={onGoBack}
|
||||
onDiscardChanges={onDiscardChanges}
|
||||
pageNav={pageNav}
|
||||
navModel={navModel}
|
||||
dashboard={dashboard}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Page navModel={navModel} pageNav={pageNav} layout={PageLayoutType.Standard}>
|
||||
|
|
@ -131,3 +240,43 @@ function VariableEditorSettingsListView({ model }: SceneComponentProps<Variables
|
|||
</Page>
|
||||
);
|
||||
}
|
||||
|
||||
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 (
|
||||
<Page navModel={navModel} pageNav={editVariablePageNav} layout={PageLayoutType.Standard}>
|
||||
<NavToolbarActions dashboard={dashboard} />
|
||||
<VariableEditorForm
|
||||
variable={variable}
|
||||
onTypeChange={onTypeChange}
|
||||
onGoBack={onGoBack}
|
||||
onDiscardChanges={onDiscardChanges}
|
||||
/>
|
||||
</Page>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<EditableVariableType>) => {
|
||||
if (option.value) {
|
||||
onTypeChange(option.value);
|
||||
}
|
||||
};
|
||||
|
||||
const onNameChange = (e: React.FormEvent<HTMLInputElement>) => setName(e.currentTarget.value);
|
||||
const onLabelChange = (e: React.FormEvent<HTMLInputElement>) => setLabel(e.currentTarget.value);
|
||||
const onDescriptionChange = (e: React.FormEvent<HTMLTextAreaElement>) => 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 (
|
||||
<>
|
||||
<form aria-label="Variable editor Form">
|
||||
<VariableTypeSelect onChange={onVariableTypeChange} type={type} />
|
||||
|
||||
<VariableLegend>General</VariableLegend>
|
||||
<VariableTextField
|
||||
value={name}
|
||||
onBlur={onNameBlur}
|
||||
onChange={onNameChange}
|
||||
name="Name"
|
||||
placeholder="Variable name"
|
||||
description="The name of the template variable. (Max. 50 characters)"
|
||||
testId={selectors.pages.Dashboard.Settings.Variables.Edit.General.generalNameInputV2}
|
||||
maxLength={VariableNameConstraints.MaxSize}
|
||||
required
|
||||
/>
|
||||
<VariableTextField
|
||||
name="Label"
|
||||
description="Optional display name"
|
||||
value={label}
|
||||
onChange={onLabelChange}
|
||||
placeholder="Label name"
|
||||
onBlur={onLabelBlur}
|
||||
testId={selectors.pages.Dashboard.Settings.Variables.Edit.General.generalLabelInputV2}
|
||||
/>
|
||||
<VariableTextAreaField
|
||||
name="Description"
|
||||
value={description}
|
||||
onChange={onDescriptionChange}
|
||||
placeholder="Descriptive text"
|
||||
onBlur={onDescriptionBlur}
|
||||
width={52}
|
||||
/>
|
||||
|
||||
<VariableHideSelect onChange={onHideChange} hide={hide || defaultVariableModel.hide!} type={type} />
|
||||
|
||||
{EditorToRender && <EditorToRender variable={variable} />}
|
||||
|
||||
{hasVariableOptions(variable) && <VariableValuesPreview options={variable.options} />}
|
||||
|
||||
<div style={{ marginTop: '16px' }}>
|
||||
<HorizontalGroup spacing="md" height="inherit">
|
||||
{/* <Button variant="destructive" fill="outline" onClick={onModalOpen}>
|
||||
Delete
|
||||
</Button> */}
|
||||
{/* <Button
|
||||
type="submit"
|
||||
aria-label={selectors.pages.Dashboard.Settings.Variables.Edit.General.submitButton}
|
||||
disabled={loading}
|
||||
variant="secondary"
|
||||
>
|
||||
Run query
|
||||
{loading && <Icon className="spin-clockwise" name="sync" size="sm" style={{ marginLeft: '2px' }} />}
|
||||
</Button> */}
|
||||
<Button
|
||||
variant="secondary"
|
||||
data-testid={selectors.pages.Dashboard.Settings.Variables.Edit.General.applyButton}
|
||||
onClick={onGoBack}
|
||||
>
|
||||
Back to list
|
||||
</Button>
|
||||
<Button
|
||||
variant="destructive"
|
||||
data-testid={selectors.pages.Dashboard.Settings.Variables.Edit.General.applyButton}
|
||||
onClick={onDiscardChanges}
|
||||
>
|
||||
Discard changes
|
||||
</Button>
|
||||
</HorizontalGroup>
|
||||
</div>
|
||||
</form>
|
||||
<ConfirmDeleteModal
|
||||
isOpen={false}
|
||||
varName={variable.state.name}
|
||||
onConfirm={() => console.log('needs implementation')}
|
||||
onDismiss={() => console.log('needs implementation')}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
@ -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),
|
||||
}),
|
||||
};
|
||||
}
|
||||
|
|
@ -9,7 +9,7 @@ interface VariableTextAreaFieldProps {
|
|||
name: string;
|
||||
value: string;
|
||||
placeholder: string;
|
||||
onChange: (event: FormEvent<HTMLTextAreaElement>) => void;
|
||||
onChange?: (event: FormEvent<HTMLTextAreaElement>) => 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%',
|
||||
},
|
||||
}),
|
||||
};
|
||||
}
|
||||
|
|
@ -7,7 +7,7 @@ interface VariableTextFieldProps {
|
|||
value: string;
|
||||
name: string;
|
||||
placeholder?: string;
|
||||
onChange: (event: FormEvent<HTMLInputElement>) => void;
|
||||
onChange?: (event: FormEvent<HTMLInputElement>) => void;
|
||||
testId?: string;
|
||||
required?: boolean;
|
||||
width?: number;
|
||||
|
|
@ -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<EditableVariableType>) => void;
|
||||
type: VariableType;
|
||||
}
|
||||
|
||||
export function VariableTypeSelect({ onChange, type }: PropsWithChildren<Props>) {
|
||||
const options = useMemo(() => getVariableTypeSelectOptions(), []);
|
||||
const value = useMemo(
|
||||
() => options.find((o: SelectableValue<EditableVariableType>) => o.value === type) ?? options[0],
|
||||
[options, type]
|
||||
);
|
||||
|
||||
return (
|
||||
<VariableSelectField
|
||||
name="Select variable type"
|
||||
value={value}
|
||||
options={options}
|
||||
onChange={onChange}
|
||||
testId={selectors.pages.Dashboard.Settings.Variables.Edit.General.generalTypeSelectV2}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
@ -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<VariableOption[]>([]);
|
||||
const [previewOptions, setPreviewOptions] = useState<VariableValueOption[]>([]);
|
||||
const showMoreOptions = useCallback(
|
||||
(event: MouseEvent) => {
|
||||
event.preventDefault();
|
||||
|
|
@ -34,8 +33,8 @@ export const VariableValuesPreview = ({ variable: { options } }: VariableValuesP
|
|||
<InlineFieldRow>
|
||||
{previewOptions.map((o, index) => (
|
||||
<InlineFieldRow key={`${o.value}-${index}`} className={styles.optionContainer}>
|
||||
<InlineLabel aria-label={selectors.pages.Dashboard.Settings.Variables.Edit.General.previewOfValuesOption}>
|
||||
<div className={styles.label}>{o.text}</div>
|
||||
<InlineLabel data-testid={selectors.pages.Dashboard.Settings.Variables.Edit.General.previewOfValuesOption}>
|
||||
<div className={styles.label}>{o.label}</div>
|
||||
</InlineLabel>
|
||||
</InlineFieldRow>
|
||||
))}
|
||||
|
|
@ -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 <div>AdHocFiltersVariableEditor</div>;
|
||||
}
|
||||
|
|
@ -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 <div>ConstantVariableEditor</div>;
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
import React from 'react';
|
||||
|
||||
import { CustomVariable } from '@grafana/scenes';
|
||||
|
||||
interface CustomVariableEditorProps {
|
||||
variable: CustomVariable;
|
||||
}
|
||||
|
||||
export function CustomVariableEditor(props: CustomVariableEditorProps) {
|
||||
return <div>CustomVariableEditor</div>;
|
||||
}
|
||||
|
|
@ -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 <div>DataSourceVariableEditor</div>;
|
||||
}
|
||||
|
|
@ -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 <div>IntervalVariableEditor</div>;
|
||||
}
|
||||
|
|
@ -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 <div>QueryVariableEditor</div>;
|
||||
}
|
||||
|
|
@ -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 <div>TextBoxVariableEditor</div>;
|
||||
}
|
||||
|
|
@ -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);
|
||||
});
|
||||
});
|
||||
|
|
@ -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<any>;
|
||||
}
|
||||
|
||||
export type EditableVariableType = Exclude<VariableType, 'system'>;
|
||||
|
||||
export function isEditableVariableType(type: VariableType): type is EditableVariableType {
|
||||
return type !== 'system';
|
||||
}
|
||||
|
||||
export const EDITABLE_VARIABLES: Record<EditableVariableType, EditableVariableConfig> = {
|
||||
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<SelectableValue<EditableVariableType>> {
|
||||
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;
|
||||
}
|
||||
|
|
@ -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';
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
|
|
|||
|
|
@ -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) => {
|
||||
|
|
|
|||
|
|
@ -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<Model extends VariableWithMultiSupport = VariableWithMultiSupport>
|
||||
|
|
|
|||
|
|
@ -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<Props, State>
|
|||
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<Props, State>
|
|||
|
||||
{EditorToRender && <EditorToRender variable={this.props.variable} onPropChange={this.onPropChanged} />}
|
||||
|
||||
{hasOptions(this.props.variable) ? <VariableValuesPreview variable={this.props.variable} /> : null}
|
||||
{hasOptions(this.props.variable) ? <VariableValuesPreview options={this.getVariableOptions()} /> : null}
|
||||
|
||||
<div style={{ marginTop: '16px' }}>
|
||||
<HorizontalGroup spacing="md" height="inherit">
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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) => ({
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue