[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:
parent
d802bf03f7
commit
b8c7945b12
|
@ -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>
|
||||
);
|
||||
|
|
|
@ -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>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 [
|
||||
|
|
|
@ -132,6 +132,7 @@ export const SplitByTermsUI = ({
|
|||
}
|
||||
>
|
||||
<FieldSelect
|
||||
data-test-subj="groupByField"
|
||||
indexPattern={indexPattern}
|
||||
onChange={handleSelectChange('terms_field')}
|
||||
value={model.terms_field}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Reference in a new issue