Skip to content

Commit cb364b4

Browse files
authored
Fix TSVB state updates when changing indexpatterns (#24832) (#25200)
* Move fieldsFetch logic into the vis editor * Add annotations index pattern change detection * Fix async update of state. Add functional test * Add missing data archive * Force fetch when component mount the first time * Fix parameters naming * Refactoring indexPatterns to fetch
1 parent 74a7731 commit cb364b4

File tree

14 files changed

+290
-126
lines changed

14 files changed

+290
-126
lines changed

src/core_plugins/metrics/public/components/index_pattern.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ export const IndexPattern = props => {
5454
disabled={props.disabled}
5555
onChange={handleTextChange(indexPatternName, '*')}
5656
value={model[indexPatternName]}
57+
data-test-subj="metricsIndexPatternInput"
5758
/>
5859
<label className="vis_editor__label" htmlFor={htmlId('timeField')}>
5960
Time Field
@@ -67,6 +68,7 @@ export const IndexPattern = props => {
6768
onChange={handleSelectChange(timeFieldName)}
6869
indexPattern={model[indexPatternName]}
6970
fields={fields}
71+
data-test-subj="metricsIndexPatternFieldsSelect"
7072
/>
7173
</div>
7274
<label className="vis_editor__label" htmlFor={htmlId('interval')}>

src/core_plugins/metrics/public/components/panel_config/metric.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ class MetricPanelConfig extends Component {
119119
aria-selected={selectedTab === 'options'}
120120
className={`kbnTabs__tab${selectedTab === 'options' && '-active' || ''}`}
121121
onClick={() => this.switchTab('options')}
122+
data-test-subj="metricEditorPanelOptionsBtn"
122123
>Panel Options
123124
</button>
124125
</div>

src/core_plugins/metrics/public/components/vis_editor.js

Lines changed: 63 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,23 @@ import VisPicker from './vis_picker';
2525
import PanelConfig from './panel_config';
2626
import brushHandler from '../lib/create_brush_handler';
2727
import { get } from 'lodash';
28+
import { extractIndexPatterns } from '../lib/extract_index_patterns';
29+
import { fetchFields } from '../lib/fetch_fields';
30+
import chrome from 'ui/chrome';
2831

2932
class VisEditor extends Component {
3033
constructor(props) {
3134
super(props);
3235
const { vis } = props;
3336
this.appState = vis.API.getAppState();
3437
const reversed = get(this.appState, 'options.darkTheme', false);
35-
this.state = { model: props.vis.params, dirty: false, autoApply: true, reversed };
38+
this.state = {
39+
model: props.vis.params,
40+
dirty: false,
41+
autoApply: true,
42+
reversed,
43+
visFields: {},
44+
};
3645
this.onBrush = brushHandler(props.vis.API.timeFilter);
3746
this.handleUiState = this.handleUiState.bind(this, props.vis);
3847
this.handleAppStateChange = this.handleAppStateChange.bind(this);
@@ -60,27 +69,54 @@ class VisEditor extends Component {
6069
}
6170
}
6271

63-
render() {
64-
const handleChange = (part) => {
65-
const nextModel = { ...this.state.model, ...part };
72+
fetchIndexPatternFields = async () => {
73+
const { params } = this.props.vis;
74+
const { visFields } = this.state;
75+
const indexPatterns = extractIndexPatterns(params, visFields);
76+
const fields = await fetchFields(indexPatterns);
77+
this.setState((previousState) => {
78+
return {
79+
visFields: {
80+
...previousState.visFields,
81+
...fields,
82+
}
83+
};
84+
});
85+
}
6686

67-
this.props.vis.params = nextModel;
68-
if (this.state.autoApply) {
69-
this.props.vis.updateState();
70-
}
87+
setDefaultIndexPattern = async () => {
88+
if (this.props.vis.params.index_pattern === '') {
89+
// set the default index pattern if none is defined.
90+
const savedObjectsClient = chrome.getSavedObjectsClient();
91+
const indexPattern = await savedObjectsClient.get('index-pattern', this.getConfig('defaultIndex'));
92+
const defaultIndexPattern = indexPattern.attributes.title;
93+
this.props.vis.params.index_pattern = defaultIndexPattern;
94+
}
95+
}
7196

72-
this.setState({ model: nextModel, dirty: !this.state.autoApply });
73-
};
97+
handleChange = async (partialModel) => {
98+
const nextModel = { ...this.state.model, ...partialModel };
99+
this.props.vis.params = nextModel;
100+
if (this.state.autoApply) {
101+
this.props.vis.updateState();
102+
}
103+
this.setState({
104+
model: nextModel,
105+
dirty: !this.state.autoApply,
106+
});
107+
this.fetchIndexPatternFields();
108+
}
74109

75-
const handleAutoApplyToggle = (part) => {
76-
this.setState({ autoApply: part.target.checked });
77-
};
110+
handleCommit = () => {
111+
this.props.vis.updateState();
112+
this.setState({ dirty: false });
113+
}
78114

79-
const handleCommit = () => {
80-
this.props.vis.updateState();
81-
this.setState({ dirty: false });
82-
};
115+
handleAutoApplyToggle = (event) => {
116+
this.setState({ autoApply: event.target.checked });
117+
}
83118

119+
render() {
84120
if (!this.props.isEditorMode) {
85121
if (!this.props.vis.params || !this.props.visData) return null;
86122
const reversed = this.state.reversed;
@@ -91,7 +127,7 @@ class VisEditor extends Component {
91127
onBrush={this.onBrush}
92128
onUiState={this.handleUiState}
93129
uiState={this.props.vis.getUiState()}
94-
fields={this.props.vis.fields}
130+
fields={this.state.visFields}
95131
model={this.props.vis.params}
96132
visData={this.props.visData}
97133
getConfig={this.getConfig}
@@ -105,7 +141,7 @@ class VisEditor extends Component {
105141
return (
106142
<div className="vis_editor">
107143
<div className="vis-editor-hide-for-reporting">
108-
<VisPicker model={model} onChange={handleChange} />
144+
<VisPicker model={model} onChange={this.handleChange} />
109145
</div>
110146
<VisEditorVisualization
111147
dirty={this.state.dirty}
@@ -117,20 +153,20 @@ class VisEditor extends Component {
117153
onUiState={this.handleUiState}
118154
uiState={this.props.vis.getUiState()}
119155
onBrush={this.onBrush}
120-
onCommit={handleCommit}
121-
onToggleAutoApply={handleAutoApplyToggle}
122-
onChange={handleChange}
156+
onCommit={this.handleCommit}
157+
onToggleAutoApply={this.handleAutoApplyToggle}
158+
onChange={this.handleChange}
123159
title={this.props.vis.title}
124160
description={this.props.vis.description}
125161
dateFormat={this.props.config.get('dateFormat')}
126162
/>
127163
<div className="vis-editor-hide-for-reporting">
128164
<PanelConfig
129-
fields={this.props.vis.fields}
165+
fields={this.state.visFields}
130166
model={model}
131167
visData={this.props.visData}
132168
dateFormat={this.props.config.get('dateFormat')}
133-
onChange={handleChange}
169+
onChange={this.handleChange}
134170
getConfig={this.getConfig}
135171
/>
136172
</div>
@@ -141,7 +177,9 @@ class VisEditor extends Component {
141177
return null;
142178
}
143179

144-
componentDidMount() {
180+
async componentDidMount() {
181+
await this.setDefaultIndexPattern();
182+
await this.fetchIndexPatternFields();
145183
this.props.renderComplete();
146184
}
147185

src/core_plugins/metrics/public/kbn_vis_types/editor_controller.js

Lines changed: 11 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -18,48 +18,27 @@
1818
*/
1919

2020
import React from 'react';
21-
import chrome from 'ui/chrome';
2221
import { render, unmountComponentAtNode } from 'react-dom';
23-
import { FetchFieldsProvider } from '../lib/fetch_fields';
24-
import { extractIndexPatterns } from '../lib/extract_index_patterns';
2522

2623
function ReactEditorControllerProvider(Private, config) {
27-
const fetchFields = Private(FetchFieldsProvider);
28-
const savedObjectsClient = chrome.getSavedObjectsClient();
29-
3024
class ReactEditorController {
3125
constructor(el, savedObj) {
3226
this.el = el;
3327
this.savedObj = savedObj;
3428
this.vis = savedObj.vis;
35-
this.vis.fields = {};
3629
}
3730

38-
render(params) {
39-
return new Promise((resolve) => {
40-
Promise.resolve().then(() => {
41-
if (this.vis.params.index_pattern === '') {
42-
return savedObjectsClient.get('index-pattern', config.get('defaultIndex')).then((indexPattern) => {
43-
this.vis.params.index_pattern = indexPattern.attributes.title;
44-
});
45-
}
46-
}).then(() => {
47-
const indexPatterns = extractIndexPatterns(this.vis);
48-
fetchFields(indexPatterns).then(fields => {
49-
this.vis.fields = { ...fields, ...this.vis.fields };
50-
const Component = this.vis.type.editorConfig.component;
51-
render(<Component
52-
config={config}
53-
vis={this.vis}
54-
savedObj={this.savedObj}
55-
timeRange={params.timeRange}
56-
renderComplete={resolve}
57-
isEditorMode={true}
58-
appState={params.appState}
59-
/>, this.el);
60-
});
61-
});
62-
});
31+
async render(params) {
32+
const Component = this.vis.type.editorConfig.component;
33+
render(<Component
34+
config={config}
35+
vis={this.vis}
36+
savedObj={this.savedObj}
37+
timeRange={params.timeRange}
38+
renderComplete={() => {}}
39+
isEditorMode={true}
40+
appState={params.appState}
41+
/>, this.el);
6342
}
6443

6544
resize() {

src/core_plugins/metrics/public/less/error.less

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
color: #c00;
2323
justify-content: center;
2424
padding: 20px;
25+
height: 100%;
26+
width: 100%;
2527
}
2628

2729
.metrics_error__title {

src/core_plugins/metrics/public/less/misc.less

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
.thor__visualization {
2+
width: 100%;
3+
height: 100%;
4+
}
15
.thor__input {
26
padding: 7px 10px;
37
border-radius: 4px;

src/core_plugins/metrics/public/lib/__tests__/extract_index_pattern.js

Lines changed: 25 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -20,44 +20,43 @@
2020
import { extractIndexPatterns } from '../extract_index_patterns';
2121
import { expect } from 'chai';
2222
describe('extractIndexPatterns(vis)', () => {
23-
let vis;
23+
let visParams;
24+
let visFields;
2425
beforeEach(() => {
25-
vis = {
26-
fields: {
27-
'*': []
28-
},
29-
params: {
30-
index_pattern: '*',
31-
series: [
32-
{
33-
override_index_pattern: 1,
34-
series_index_pattern: 'example-1-*'
35-
},
36-
{
37-
override_index_pattern: 1,
38-
series_index_pattern: 'example-2-*'
39-
}
40-
],
41-
annotations: [
42-
{ index_pattern: 'notes-*' },
43-
{ index_pattern: 'example-1-*' }
44-
]
45-
}
26+
visFields = {
27+
'*': []
28+
};
29+
visParams = {
30+
index_pattern: '*',
31+
series: [
32+
{
33+
override_index_pattern: 1,
34+
series_index_pattern: 'example-1-*'
35+
},
36+
{
37+
override_index_pattern: 1,
38+
series_index_pattern: 'example-2-*'
39+
}
40+
],
41+
annotations: [
42+
{ index_pattern: 'notes-*' },
43+
{ index_pattern: 'example-1-*' }
44+
]
4645
};
4746
});
4847

4948
it('should return index patterns', () => {
50-
vis.fields = {};
51-
expect(extractIndexPatterns(vis)).to.eql([
49+
visFields = {};
50+
expect(extractIndexPatterns(visParams, visFields)).to.eql([
5251
'*',
5352
'example-1-*',
5453
'example-2-*',
5554
'notes-*'
5655
]);
5756
});
5857

59-
it('should return index patterns that do not exist in vis.fields', () => {
60-
expect(extractIndexPatterns(vis)).to.eql([
58+
it('should return index patterns that do not exist in visFields', () => {
59+
expect(extractIndexPatterns(visParams, visFields)).to.eql([
6160
'example-1-*',
6261
'example-2-*',
6362
'notes-*'

src/core_plugins/metrics/public/lib/extract_index_patterns.js

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,24 +18,24 @@
1818
*/
1919

2020
import { uniq } from 'lodash';
21-
export function extractIndexPatterns(vis) {
21+
export function extractIndexPatterns(params, fetchedFields) {
2222
const patternsToFetch = [];
2323

24-
if (!vis.fields[vis.params.index_pattern]) {
25-
patternsToFetch.push(vis.params.index_pattern);
24+
if (!fetchedFields[params.index_pattern]) {
25+
patternsToFetch.push(params.index_pattern);
2626
}
2727

28-
vis.params.series.forEach(series => {
28+
params.series.forEach(series => {
2929
const indexPattern = series.series_index_pattern;
30-
if (series.override_index_pattern && !vis.fields[indexPattern]) {
30+
if (series.override_index_pattern && !fetchedFields[indexPattern]) {
3131
patternsToFetch.push(indexPattern);
3232
}
3333
});
3434

35-
if (vis.params.annotations) {
36-
vis.params.annotations.forEach(item => {
35+
if (params.annotations) {
36+
params.annotations.forEach(item => {
3737
const indexPattern = item.index_pattern;
38-
if (indexPattern && !vis.fields[indexPattern]) {
38+
if (indexPattern && !fetchedFields[indexPattern]) {
3939
patternsToFetch.push(indexPattern);
4040
}
4141
});

0 commit comments

Comments
 (0)