[TSVB] Fix panel config updates on history changes (#75896)

* Apply history changes to panel config

* Add functional tests

* Update jest snapshot

* Add waiters for stabilizing vis chart

* Fix comments

* Remove unused method isValidKueryQuery

* Add a waiter for component render

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
This commit is contained in:
Daniil Suleiman 2020-09-01 13:29:35 +03:00 committed by GitHub
parent d802bf03f7
commit b8c7945b12
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 153 additions and 28 deletions

View file

@ -67,7 +67,9 @@ export function PanelConfig(props) {
return (
<FormValidationContext.Provider value={updateControlValidity}>
<VisDataContext.Provider value={visData}>
<Component {...props} />
<div data-test-subj={`tvbPanelConfig__${model.type}`}>
<Component {...props} />
</div>
</VisDataContext.Provider>
</FormValidationContext.Provider>
);

View file

@ -330,7 +330,7 @@ class GaugePanelConfigUi extends Component {
);
}
return (
<div>
<>
<EuiTabs size="s">
<EuiTab isSelected={selectedTab === 'data'} onClick={() => this.switchTab('data')}>
<FormattedMessage
@ -346,7 +346,7 @@ class GaugePanelConfigUi extends Component {
</EuiTab>
</EuiTabs>
{view}
</div>
</>
);
}
}

View file

@ -294,7 +294,7 @@ class MarkdownPanelConfigUi extends Component {
);
}
return (
<div>
<>
<EuiTabs size="s">
<EuiTab
isSelected={selectedTab === 'markdown'}
@ -325,7 +325,7 @@ class MarkdownPanelConfigUi extends Component {
</EuiTab>
</EuiTabs>
{view}
</div>
</>
);
}
}

View file

@ -167,7 +167,7 @@ export class MetricPanelConfig extends Component {
);
}
return (
<div>
<>
<EuiTabs size="s">
<EuiTab isSelected={selectedTab === 'data'} onClick={() => this.switchTab('data')}>
<FormattedMessage
@ -187,7 +187,7 @@ export class MetricPanelConfig extends Component {
</EuiTab>
</EuiTabs>
{view}
</div>
</>
);
}
}

View file

@ -269,7 +269,7 @@ export class TablePanelConfig extends Component {
);
}
return (
<div>
<>
<EuiTabs size="s">
<EuiTab isSelected={selectedTab === 'data'} onClick={() => this.switchTab('data')}>
<FormattedMessage
@ -285,7 +285,7 @@ export class TablePanelConfig extends Component {
</EuiTab>
</EuiTabs>
{view}
</div>
</>
);
}
}

View file

@ -44,6 +44,7 @@ import {
import { injectI18n, FormattedMessage } from '@kbn/i18n/react';
import { getDefaultQueryLanguage } from '../lib/get_default_query_language';
import { QueryBarWrapper } from '../query_bar_wrapper';
class TimeseriesPanelConfigUi extends Component {
constructor(props) {
super(props);
@ -401,7 +402,7 @@ class TimeseriesPanelConfigUi extends Component {
);
}
return (
<div>
<>
<EuiTabs size="s">
<EuiTab isSelected={selectedTab === 'data'} onClick={() => this.switchTab('data')}>
<FormattedMessage
@ -430,7 +431,7 @@ class TimeseriesPanelConfigUi extends Component {
</EuiTab>
</EuiTabs>
{view}
</div>
</>
);
}
}

View file

@ -227,7 +227,7 @@ export class TopNPanelConfig extends Component {
);
}
return (
<div>
<>
<EuiTabs size="s">
<EuiTab isSelected={selectedTab === 'data'} onClick={() => this.switchTab('data')}>
<FormattedMessage
@ -243,7 +243,7 @@ export class TopNPanelConfig extends Component {
</EuiTab>
</EuiTabs>
{view}
</div>
</>
);
}
}

View file

@ -44,6 +44,7 @@ exports[`src/legacy/core_plugins/metrics/public/components/splits/terms.test.js
labelType="label"
>
<InjectIntl(FieldSelectUi)
data-test-subj="groupByField"
fields={
Object {
"kibana_sample_data_flights": Array [

View file

@ -132,6 +132,7 @@ export const SplitByTermsUI = ({
}
>
<FieldSelect
data-test-subj="groupByField"
indexPattern={indexPattern}
onChange={handleSelectChange('terms_field')}
value={model.terms_field}

View file

@ -29,7 +29,6 @@ import { PanelConfig } from './panel_config';
import { createBrushHandler } from '../lib/create_brush_handler';
import { fetchFields } from '../lib/fetch_fields';
import { extractIndexPatterns } from '../../../../../plugins/vis_type_timeseries/common/extract_index_patterns';
import { esKuery, UI_SETTINGS } from '../../../../../plugins/data/public';
import { getSavedObjectsClient, getUISettings, getDataStart, getCoreStart } from '../../services';
import { CoreStartContextProvider } from '../contexts/query_input_bar_context';
@ -86,20 +85,6 @@ export class VisEditor extends Component {
});
}, VIS_STATE_DEBOUNCE_DELAY);
isValidKueryQuery = (filterQuery) => {
if (filterQuery && filterQuery.language === 'kuery') {
try {
const queryOptions = this.coreContext.uiSettings.get(
UI_SETTINGS.QUERY_ALLOW_LEADING_WILDCARDS
);
esKuery.fromKueryExpression(filterQuery.query, { allowLeadingWildcards: queryOptions });
} catch (error) {
return false;
}
}
return true;
};
handleChange = (partialModel) => {
if (isEmpty(partialModel)) {
return;
@ -134,6 +119,14 @@ export class VisEditor extends Component {
});
};
updateModel = () => {
const { params } = this.props.vis.clone();
this.setState({
model: params,
});
};
handleCommit = () => {
this.updateVisState();
this.setState({ dirty: false });
@ -219,6 +212,10 @@ export class VisEditor extends Component {
componentDidMount() {
this.props.renderComplete();
if (this.props.isEditorMode && this.props.eventEmitter) {
this.props.eventEmitter.on('updateEditor', this.updateModel);
}
}
componentDidUpdate() {
@ -227,6 +224,10 @@ export class VisEditor extends Component {
componentWillUnmount() {
this.updateVisState.cancel();
if (this.props.isEditorMode && this.props.eventEmitter) {
this.props.eventEmitter.off('updateEditor', this.updateModel);
}
}
}

View file

@ -21,6 +21,7 @@ import expect from '@kbn/expect';
import { FtrProviderContext } from '../../ftr_provider_context';
export default function ({ getService, getPageObjects }: FtrProviderContext) {
const browser = getService('browser');
const esArchiver = getService('esArchiver');
const log = getService('log');
const inspector = getService('inspector');
@ -146,5 +147,79 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
expect(newValue).to.eql('10');
});
});
describe('browser history changes', () => {
it('should activate previous/next chart tab and panel config', async () => {
await PageObjects.visualBuilder.resetPage();
log.debug('Click metric chart');
await PageObjects.visualBuilder.clickMetric();
await PageObjects.visualBuilder.checkMetricTabIsPresent();
await PageObjects.visualBuilder.checkTabIsSelected('metric');
log.debug('Click Top N chart');
await PageObjects.visualBuilder.clickTopN();
await PageObjects.visualBuilder.checkTopNTabIsPresent();
await PageObjects.visualBuilder.checkTabIsSelected('top_n');
log.debug('Go back in browser history');
await browser.goBack();
log.debug('Check metric chart and panel config is rendered');
await PageObjects.visualBuilder.checkMetricTabIsPresent();
await PageObjects.visualBuilder.checkTabIsSelected('metric');
await PageObjects.visualBuilder.checkPanelConfigIsPresent('metric');
log.debug('Go back in browser history');
await browser.goBack();
log.debug('Check timeseries chart and panel config is rendered');
await PageObjects.visualBuilder.checkTimeSeriesChartIsPresent();
await PageObjects.visualBuilder.checkTabIsSelected('timeseries');
await PageObjects.visualBuilder.checkPanelConfigIsPresent('timeseries');
log.debug('Go forward in browser history');
await browser.goForward();
log.debug('Check metric chart and panel config is rendered');
await PageObjects.visualBuilder.checkMetricTabIsPresent();
await PageObjects.visualBuilder.checkTabIsSelected('metric');
await PageObjects.visualBuilder.checkPanelConfigIsPresent('metric');
});
it('should update panel config', async () => {
await PageObjects.visualBuilder.resetPage();
const initialLegendItems = ['Count: 156'];
const finalLegendItems = ['jpg: 106', 'css: 22', 'png: 14', 'gif: 8', 'php: 6'];
log.debug('Group metrics by terms: extension.raw');
await PageObjects.visualBuilder.setMetricsGroupByTerms('extension.raw');
await PageObjects.visChart.waitForVisualizationRenderingStabilized();
const legendItems1 = await PageObjects.visualBuilder.getLegendItemsContent();
expect(legendItems1).to.eql(finalLegendItems);
log.debug('Go back in browser history');
await browser.goBack();
const isTermsSelected = await PageObjects.visualBuilder.checkSelectedMetricsGroupByValue(
'Terms'
);
expect(isTermsSelected).to.be(true);
log.debug('Go back in browser history');
await browser.goBack();
await PageObjects.visualBuilder.checkSelectedMetricsGroupByValue('Everything');
await PageObjects.visChart.waitForVisualizationRenderingStabilized();
const legendItems2 = await PageObjects.visualBuilder.getLegendItemsContent();
expect(legendItems2).to.eql(initialLegendItems);
log.debug('Go forward twice in browser history');
await browser.goForward();
await browser.goForward();
await PageObjects.visChart.waitForVisualizationRenderingStabilized();
const legendItems3 = await PageObjects.visualBuilder.getLegendItemsContent();
expect(legendItems3).to.eql(finalLegendItems);
});
});
});
}

View file

@ -64,6 +64,19 @@ export function VisualBuilderPageProvider({ getService, getPageObjects }: FtrPro
}
}
public async checkTabIsSelected(chartType: string) {
const chartTypeBtn = await testSubjects.find(`${chartType}TsvbTypeBtn`);
const isSelected = await chartTypeBtn.getAttribute('aria-selected');
if (isSelected !== 'true') {
throw new Error(`TSVB ${chartType} tab is not selected`);
}
}
public async checkPanelConfigIsPresent(chartType: string) {
await testSubjects.existOrFail(`tvbPanelConfig__${chartType}`);
}
public async checkVisualBuilderIsPresent() {
await this.checkTabIsLoaded('tvbVisEditor', 'Time Series');
}
@ -558,9 +571,40 @@ export function VisualBuilderPageProvider({ getService, getPageObjects }: FtrPro
return await find.allByCssSelector('.echLegendItem');
}
public async getLegendItemsContent(): Promise<string[]> {
const legendList = await find.byCssSelector('.echLegendList');
const $ = await legendList.parseDomContent();
return $('li')
.toArray()
.map((li) => {
const label = $(li).find('.echLegendItem__label').text();
const value = $(li).find('.echLegendItem__extra').text();
return `${label}: ${value}`;
});
}
public async getSeries(): Promise<WebElementWrapper[]> {
return await find.allByCssSelector('.tvbSeriesEditor');
}
public async setMetricsGroupByTerms(field: string) {
const groupBy = await find.byCssSelector(
'.tvbAggRow--split [data-test-subj="comboBoxInput"]'
);
await comboBox.setElement(groupBy, 'Terms', { clickWithMouse: true });
await PageObjects.common.sleep(1000);
const byField = await testSubjects.find('groupByField');
await comboBox.setElement(byField, field, { clickWithMouse: true });
}
public async checkSelectedMetricsGroupByValue(value: string) {
const groupBy = await find.byCssSelector(
'.tvbAggRow--split [data-test-subj="comboBoxInput"]'
);
return await comboBox.isOptionSelected(groupBy, value);
}
}
return new VisualBuilderPage();