Skip to content

Commit

Permalink
Fix invisible filters caused by missing index pattern (elastic#14131)
Browse files Browse the repository at this point in the history
"invisible filters" occur when the mapping chain throws an error. If a single filter throws an error, the entire chain rejects. As a result, not even the valid filters appear in the filter bar because they never get added to the scope. However the filters still exist in app state and still get sent with each search request.

The most common error occurs when the filter's meta.index property points to a non-existing index pattern. Since this property is only used for looking up field formatters and it is not essential for a working filter, we now fall back on raw values instead of failing if the index pattern is not found. See the PR this one replaces for discussion about other solutions we tried and why we chose to go this route.
  • Loading branch information
Bargs committed Oct 4, 2017
1 parent 3503aac commit 397954c
Show file tree
Hide file tree
Showing 7 changed files with 88 additions and 117 deletions.
69 changes: 0 additions & 69 deletions src/ui/public/filter_bar/lib/__tests__/map_script.js

This file was deleted.

2 changes: 0 additions & 2 deletions src/ui/public/filter_bar/lib/map_filter.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import { FilterBarLibMapMissingProvider } from './map_missing';
import { FilterBarLibMapQueryStringProvider } from './map_query_string';
import { FilterBarLibMapGeoBoundingBoxProvider } from './map_geo_bounding_box';
import { FilterBarLibMapGeoPolygonProvider } from './map_geo_polygon';
import { FilterBarLibMapScriptProvider } from './map_script';
import { FilterBarLibMapDefaultProvider } from './map_default';

export function FilterBarLibMapFilterProvider(Promise, Private) {
Expand Down Expand Up @@ -42,7 +41,6 @@ export function FilterBarLibMapFilterProvider(Promise, Private) {
Private(FilterBarLibMapQueryStringProvider),
Private(FilterBarLibMapGeoBoundingBoxProvider),
Private(FilterBarLibMapGeoPolygonProvider),
Private(FilterBarLibMapScriptProvider),
Private(FilterBarLibMapDefaultProvider),
];

Expand Down
30 changes: 24 additions & 6 deletions src/ui/public/filter_bar/lib/map_geo_bounding_box.js
Original file line number Diff line number Diff line change
@@ -1,20 +1,38 @@
import _ from 'lodash';
import { SavedObjectNotFound } from '../../errors';

export function FilterBarLibMapGeoBoundingBoxProvider(Promise, courier) {
return function (filter) {
if (filter.geo_bounding_box) {
return courier
.indexPatterns
.get(filter.meta.index).then(function (indexPattern) {
function getParams(indexPattern) {
const type = 'geo_bounding_box';
const key = _.keys(filter.geo_bounding_box)
.filter(key => key !== 'ignore_unmapped')[0];
const field = indexPattern.fields.byName[key];
const params = filter.geo_bounding_box[key];
const topLeft = field.format.convert(params.top_left);
const bottomRight = field.format.convert(params.bottom_right);

// Sometimes a filter will end up with an invalid index param. This could happen for a lot of reasons,
// for example a user might manually edit the url or the index pattern's ID might change due to
// external factors e.g. a reindex. We only need the index in order to grab the field formatter, so we fallback
// on displaying the raw value if the index is invalid.
const topLeft = indexPattern
? indexPattern.fields.byName[key].format.convert(params.top_left)
: JSON.stringify(params.top_left);
const bottomRight = indexPattern
? indexPattern.fields.byName[key].format.convert(params.bottom_right)
: JSON.stringify(params.bottom_right);
const value = topLeft + ' to ' + bottomRight;
return { type, key, value, params };
}

return courier
.indexPatterns
.get(filter.meta.index)
.then(getParams)
.catch((error) => {
if (error instanceof SavedObjectNotFound) {
return getParams();
}
throw error;
});
}
return Promise.reject(filter);
Expand Down
28 changes: 23 additions & 5 deletions src/ui/public/filter_bar/lib/map_geo_polygon.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,37 @@
import _ from 'lodash';
import { SavedObjectNotFound } from '../../errors';

export function FilterBarLibMapGeoPolygonProvider(Promise, courier) {
return function (filter) {
if (filter.geo_polygon) {
return courier
.indexPatterns
.get(filter.meta.index).then(function (indexPattern) {
function getParams(indexPattern) {
const type = 'geo_polygon';
const key = _.keys(filter.geo_polygon)
.filter(key => key !== 'ignore_unmapped')[0];
const field = indexPattern.fields.byName[key];
const params = filter.geo_polygon[key];
const points = params.points.map((point) => field.format.convert(point));

// Sometimes a filter will end up with an invalid index param. This could happen for a lot of reasons,
// for example a user might manually edit the url or the index pattern's ID might change due to
// external factors e.g. a reindex. We only need the index in order to grab the field formatter, so we fallback
// on displaying the raw value if the index is invalid.
const points = params.points.map((point) => {
return indexPattern
? indexPattern.fields.byName[key].format.convert(point)
: JSON.stringify(point);
});
const value = points.join(', ');
return { type, key, value, params };
}

return courier
.indexPatterns
.get(filter.meta.index)
.then(getParams)
.catch((error) => {
if (error instanceof SavedObjectNotFound) {
return getParams();
}
throw error;
});
}
return Promise.reject(filter);
Expand Down
24 changes: 19 additions & 5 deletions src/ui/public/filter_bar/lib/map_phrase.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import _ from 'lodash';
import { SavedObjectNotFound } from '../../errors';

export function FilterBarLibMapPhraseProvider(Promise, courier) {
return function (filter) {
Expand All @@ -7,16 +8,29 @@ export function FilterBarLibMapPhraseProvider(Promise, courier) {
return Promise.reject(filter);
}

return courier
.indexPatterns
.get(filter.meta.index).then(function (indexPattern) {
function getParams(indexPattern) {
const type = 'phrase';
const key = isScriptedPhraseFilter ? filter.meta.field : Object.keys(filter.query.match)[0];
const field = indexPattern.fields.byName[key];
const params = isScriptedPhraseFilter ? filter.script.script.params : filter.query.match[key];
const query = isScriptedPhraseFilter ? params.value : params.query;
const value = field.format.convert(query);

// Sometimes a filter will end up with an invalid index param. This could happen for a lot of reasons,
// for example a user might manually edit the url or the index pattern's ID might change due to
// external factors e.g. a reindex. We only need the index in order to grab the field formatter, so we fallback
// on displaying the raw value if the index is invalid.
const value = indexPattern ? indexPattern.fields.byName[key].format.convert(query) : query;
return { type, key, value, params };
}

return courier
.indexPatterns
.get(filter.meta.index)
.then(getParams)
.catch((error) => {
if (error instanceof SavedObjectNotFound) {
return getParams();
}
throw error;
});
};
}
Expand Down
28 changes: 22 additions & 6 deletions src/ui/public/filter_bar/lib/map_range.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { has, get } from 'lodash';
import { SavedObjectNotFound } from '../../errors';

export function FilterBarLibMapRangeProvider(Promise, courier) {
return function (filter) {
Expand All @@ -7,13 +8,9 @@ export function FilterBarLibMapRangeProvider(Promise, courier) {
return Promise.reject(filter);
}

return courier
.indexPatterns
.get(filter.meta.index)
.then(function (indexPattern) {
function getParams(indexPattern) {
const type = 'range';
const key = isScriptedRangeFilter ? filter.meta.field : Object.keys(filter.range)[0];
const convert = indexPattern.fields.byName[key].format.getConverterFor('text');
const params = isScriptedRangeFilter ? filter.script.script.params : filter.range[key];

let left = has(params, 'gte') ? params.gte : params.gt;
Expand All @@ -22,9 +19,28 @@ export function FilterBarLibMapRangeProvider(Promise, courier) {
let right = has(params, 'lte') ? params.lte : params.lt;
if (right == null) right = Infinity;

const value = `${convert(left)} to ${convert(right)}`;
// Sometimes a filter will end up with an invalid index param. This could happen for a lot of reasons,
// for example a user might manually edit the url or the index pattern's ID might change due to
// external factors e.g. a reindex. We only need the index in order to grab the field formatter, so we fallback
// on displaying the raw value if the index is invalid.
let value = `${left} to ${right}`;
if (indexPattern) {
const convert = indexPattern.fields.byName[key].format.getConverterFor('text');
value = `${convert(left)} to ${convert(right)}`;
}

return { type, key, value, params };
}

return courier
.indexPatterns
.get(filter.meta.index)
.then(getParams)
.catch((error) => {
if (error instanceof SavedObjectNotFound) {
return getParams();
}
throw error;
});

};
Expand Down
24 changes: 0 additions & 24 deletions src/ui/public/filter_bar/lib/map_script.js

This file was deleted.

0 comments on commit 397954c

Please sign in to comment.