Add "use time filter" option to input controls (#15852) (#16071)

* add useTimeFilter parameter to Controls visualization

* fix broken jest test

* add functional tests for useTimeFilter

* remove wrong comment

* use _.clone and _.isEqual for time comparision

* do not track time changes in vis_controller - use status.time instead
This commit is contained in:
Nathan Reese 2018-01-16 13:55:03 -07:00 committed by GitHub
parent d3bc3af39b
commit dc9e8def07
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 92 additions and 15 deletions

View file

@ -24,6 +24,25 @@ exports[`renders OptionsTab 1`] = `
</KuiFieldGroupSection>
</KuiFieldGroup>
</div>
<div
className="vis-editor-agg-header"
>
<KuiFieldGroup
isAlignedTop={false}
>
<KuiFieldGroupSection
isWide={false}
>
<KuiCheckBoxLabel
data-test-subj="inputControlEditorUseTimeFilterCheckbox"
isChecked={false}
isDisabled={false}
onChange={[Function]}
text="Use time filter"
/>
</KuiFieldGroupSection>
</KuiFieldGroup>
</div>
</div>
</div>
`;

View file

@ -7,22 +7,21 @@ import {
KuiCheckBoxLabel } from 'ui_framework/components';
export class OptionsTab extends Component {
constructor(props) {
super(props);
this.handleUpdateFiltersChange = this.handleUpdateFiltersChange.bind(this);
}
setVisParam(paramName, paramValue) {
setVisParam = (paramName, paramValue) => {
const params = _.cloneDeep(this.props.scope.vis.params);
params[paramName] = paramValue;
this.props.stageEditorParams(params);
}
handleUpdateFiltersChange(evt) {
handleUpdateFiltersChange = (evt) => {
this.setVisParam('updateFiltersOnChange', evt.target.checked);
}
handleUseTimeFilter = (evt) => {
this.setVisParam('useTimeFilter', evt.target.checked);
}
render() {
return (
<div>
@ -40,6 +39,19 @@ export class OptionsTab extends Component {
</KuiFieldGroupSection>
</KuiFieldGroup>
</div>
<div className="vis-editor-agg-header">
<KuiFieldGroup>
<KuiFieldGroupSection>
<KuiCheckBoxLabel
text="Use time filter"
isChecked={this.props.scope.vis.params.useTimeFilter}
onChange={this.handleUseTimeFilter}
data-test-subj="inputControlEditorUseTimeFilterCheckbox"
/>
</KuiFieldGroupSection>
</KuiFieldGroup>
</div>
</div>
</div>

View file

@ -9,7 +9,8 @@ import {
const scopeMock = {
vis: {
params: {
updateFiltersOnChange: false
updateFiltersOnChange: false,
useTimeFilter: false
}
}
};
@ -40,3 +41,17 @@ test('updateFiltersOnChange', () => {
sinon.assert.calledOnce(stageEditorParams);
sinon.assert.calledWith(stageEditorParams, sinon.match(expectedParams));
});
test('useTimeFilter', () => {
const component = mount(<OptionsTab
scope={scopeMock}
stageEditorParams={stageEditorParams}
/>);
const checkbox = component.find('[data-test-subj="inputControlEditorUseTimeFilterCheckbox"] input[type="checkbox"]');
checkbox.simulate('change', { target: { checked: true } });
const expectedParams = {
useTimeFilter: true
};
sinon.assert.calledOnce(stageEditorParams);
sinon.assert.calledWith(stageEditorParams, sinon.match(expectedParams));
});

View file

@ -45,14 +45,16 @@ class ListControl extends Control {
}
}
export async function listControlFactory(controlParams, kbnApi) {
export async function listControlFactory(controlParams, kbnApi, useTimeFilter) {
const indexPattern = await kbnApi.indexPatterns.get(controlParams.indexPattern);
// TODO replace SearchSource with call to suggestions API
const searchSource = new kbnApi.SearchSource({
timeout: '1s',
terminate_after: 100000
});
searchSource.inherits(false); //Do not filter by time so can not inherit from rootSearchSource
if (!useTimeFilter) {
searchSource.inherits(false); //Do not filter by time so can not inherit from rootSearchSource
}
searchSource.size(0);
searchSource.index(indexPattern);
searchSource.aggs(termsAgg(

View file

@ -33,10 +33,12 @@ class RangeControl extends Control {
}
}
export async function rangeControlFactory(controlParams, kbnApi) {
export async function rangeControlFactory(controlParams, kbnApi, useTimeFilter) {
const indexPattern = await kbnApi.indexPatterns.get(controlParams.indexPattern);
const searchSource = new kbnApi.SearchSource();
searchSource.inherits(false); //Do not filter by time so can not inherit from rootSearchSource
if (!useTimeFilter) {
searchSource.inherits(false); //Do not filter by time so can not inherit from rootSearchSource
}
searchSource.size(0);
searchSource.index(indexPattern);
searchSource.aggs(minMaxAgg(indexPattern.fields.byName[controlParams.fieldName]));

View file

@ -25,7 +25,8 @@ function InputControlVisProvider(Private) {
visConfig: {
defaults: {
controls: [],
updateFiltersOnChange: false
updateFiltersOnChange: false,
useTimeFilter: false,
},
},
editor: 'default',

View file

@ -14,7 +14,7 @@ class VisController {
}
async render(visData, status) {
if (status.params) {
if (status.params || (this.vis.params.useTimeFilter && status.time)) {
this.controls = [];
this.controls = await this.initControls();
this.drawVis();
@ -51,7 +51,7 @@ class VisController {
})
.map((controlParams) => {
const factory = controlFactory(controlParams);
return factory(controlParams, this.vis.API);
return factory(controlParams, this.vis.API, this.vis.params.useTimeFilter);
})
);
}

View file

@ -4,6 +4,7 @@ export default function ({ getService, getPageObjects }) {
const filterBar = getService('filterBar');
const PageObjects = getPageObjects(['common', 'visualize', 'header']);
const testSubjects = getService('testSubjects');
const find = getService('find');
const FIELD_NAME = 'machine.os.raw';
@ -11,6 +12,8 @@ export default function ({ getService, getPageObjects }) {
before(async () => {
await PageObjects.common.navigateToUrl('visualize', 'new');
await PageObjects.visualize.clickInputControlVis();
// set time range to time with no documents - input controls do not use time filter be default
await PageObjects.header.setAbsoluteRange('2017-01-01', '2017-01-02');
await PageObjects.visualize.clickVisEditorTab('controls');
await PageObjects.visualize.addInputControl();
await PageObjects.visualize.setReactSelect('.index-pattern-react-select', 'logstash');
@ -137,6 +140,29 @@ export default function ({ getService, getPageObjects }) {
expect(hasFilter).to.equal(true);
});
});
describe('useTimeFilter', () => {
it('should use global time filter when getting terms', async () => {
await PageObjects.visualize.clickVisEditorTab('options');
await PageObjects.visualize.checkCheckbox('inputControlEditorUseTimeFilterCheckbox');
await PageObjects.visualize.clickGo();
await PageObjects.header.waitUntilLoadingHasFinished();
// Expect control to be disabled because no terms could be gathered with time filter applied
const input = await find.byCssSelector('[data-test-subj="inputControl0"] input');
const isDisabled = await input.getProperty('disabled');
expect(isDisabled).to.equal(true);
});
it('should re-create control when global time filter is updated', async () => {
await PageObjects.header.setAbsoluteRange('2015-01-01', '2016-01-01');
await PageObjects.header.waitUntilLoadingHasFinished();
// Expect control to have values for selected time filter
const menu = await PageObjects.visualize.getReactSelectOptions('inputControl0');
expect(menu.trim().split('\n').join()).to.equal('win 8,win xp,win 7,osx');
});
});
});
});
}