diff --git a/public/app/features/explore/AdHocFilterField.test.tsx b/public/app/features/explore/AdHocFilterField.test.tsx new file mode 100644 index 00000000000..dcd2e26ce74 --- /dev/null +++ b/public/app/features/explore/AdHocFilterField.test.tsx @@ -0,0 +1,64 @@ +import React from 'react'; +import { shallow } from 'enzyme'; + +import { AdHocFilterField, DEFAULT_REMOVE_FILTER_VALUE } from './AdHocFilterField'; +import { AdHocFilter } from './AdHocFilter'; +import { MockDataSourceApi } from '../../../test/mocks/datasource_srv'; + +describe('', () => { + let mockDataSourceApi; + + beforeEach(() => { + mockDataSourceApi = new MockDataSourceApi(); + }); + + it('should initially have no filters', () => { + const mockOnPairsChanged = jest.fn(); + const wrapper = shallow(); + expect(wrapper.state('pairs')).toEqual([]); + expect(wrapper.find(AdHocFilter).exists()).toBeFalsy(); + }); + + it('should add when onAddFilter is invoked', () => { + const mockOnPairsChanged = jest.fn(); + const wrapper = shallow(); + expect(wrapper.state('pairs')).toEqual([]); + wrapper + .find('button') + .first() + .simulate('click'); + expect(wrapper.find(AdHocFilter).exists()).toBeTruthy(); + }); + + it(`should remove the relavant filter when the '${DEFAULT_REMOVE_FILTER_VALUE}' key is selected`, () => { + const mockOnPairsChanged = jest.fn(); + const wrapper = shallow(); + expect(wrapper.state('pairs')).toEqual([]); + + wrapper + .find('button') + .first() + .simulate('click'); + expect(wrapper.find(AdHocFilter).exists()).toBeTruthy(); + + wrapper.find(AdHocFilter).prop('onKeyChanged')(DEFAULT_REMOVE_FILTER_VALUE); + expect(wrapper.find(AdHocFilter).exists()).toBeFalsy(); + }); + + it('it should call onPairsChanged when a filter is removed', async () => { + const mockOnPairsChanged = jest.fn(); + const wrapper = shallow(); + expect(wrapper.state('pairs')).toEqual([]); + + wrapper + .find('button') + .first() + .simulate('click'); + expect(wrapper.find(AdHocFilter).exists()).toBeTruthy(); + + wrapper.find(AdHocFilter).prop('onKeyChanged')(DEFAULT_REMOVE_FILTER_VALUE); + expect(wrapper.find(AdHocFilter).exists()).toBeFalsy(); + + expect(mockOnPairsChanged.mock.calls.length).toBe(1); + }); +}); diff --git a/public/app/features/explore/AdHocFilterField.tsx b/public/app/features/explore/AdHocFilterField.tsx index e3584027af4..152e9f831c0 100644 --- a/public/app/features/explore/AdHocFilterField.tsx +++ b/public/app/features/explore/AdHocFilterField.tsx @@ -2,6 +2,8 @@ import React from 'react'; import { DataSourceApi, DataQuery, DataSourceJsonData } from '@grafana/ui'; import { AdHocFilter } from './AdHocFilter'; +export const DEFAULT_REMOVE_FILTER_VALUE = '-- remove filter --'; + export interface KeyValuePair { keys: string[]; key: string; @@ -25,21 +27,18 @@ export class AdHocFilterField< > extends React.PureComponent, State> { state: State = { pairs: [] }; - async componentDidMount() { - const tagKeys = this.props.datasource.getTagKeys ? await this.props.datasource.getTagKeys({}) : []; - const keys = tagKeys.map(tagKey => tagKey.text); - const pairs = [{ key: null, operator: null, value: null, keys, values: [] }]; - this.setState({ pairs }); - } - onKeyChanged = (index: number) => async (key: string) => { - const { datasource, onPairsChanged } = this.props; - const tagValues = datasource.getTagValues ? await datasource.getTagValues({ key }) : []; - const values = tagValues.map(tagValue => tagValue.text); - const newPairs = this.updatePairAt(index, { key, values }); + if (key !== DEFAULT_REMOVE_FILTER_VALUE) { + const { datasource, onPairsChanged } = this.props; + const tagValues = datasource.getTagValues ? await datasource.getTagValues({ key }) : []; + const values = tagValues.map(tagValue => tagValue.text); + const newPairs = this.updatePairAt(index, { key, values }); - this.setState({ pairs: newPairs }); - onPairsChanged(newPairs); + this.setState({ pairs: newPairs }); + onPairsChanged(newPairs); + } else { + this.onRemoveFilter(index); + } }; onValueChanged = (index: number) => (value: string) => { @@ -75,6 +74,7 @@ export class AdHocFilterField< }, []); this.setState({ pairs: newPairs }); + this.props.onPairsChanged(newPairs); }; private updatePairAt = (index: number, pair: Partial) => { @@ -104,12 +104,17 @@ export class AdHocFilterField< const { pairs } = this.state; return ( <> + {pairs.length < 1 && ( + + )} {pairs.map((pair, index) => { const adHocKey = `adhoc-filter-${index}-${pair.key}-${pair.value}`; return (