mirror of https://github.com/grafana/grafana
Dashboard: Migration - EditVariable Settings: Implement DataSource Variable (#80885)
* Extract DatasourceVariableForm logic and use it in core grafana * Implement DataSourceVariable editor in scenes * Refactor VariableSelect and add unit test for DataSourceVariableEditor * Refactor old unit test to use userEvent and mock getDataSourceSrvpull/81256/head
parent
0880a239f8
commit
2774e0d023
@ -0,0 +1,79 @@ |
||||
import React, { FormEvent } from 'react'; |
||||
|
||||
import { SelectableValue } from '@grafana/data'; |
||||
import { selectors } from '@grafana/e2e-selectors'; |
||||
|
||||
import { SelectionOptionsForm } from './SelectionOptionsForm'; |
||||
import { VariableLegend } from './VariableLegend'; |
||||
import { VariableSelectField } from './VariableSelectField'; |
||||
import { VariableTextField } from './VariableTextField'; |
||||
|
||||
interface DataSourceVariableFormProps { |
||||
query: string; |
||||
regex: string; |
||||
multi: boolean; |
||||
allValue?: string | null; |
||||
includeAll: boolean; |
||||
onChange: (option: SelectableValue) => void; |
||||
optionTypes: Array<{ value: string; label: string }>; |
||||
onRegExBlur: (event: FormEvent<HTMLInputElement>) => 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 DataSourceVariableForm({ |
||||
query, |
||||
regex, |
||||
optionTypes, |
||||
onChange, |
||||
onRegExBlur, |
||||
multi, |
||||
includeAll, |
||||
allValue, |
||||
onMultiChange, |
||||
onIncludeAllChange, |
||||
onAllValueChange, |
||||
}: DataSourceVariableFormProps) { |
||||
const typeValue = optionTypes.find((o) => o.value === query) ?? optionTypes[0]; |
||||
|
||||
return ( |
||||
<> |
||||
<VariableLegend>Data source options</VariableLegend> |
||||
<VariableSelectField |
||||
name="Type" |
||||
value={typeValue} |
||||
options={optionTypes} |
||||
onChange={onChange} |
||||
testId={selectors.pages.Dashboard.Settings.Variables.Edit.DatasourceVariable.datasourceSelect} |
||||
/> |
||||
|
||||
<VariableTextField |
||||
defaultValue={regex} |
||||
name="Instance name filter" |
||||
placeholder="/.*-(.*)-.*/" |
||||
onBlur={onRegExBlur} |
||||
description={ |
||||
<div> |
||||
Regex filter for which data source instances to choose from in the variable value list. Leave empty for all. |
||||
<br /> |
||||
<br /> |
||||
Example: <code>/^prod/</code> |
||||
</div> |
||||
} |
||||
/> |
||||
|
||||
<VariableLegend>Selection options</VariableLegend> |
||||
<SelectionOptionsForm |
||||
multi={multi} |
||||
includeAll={includeAll} |
||||
allValue={allValue} |
||||
onMultiChange={onMultiChange} |
||||
onIncludeAllChange={onIncludeAllChange} |
||||
onAllValueChange={onAllValueChange} |
||||
/> |
||||
</> |
||||
); |
||||
} |
@ -0,0 +1,157 @@ |
||||
// add unit test for the DataSourceVariableEditor component
|
||||
|
||||
import { render } from '@testing-library/react'; |
||||
import userEvent from '@testing-library/user-event'; |
||||
import React from 'react'; |
||||
|
||||
import { selectors } from '@grafana/e2e-selectors'; |
||||
import { DataSourceVariable } from '@grafana/scenes'; |
||||
|
||||
import { DataSourceVariableEditor } from './DataSourceVariableEditor'; |
||||
|
||||
//mock getDataSorceSrv.getList() to return a list of datasources
|
||||
jest.mock('@grafana/runtime', () => ({ |
||||
...jest.requireActual('@grafana/runtime'), |
||||
getDataSourceSrv: () => ({ |
||||
getList: () => { |
||||
return [ |
||||
{ |
||||
name: 'DataSourceInstance1', |
||||
uid: 'ds1', |
||||
meta: { |
||||
name: 'ds1', |
||||
id: 'dsTestDataSource', |
||||
}, |
||||
}, |
||||
{ |
||||
name: 'DataSourceInstance2', |
||||
uid: 'ds2', |
||||
meta: { |
||||
name: 'ds1', |
||||
id: 'dsTestDataSource', |
||||
}, |
||||
}, |
||||
{ |
||||
name: 'ABCDataSourceInstance', |
||||
uid: 'ds3', |
||||
meta: { |
||||
name: 'abDS', |
||||
id: 'ABCDS', |
||||
}, |
||||
}, |
||||
]; |
||||
}, |
||||
}), |
||||
})); |
||||
|
||||
describe('DataSourceVariableEditor', () => { |
||||
it('shoud render correctly with multi and all not checked', () => { |
||||
const variable = new DataSourceVariable({ |
||||
name: 'dsVariable', |
||||
type: 'datasource', |
||||
label: 'Datasource', |
||||
pluginId: 'dsTestDataSource', |
||||
}); |
||||
const onRunQuery = jest.fn(); |
||||
|
||||
const { getByTestId } = render(<DataSourceVariableEditor 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 |
||||
); |
||||
|
||||
const typeSelect = getByTestId( |
||||
selectors.pages.Dashboard.Settings.Variables.Edit.DatasourceVariable.datasourceSelect |
||||
); |
||||
expect(typeSelect).toBeInTheDocument(); |
||||
expect(typeSelect.textContent).toBe('ds1'); |
||||
expect(multiCheckbox).toBeInTheDocument(); |
||||
expect(multiCheckbox).not.toBeChecked(); |
||||
expect(includeAllCheckbox).toBeInTheDocument(); |
||||
expect(includeAllCheckbox).not.toBeChecked(); |
||||
}); |
||||
|
||||
it('shoud render correctly with multi and includeAll checked', () => { |
||||
const variable = new DataSourceVariable({ |
||||
name: 'dsVariable', |
||||
type: 'datasource', |
||||
label: 'Datasource', |
||||
pluginId: 'dsTestDataSource', |
||||
isMulti: true, |
||||
includeAll: true, |
||||
}); |
||||
const onRunQuery = jest.fn(); |
||||
|
||||
const { getByTestId } = render(<DataSourceVariableEditor 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 |
||||
); |
||||
|
||||
const typeSelect = getByTestId( |
||||
selectors.pages.Dashboard.Settings.Variables.Edit.DatasourceVariable.datasourceSelect |
||||
); |
||||
expect(typeSelect).toBeInTheDocument(); |
||||
expect(typeSelect.textContent).toBe('ds1'); |
||||
expect(multiCheckbox).toBeInTheDocument(); |
||||
expect(multiCheckbox).toBeChecked(); |
||||
expect(includeAllCheckbox).toBeInTheDocument(); |
||||
expect(includeAllCheckbox).toBeChecked(); |
||||
}); |
||||
|
||||
it('Should change type option when users select a different datasource type', async () => { |
||||
const variable = new DataSourceVariable({ |
||||
name: 'dsVariable', |
||||
type: 'datasource', |
||||
label: 'Datasource', |
||||
pluginId: 'dsTestDataSource', |
||||
isMulti: false, |
||||
includeAll: false, |
||||
}); |
||||
const onRunQuery = jest.fn(); |
||||
|
||||
const { getByTestId, user } = setup(<DataSourceVariableEditor variable={variable} onRunQuery={onRunQuery} />); |
||||
|
||||
const typeSelect = getByTestId( |
||||
selectors.pages.Dashboard.Settings.Variables.Edit.DatasourceVariable.datasourceSelect |
||||
); |
||||
// when user change type datasource
|
||||
await user.click(typeSelect); |
||||
await user.type(typeSelect, 'abDS'); |
||||
await user.keyboard('{enter}'); |
||||
expect(typeSelect).toBeInTheDocument(); |
||||
expect(typeSelect.textContent).toBe('abDS'); |
||||
expect(onRunQuery).toHaveBeenCalledTimes(1); |
||||
|
||||
// when user change checkbox multi
|
||||
|
||||
const multiCheckbox = getByTestId( |
||||
selectors.pages.Dashboard.Settings.Variables.Edit.General.selectionOptionsMultiSwitch |
||||
); |
||||
const includeAllCheckbox = getByTestId( |
||||
selectors.pages.Dashboard.Settings.Variables.Edit.General.selectionOptionsIncludeAllSwitch |
||||
); |
||||
|
||||
await user.click(multiCheckbox); |
||||
expect(multiCheckbox).toBeChecked(); |
||||
|
||||
// when user include all there is a new call to onRunQuery
|
||||
await user.click(includeAllCheckbox); |
||||
expect(includeAllCheckbox).toBeChecked(); |
||||
expect(onRunQuery).toHaveBeenCalledTimes(1); |
||||
}); |
||||
}); |
||||
|
||||
// based on styleguide recomendation
|
||||
function setup(jsx: JSX.Element) { |
||||
return { |
||||
user: userEvent.setup(), |
||||
...render(jsx), |
||||
}; |
||||
} |
@ -1,12 +1,62 @@ |
||||
import React from 'react'; |
||||
import React, { FormEvent } from 'react'; |
||||
|
||||
import { SelectableValue } from '@grafana/data'; |
||||
import { DataSourceVariable } from '@grafana/scenes'; |
||||
|
||||
import { DataSourceVariableForm } from '../components/DataSourceVariableForm'; |
||||
import { getOptionDataSourceTypes } from '../utils'; |
||||
|
||||
interface DataSourceVariableEditorProps { |
||||
variable: DataSourceVariable; |
||||
onChange: (variable: DataSourceVariable) => void; |
||||
onRunQuery: () => void; |
||||
} |
||||
|
||||
export function DataSourceVariableEditor(props: DataSourceVariableEditorProps) { |
||||
return <div>DataSourceVariableEditor</div>; |
||||
export function DataSourceVariableEditor({ variable, onRunQuery }: DataSourceVariableEditorProps) { |
||||
const { pluginId, regex, isMulti, allValue, includeAll } = variable.useState(); |
||||
|
||||
const optionTypes = getOptionDataSourceTypes(); |
||||
|
||||
const onChangeType = (option: SelectableValue) => { |
||||
variable.setState({ |
||||
pluginId: option.value, |
||||
}); |
||||
onRunQuery(); |
||||
}; |
||||
|
||||
const onRegExChange = (event: FormEvent<HTMLInputElement>) => { |
||||
variable.setState({ |
||||
regex: event.currentTarget.value, |
||||
}); |
||||
onRunQuery(); |
||||
}; |
||||
|
||||
const onMultiChange = (event: FormEvent<HTMLInputElement>) => { |
||||
variable.setState({ |
||||
isMulti: event.currentTarget.checked, |
||||
}); |
||||
}; |
||||
|
||||
const onIncludeAllChange = (event: FormEvent<HTMLInputElement>) => { |
||||
variable.setState({ includeAll: event.currentTarget.checked }); |
||||
}; |
||||
|
||||
const onAllValueChange = (event: FormEvent<HTMLInputElement>) => { |
||||
variable.setState({ allValue: event.currentTarget.value }); |
||||
}; |
||||
|
||||
return ( |
||||
<DataSourceVariableForm |
||||
query={pluginId} |
||||
regex={regex} |
||||
multi={isMulti || false} |
||||
allValue={allValue} |
||||
includeAll={includeAll || false} |
||||
optionTypes={optionTypes} |
||||
onChange={onChangeType} |
||||
onRegExBlur={onRegExChange} |
||||
onMultiChange={onMultiChange} |
||||
onIncludeAllChange={onIncludeAllChange} |
||||
onAllValueChange={onAllValueChange} |
||||
/> |
||||
); |
||||
} |
||||
|
Loading…
Reference in new issue