mirror of https://github.com/grafana/grafana
CustomVariable: Be able to edit them using scenes (#80193)
--------- Co-authored-by: Alexandra Vargas <alexa1866@gmail.com>pull/80742/head^2
parent
c9211fbd69
commit
3b401d0d4d
@ -0,0 +1,116 @@ |
|||||||
|
import { render, fireEvent } from '@testing-library/react'; |
||||||
|
import React from 'react'; |
||||||
|
|
||||||
|
import { selectors } from '@grafana/e2e-selectors'; |
||||||
|
|
||||||
|
import { CustomVariableForm } from './CustomVariableForm'; |
||||||
|
|
||||||
|
describe('CustomVariableForm', () => { |
||||||
|
const onQueryChange = jest.fn(); |
||||||
|
const onMultiChange = jest.fn(); |
||||||
|
const onIncludeAllChange = jest.fn(); |
||||||
|
const onAllValueChange = jest.fn(); |
||||||
|
|
||||||
|
beforeEach(() => { |
||||||
|
jest.clearAllMocks(); |
||||||
|
}); |
||||||
|
|
||||||
|
it('should render the form fields correctly', () => { |
||||||
|
const { getByTestId } = render( |
||||||
|
<CustomVariableForm |
||||||
|
query="query" |
||||||
|
multi={true} |
||||||
|
allValue="custom value" |
||||||
|
includeAll={true} |
||||||
|
onQueryChange={onQueryChange} |
||||||
|
onMultiChange={onMultiChange} |
||||||
|
onIncludeAllChange={onIncludeAllChange} |
||||||
|
onAllValueChange={onAllValueChange} |
||||||
|
/> |
||||||
|
); |
||||||
|
|
||||||
|
const queryInput = getByTestId(selectors.pages.Dashboard.Settings.Variables.Edit.CustomVariable.customValueInput); |
||||||
|
const multiCheckbox = getByTestId( |
||||||
|
selectors.pages.Dashboard.Settings.Variables.Edit.General.selectionOptionsMultiSwitch |
||||||
|
); |
||||||
|
const includeAllCheckbox = getByTestId( |
||||||
|
selectors.pages.Dashboard.Settings.Variables.Edit.General.selectionOptionsIncludeAllSwitch |
||||||
|
); |
||||||
|
const allValueInput = getByTestId( |
||||||
|
selectors.pages.Dashboard.Settings.Variables.Edit.General.selectionOptionsCustomAllInput |
||||||
|
); |
||||||
|
|
||||||
|
expect(queryInput).toBeInTheDocument(); |
||||||
|
expect(queryInput).toHaveValue('query'); |
||||||
|
expect(multiCheckbox).toBeInTheDocument(); |
||||||
|
expect(multiCheckbox).toBeChecked(); |
||||||
|
expect(includeAllCheckbox).toBeInTheDocument(); |
||||||
|
expect(includeAllCheckbox).toBeChecked(); |
||||||
|
expect(allValueInput).toBeInTheDocument(); |
||||||
|
expect(allValueInput).toHaveValue('custom value'); |
||||||
|
}); |
||||||
|
|
||||||
|
it('should call the correct event handlers on input change', () => { |
||||||
|
const { getByTestId } = render( |
||||||
|
<CustomVariableForm |
||||||
|
query="" |
||||||
|
multi={true} |
||||||
|
allValue="" |
||||||
|
includeAll={true} |
||||||
|
onQueryChange={onQueryChange} |
||||||
|
onMultiChange={onMultiChange} |
||||||
|
onIncludeAllChange={onIncludeAllChange} |
||||||
|
onAllValueChange={onAllValueChange} |
||||||
|
/> |
||||||
|
); |
||||||
|
|
||||||
|
const queryInput = getByTestId(selectors.pages.Dashboard.Settings.Variables.Edit.CustomVariable.customValueInput); |
||||||
|
const multiCheckbox = getByTestId( |
||||||
|
selectors.pages.Dashboard.Settings.Variables.Edit.General.selectionOptionsMultiSwitch |
||||||
|
); |
||||||
|
const includeAllCheckbox = getByTestId( |
||||||
|
selectors.pages.Dashboard.Settings.Variables.Edit.General.selectionOptionsIncludeAllSwitch |
||||||
|
); |
||||||
|
const allValueInput = getByTestId( |
||||||
|
selectors.pages.Dashboard.Settings.Variables.Edit.General.selectionOptionsCustomAllInput |
||||||
|
); |
||||||
|
|
||||||
|
fireEvent.click(multiCheckbox); |
||||||
|
fireEvent.click(includeAllCheckbox); |
||||||
|
fireEvent.change(queryInput, { currentTarget: { value: 'test query' } }); |
||||||
|
fireEvent.change(allValueInput, { currentTarget: { value: 'test value' } }); |
||||||
|
|
||||||
|
expect(onMultiChange).toHaveBeenCalledTimes(1); |
||||||
|
expect(onIncludeAllChange).toHaveBeenCalledTimes(1); |
||||||
|
expect(onQueryChange).not.toHaveBeenCalledTimes(1); |
||||||
|
expect(onAllValueChange).not.toHaveBeenCalledTimes(1); |
||||||
|
}); |
||||||
|
|
||||||
|
it('should call the correct event handlers on input blur', () => { |
||||||
|
const { getByTestId } = render( |
||||||
|
<CustomVariableForm |
||||||
|
query="query value" |
||||||
|
multi={true} |
||||||
|
allValue="custom all value" |
||||||
|
includeAll={true} |
||||||
|
onQueryChange={onQueryChange} |
||||||
|
onMultiChange={onMultiChange} |
||||||
|
onIncludeAllChange={onIncludeAllChange} |
||||||
|
onAllValueChange={onAllValueChange} |
||||||
|
/> |
||||||
|
); |
||||||
|
|
||||||
|
const queryInput = getByTestId(selectors.pages.Dashboard.Settings.Variables.Edit.CustomVariable.customValueInput); |
||||||
|
const allValueInput = getByTestId( |
||||||
|
selectors.pages.Dashboard.Settings.Variables.Edit.General.selectionOptionsCustomAllInput |
||||||
|
); |
||||||
|
|
||||||
|
fireEvent.blur(queryInput); |
||||||
|
fireEvent.blur(allValueInput); |
||||||
|
|
||||||
|
expect(onQueryChange).toHaveBeenCalled(); |
||||||
|
expect(onAllValueChange).toHaveBeenCalled(); |
||||||
|
expect(onMultiChange).not.toHaveBeenCalled(); |
||||||
|
expect(onIncludeAllChange).not.toHaveBeenCalled(); |
||||||
|
}); |
||||||
|
}); |
@ -0,0 +1,57 @@ |
|||||||
|
import React, { FormEvent } from 'react'; |
||||||
|
|
||||||
|
import { selectors } from '@grafana/e2e-selectors'; |
||||||
|
|
||||||
|
import { VariableLegend } from '../components/VariableLegend'; |
||||||
|
import { VariableTextAreaField } from '../components/VariableTextAreaField'; |
||||||
|
|
||||||
|
import { SelectionOptionsForm } from './SelectionOptionsForm'; |
||||||
|
|
||||||
|
interface CustomVariableFormProps { |
||||||
|
query: string; |
||||||
|
multi: boolean; |
||||||
|
allValue?: string | null; |
||||||
|
includeAll: boolean; |
||||||
|
onQueryChange: (event: FormEvent<HTMLTextAreaElement>) => void; |
||||||
|
onMultiChange: (event: FormEvent<HTMLInputElement>) => void; |
||||||
|
onIncludeAllChange: (event: FormEvent<HTMLInputElement>) => void; |
||||||
|
onAllValueChange: (event: FormEvent<HTMLInputElement>) => void; |
||||||
|
onQueryBlur?: (event: FormEvent<HTMLTextAreaElement>) => void; |
||||||
|
onAllValueBlur?: (event: FormEvent<HTMLInputElement>) => void; |
||||||
|
} |
||||||
|
|
||||||
|
export function CustomVariableForm({ |
||||||
|
query, |
||||||
|
multi, |
||||||
|
allValue, |
||||||
|
includeAll, |
||||||
|
onQueryChange, |
||||||
|
onMultiChange, |
||||||
|
onIncludeAllChange, |
||||||
|
onAllValueChange, |
||||||
|
}: CustomVariableFormProps) { |
||||||
|
return ( |
||||||
|
<> |
||||||
|
<VariableLegend>Custom options</VariableLegend> |
||||||
|
|
||||||
|
<VariableTextAreaField |
||||||
|
name="Values separated by comma" |
||||||
|
defaultValue={query} |
||||||
|
placeholder="1, 10, mykey : myvalue, myvalue, escaped\,value" |
||||||
|
onBlur={onQueryChange} |
||||||
|
required |
||||||
|
width={52} |
||||||
|
testId={selectors.pages.Dashboard.Settings.Variables.Edit.CustomVariable.customValueInput} |
||||||
|
/> |
||||||
|
<VariableLegend>Selection options</VariableLegend> |
||||||
|
<SelectionOptionsForm |
||||||
|
multi={multi} |
||||||
|
includeAll={includeAll} |
||||||
|
allValue={allValue} |
||||||
|
onMultiChange={onMultiChange} |
||||||
|
onIncludeAllChange={onIncludeAllChange} |
||||||
|
onAllValueChange={onAllValueChange} |
||||||
|
/> |
||||||
|
</> |
||||||
|
); |
||||||
|
} |
@ -0,0 +1,52 @@ |
|||||||
|
import React, { ChangeEvent, FormEvent } from 'react'; |
||||||
|
|
||||||
|
import { selectors } from '@grafana/e2e-selectors'; |
||||||
|
import { VerticalGroup } from '@grafana/ui'; |
||||||
|
import { VariableCheckboxField } from 'app/features/dashboard-scene/settings/variables/components/VariableCheckboxField'; |
||||||
|
import { VariableTextField } from 'app/features/dashboard-scene/settings/variables/components/VariableTextField'; |
||||||
|
|
||||||
|
interface SelectionOptionsFormProps { |
||||||
|
multi: boolean; |
||||||
|
includeAll: boolean; |
||||||
|
allValue?: string | null; |
||||||
|
onMultiChange: (event: ChangeEvent<HTMLInputElement>) => void; |
||||||
|
onIncludeAllChange: (event: ChangeEvent<HTMLInputElement>) => void; |
||||||
|
onAllValueChange: (event: FormEvent<HTMLInputElement>) => void; |
||||||
|
} |
||||||
|
|
||||||
|
export function SelectionOptionsForm({ |
||||||
|
multi, |
||||||
|
includeAll, |
||||||
|
allValue, |
||||||
|
onMultiChange, |
||||||
|
onIncludeAllChange, |
||||||
|
onAllValueChange, |
||||||
|
}: SelectionOptionsFormProps) { |
||||||
|
return ( |
||||||
|
<VerticalGroup spacing="md" height="inherit"> |
||||||
|
<VariableCheckboxField |
||||||
|
value={multi} |
||||||
|
name="Multi-value" |
||||||
|
description="Enables multiple values to be selected at the same time" |
||||||
|
onChange={onMultiChange} |
||||||
|
testId={selectors.pages.Dashboard.Settings.Variables.Edit.General.selectionOptionsMultiSwitch} |
||||||
|
/> |
||||||
|
<VariableCheckboxField |
||||||
|
value={includeAll} |
||||||
|
name="Include All option" |
||||||
|
description="Enables an option to include all variables" |
||||||
|
onChange={onIncludeAllChange} |
||||||
|
testId={selectors.pages.Dashboard.Settings.Variables.Edit.General.selectionOptionsIncludeAllSwitch} |
||||||
|
/> |
||||||
|
{includeAll && ( |
||||||
|
<VariableTextField |
||||||
|
defaultValue={allValue ?? ''} |
||||||
|
onBlur={onAllValueChange} |
||||||
|
name="Custom all value" |
||||||
|
placeholder="blank = auto" |
||||||
|
testId={selectors.pages.Dashboard.Settings.Variables.Edit.General.selectionOptionsCustomAllInput} |
||||||
|
/> |
||||||
|
)} |
||||||
|
</VerticalGroup> |
||||||
|
); |
||||||
|
} |
@ -0,0 +1,115 @@ |
|||||||
|
import { render, fireEvent } from '@testing-library/react'; |
||||||
|
import React from 'react'; |
||||||
|
|
||||||
|
import { selectors } from '@grafana/e2e-selectors'; |
||||||
|
import { CustomVariable } from '@grafana/scenes'; |
||||||
|
|
||||||
|
import { CustomVariableEditor } from './CustomVariableEditor'; |
||||||
|
|
||||||
|
describe('CustomVariableEditor', () => { |
||||||
|
it('should render the CustomVariableForm with correct initial values', () => { |
||||||
|
const variable = new CustomVariable({ |
||||||
|
name: 'customVar', |
||||||
|
query: 'test, test2', |
||||||
|
value: 'test', |
||||||
|
isMulti: true, |
||||||
|
includeAll: true, |
||||||
|
allValue: 'test', |
||||||
|
}); |
||||||
|
const onRunQuery = jest.fn(); |
||||||
|
|
||||||
|
const { getByTestId } = render(<CustomVariableEditor variable={variable} onRunQuery={onRunQuery} />); |
||||||
|
|
||||||
|
const queryInput = getByTestId( |
||||||
|
selectors.pages.Dashboard.Settings.Variables.Edit.CustomVariable.customValueInput |
||||||
|
) as HTMLInputElement; |
||||||
|
const allValueInput = getByTestId( |
||||||
|
selectors.pages.Dashboard.Settings.Variables.Edit.General.selectionOptionsCustomAllInput |
||||||
|
) as HTMLInputElement; |
||||||
|
const multiCheckbox = getByTestId( |
||||||
|
selectors.pages.Dashboard.Settings.Variables.Edit.General.selectionOptionsMultiSwitch |
||||||
|
) as HTMLInputElement; |
||||||
|
const includeAllCheckbox = getByTestId( |
||||||
|
selectors.pages.Dashboard.Settings.Variables.Edit.General.selectionOptionsIncludeAllSwitch |
||||||
|
) as HTMLInputElement; |
||||||
|
|
||||||
|
expect(queryInput.value).toBe('test, test2'); |
||||||
|
expect(allValueInput.value).toBe('test'); |
||||||
|
expect(multiCheckbox.checked).toBe(true); |
||||||
|
expect(includeAllCheckbox.checked).toBe(true); |
||||||
|
}); |
||||||
|
|
||||||
|
it('should update the variable state when input values change', () => { |
||||||
|
const variable = new CustomVariable({ |
||||||
|
name: 'customVar', |
||||||
|
query: 'test, test2', |
||||||
|
value: 'test', |
||||||
|
}); |
||||||
|
const onRunQuery = jest.fn(); |
||||||
|
|
||||||
|
const { getByTestId } = render(<CustomVariableEditor variable={variable} onRunQuery={onRunQuery} />); |
||||||
|
|
||||||
|
const multiCheckbox = getByTestId( |
||||||
|
selectors.pages.Dashboard.Settings.Variables.Edit.General.selectionOptionsMultiSwitch |
||||||
|
); |
||||||
|
const includeAllCheckbox = getByTestId( |
||||||
|
selectors.pages.Dashboard.Settings.Variables.Edit.General.selectionOptionsIncludeAllSwitch |
||||||
|
); |
||||||
|
|
||||||
|
// It include-all-custom input appears after include-all checkbox is checked only
|
||||||
|
expect(() => |
||||||
|
getByTestId(selectors.pages.Dashboard.Settings.Variables.Edit.General.selectionOptionsCustomAllInput) |
||||||
|
).toThrow('Unable to find an element'); |
||||||
|
|
||||||
|
fireEvent.click(multiCheckbox); |
||||||
|
|
||||||
|
fireEvent.click(includeAllCheckbox); |
||||||
|
const allValueInput = getByTestId( |
||||||
|
selectors.pages.Dashboard.Settings.Variables.Edit.General.selectionOptionsCustomAllInput |
||||||
|
); |
||||||
|
|
||||||
|
expect(variable.state.isMulti).toBe(true); |
||||||
|
expect(variable.state.includeAll).toBe(true); |
||||||
|
expect(allValueInput).toBeInTheDocument(); |
||||||
|
}); |
||||||
|
|
||||||
|
it('should call update query and re-run query when input loses focus', async () => { |
||||||
|
const variable = new CustomVariable({ |
||||||
|
name: 'customVar', |
||||||
|
query: 'test, test2', |
||||||
|
value: 'test', |
||||||
|
}); |
||||||
|
const onRunQuery = jest.fn(); |
||||||
|
|
||||||
|
const { getByTestId } = render(<CustomVariableEditor variable={variable} onRunQuery={onRunQuery} />); |
||||||
|
|
||||||
|
const queryInput = getByTestId(selectors.pages.Dashboard.Settings.Variables.Edit.CustomVariable.customValueInput); |
||||||
|
fireEvent.change(queryInput, { target: { value: 'test3, test4' } }); |
||||||
|
fireEvent.blur(queryInput); |
||||||
|
|
||||||
|
expect(onRunQuery).toHaveBeenCalled(); |
||||||
|
expect(variable.state.query).toBe('test3, test4'); |
||||||
|
}); |
||||||
|
|
||||||
|
it('should update the variable state when all-custom-value input loses focus', () => { |
||||||
|
const variable = new CustomVariable({ |
||||||
|
name: 'customVar', |
||||||
|
query: 'test, test2', |
||||||
|
value: 'test', |
||||||
|
isMulti: true, |
||||||
|
includeAll: true, |
||||||
|
}); |
||||||
|
const onRunQuery = jest.fn(); |
||||||
|
|
||||||
|
const { getByTestId } = render(<CustomVariableEditor variable={variable} onRunQuery={onRunQuery} />); |
||||||
|
|
||||||
|
const allValueInput = getByTestId( |
||||||
|
selectors.pages.Dashboard.Settings.Variables.Edit.General.selectionOptionsCustomAllInput |
||||||
|
) as HTMLInputElement; |
||||||
|
|
||||||
|
fireEvent.change(allValueInput, { target: { value: 'new custom all' } }); |
||||||
|
fireEvent.blur(allValueInput); |
||||||
|
|
||||||
|
expect(variable.state.allValue).toBe('new custom all'); |
||||||
|
}); |
||||||
|
}); |
@ -1,11 +1,41 @@ |
|||||||
import React from 'react'; |
import React, { FormEvent } from 'react'; |
||||||
|
|
||||||
import { CustomVariable } from '@grafana/scenes'; |
import { CustomVariable } from '@grafana/scenes'; |
||||||
|
|
||||||
|
import { CustomVariableForm } from '../components/CustomVariableForm'; |
||||||
|
|
||||||
interface CustomVariableEditorProps { |
interface CustomVariableEditorProps { |
||||||
variable: CustomVariable; |
variable: CustomVariable; |
||||||
|
onRunQuery: () => void; |
||||||
} |
} |
||||||
|
|
||||||
export function CustomVariableEditor(props: CustomVariableEditorProps) { |
export function CustomVariableEditor({ variable, onRunQuery }: CustomVariableEditorProps) { |
||||||
return <div>CustomVariableEditor</div>; |
const { query, isMulti, allValue, includeAll } = variable.useState(); |
||||||
|
|
||||||
|
const onMultiChange = (event: FormEvent<HTMLInputElement>) => { |
||||||
|
variable.setState({ isMulti: event.currentTarget.checked }); |
||||||
|
}; |
||||||
|
const onIncludeAllChange = (event: FormEvent<HTMLInputElement>) => { |
||||||
|
variable.setState({ includeAll: event.currentTarget.checked }); |
||||||
|
}; |
||||||
|
const onQueryChange = (event: FormEvent<HTMLTextAreaElement>) => { |
||||||
|
variable.setState({ query: event.currentTarget.value }); |
||||||
|
onRunQuery(); |
||||||
|
}; |
||||||
|
const onAllValueChange = (event: FormEvent<HTMLInputElement>) => { |
||||||
|
variable.setState({ allValue: event.currentTarget.value }); |
||||||
|
}; |
||||||
|
|
||||||
|
return ( |
||||||
|
<CustomVariableForm |
||||||
|
query={query ?? ''} |
||||||
|
multi={!!isMulti} |
||||||
|
allValue={allValue ?? ''} |
||||||
|
includeAll={!!includeAll} |
||||||
|
onMultiChange={onMultiChange} |
||||||
|
onIncludeAllChange={onIncludeAllChange} |
||||||
|
onQueryChange={onQueryChange} |
||||||
|
onAllValueChange={onAllValueChange} |
||||||
|
/> |
||||||
|
); |
||||||
} |
} |
||||||
|
Loading…
Reference in new issue