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 { CustomVariableForm } from '../components/CustomVariableForm'; |
||||
|
||||
interface CustomVariableEditorProps { |
||||
variable: CustomVariable; |
||||
onRunQuery: () => void; |
||||
} |
||||
|
||||
export function CustomVariableEditor(props: CustomVariableEditorProps) { |
||||
return <div>CustomVariableEditor</div>; |
||||
export function CustomVariableEditor({ variable, onRunQuery }: CustomVariableEditorProps) { |
||||
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