Skip to content

Commit

Permalink
[Autocomplete] Support useTimeFilter option (#81515) (#83090)
Browse files Browse the repository at this point in the history
* pass timefilter to autocomplete

* ignoreTimeRange advanced setting

* Show all results in filter bar autocomplete

* Round timerange to minute for autocomplete memoization

* Change useTimeFilter param name
Update autocomplete tests and docs

* Fix maps test
useTimeFilter in uptime

* docs

* useTimeRange in apm

* remove date validation

* Update src/plugins/data/common/constants.ts

Co-authored-by: Lukas Olson <[email protected]>

* docs

Co-authored-by: Kibana Machine <[email protected]>
Co-authored-by: Lukas Olson <[email protected]>

Co-authored-by: Kibana Machine <[email protected]>
Co-authored-by: Lukas Olson <[email protected]>
  • Loading branch information
3 people authored Nov 15, 2020
1 parent 45de98a commit 8f08058
Show file tree
Hide file tree
Showing 20 changed files with 136 additions and 46 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,5 @@ export interface QuerySuggestionGetFnArgs
| [selectionEnd](./kibana-plugin-plugins-data-public.querysuggestiongetfnargs.selectionend.md) | <code>number</code> | |
| [selectionStart](./kibana-plugin-plugins-data-public.querysuggestiongetfnargs.selectionstart.md) | <code>number</code> | |
| [signal](./kibana-plugin-plugins-data-public.querysuggestiongetfnargs.signal.md) | <code>AbortSignal</code> | |
| [useTimeRange](./kibana-plugin-plugins-data-public.querysuggestiongetfnargs.usetimerange.md) | <code>boolean</code> | |

Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->

[Home](./index.md) &gt; [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) &gt; [QuerySuggestionGetFnArgs](./kibana-plugin-plugins-data-public.querysuggestiongetfnargs.md) &gt; [useTimeRange](./kibana-plugin-plugins-data-public.querysuggestiongetfnargs.usetimerange.md)

## QuerySuggestionGetFnArgs.useTimeRange property

<b>Signature:</b>

```typescript
useTimeRange?: boolean;
```
Original file line number Diff line number Diff line change
Expand Up @@ -37,5 +37,6 @@ UI_SETTINGS: {
readonly INDEXPATTERN_PLACEHOLDER: "indexPattern:placeholder";
readonly FILTERS_PINNED_BY_DEFAULT: "filters:pinnedByDefault";
readonly FILTERS_EDITOR_SUGGEST_VALUES: "filterEditor:suggestValues";
readonly AUTOCOMPLETE_USE_TIMERANGE: "autocomplete:useTimeRange";
}
```
Original file line number Diff line number Diff line change
Expand Up @@ -37,5 +37,6 @@ UI_SETTINGS: {
readonly INDEXPATTERN_PLACEHOLDER: "indexPattern:placeholder";
readonly FILTERS_PINNED_BY_DEFAULT: "filters:pinnedByDefault";
readonly FILTERS_EDITOR_SUGGEST_VALUES: "filterEditor:suggestValues";
readonly AUTOCOMPLETE_USE_TIMERANGE: "autocomplete:useTimeRange";
}
```
1 change: 1 addition & 0 deletions src/plugins/data/common/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,4 +49,5 @@ export const UI_SETTINGS = {
INDEXPATTERN_PLACEHOLDER: 'indexPattern:placeholder',
FILTERS_PINNED_BY_DEFAULT: 'filters:pinnedByDefault',
FILTERS_EDITOR_SUGGEST_VALUES: 'filterEditor:suggestValues',
AUTOCOMPLETE_USE_TIMERANGE: 'autocomplete:useTimeRange',
} as const;
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ export interface QuerySuggestionGetFnArgs {
selectionStart: number;
selectionEnd: number;
signal?: AbortSignal;
useTimeRange?: boolean;
boolFilter?: any;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,26 @@ import { stubIndexPattern, stubFields } from '../../stubs';
import { setupValueSuggestionProvider, ValueSuggestionsGetFn } from './value_suggestion_provider';
import { IUiSettingsClient, CoreSetup } from 'kibana/public';

jest.mock('../../services', () => ({
getQueryService: () => ({
timefilter: {
timefilter: {
createFilter: () => {
return {
time: 'fake',
};
},
getTime: () => {
return {
to: 'now',
from: 'now-15m',
};
},
},
},
}),
}));

describe('FieldSuggestions', () => {
let getValueSuggestions: ValueSuggestionsGetFn;
let http: any;
Expand Down Expand Up @@ -94,6 +114,7 @@ describe('FieldSuggestions', () => {
indexPattern: stubIndexPattern,
field,
query: '',
useTimeRange: false,
});

expect(http.fetch).toHaveBeenCalled();
Expand All @@ -107,6 +128,7 @@ describe('FieldSuggestions', () => {
indexPattern: stubIndexPattern,
field,
query: '',
useTimeRange: false,
};

await getValueSuggestions(args);
Expand All @@ -123,6 +145,7 @@ describe('FieldSuggestions', () => {
indexPattern: stubIndexPattern,
field,
query: '',
useTimeRange: false,
};

const { now } = Date;
Expand All @@ -146,50 +169,76 @@ describe('FieldSuggestions', () => {
indexPattern: stubIndexPattern,
field: fields[0],
query: '',
useTimeRange: false,
});
await getValueSuggestions({
indexPattern: stubIndexPattern,
field: fields[0],
query: 'query',
useTimeRange: false,
});
await getValueSuggestions({
indexPattern: stubIndexPattern,
field: fields[1],
query: '',
useTimeRange: false,
});
await getValueSuggestions({
indexPattern: stubIndexPattern,
field: fields[1],
query: 'query',
useTimeRange: false,
});

const customIndexPattern = {
...stubIndexPattern,
title: 'customIndexPattern',
useTimeRange: false,
};

await getValueSuggestions({
indexPattern: customIndexPattern,
field: fields[0],
query: '',
useTimeRange: false,
});
await getValueSuggestions({
indexPattern: customIndexPattern,
field: fields[0],
query: 'query',
useTimeRange: false,
});
await getValueSuggestions({
indexPattern: customIndexPattern,
field: fields[1],
query: '',
useTimeRange: false,
});
await getValueSuggestions({
indexPattern: customIndexPattern,
field: fields[1],
query: 'query',
useTimeRange: false,
});

expect(http.fetch).toHaveBeenCalledTimes(8);
});

it('should apply timefilter', async () => {
const [field] = stubFields.filter(
({ type, aggregatable }) => type === 'string' && aggregatable
);

await getValueSuggestions({
indexPattern: stubIndexPattern,
field,
query: '',
useTimeRange: true,
});
const callParams = http.fetch.mock.calls[0][1];

expect(JSON.parse(callParams.body).filters).toHaveLength(1);
expect(http.fetch).toHaveBeenCalled();
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,16 @@
* under the License.
*/

import dateMath from '@elastic/datemath';
import { memoize } from 'lodash';
import { CoreSetup } from 'src/core/public';
import { IIndexPattern, IFieldType, UI_SETTINGS } from '../../../common';
import { IIndexPattern, IFieldType, UI_SETTINGS, buildQueryFromFilters } from '../../../common';
import { getQueryService } from '../../services';

function resolver(title: string, field: IFieldType, query: string, boolFilter: any) {
function resolver(title: string, field: IFieldType, query: string, filters: any[]) {
// Only cache results for a minute
const ttl = Math.floor(Date.now() / 1000 / 60);

return [ttl, query, title, field.name, JSON.stringify(boolFilter)].join('|');
return [ttl, query, title, field.name, JSON.stringify(filters)].join('|');
}

export type ValueSuggestionsGetFn = (args: ValueSuggestionsGetFnArgs) => Promise<any[]>;
Expand All @@ -34,18 +35,31 @@ interface ValueSuggestionsGetFnArgs {
indexPattern: IIndexPattern;
field: IFieldType;
query: string;
useTimeRange?: boolean;
boolFilter?: any[];
signal?: AbortSignal;
}

const getAutocompleteTimefilter = (indexPattern: IIndexPattern) => {
const { timefilter } = getQueryService().timefilter;
const timeRange = timefilter.getTime();

// Use a rounded timerange so that memoizing works properly
const roundedTimerange = {
from: dateMath.parse(timeRange.from)!.startOf('minute').toISOString(),
to: dateMath.parse(timeRange.to)!.endOf('minute').toISOString(),
};
return timefilter.createFilter(indexPattern, roundedTimerange);
};

export const getEmptyValueSuggestions = (() => Promise.resolve([])) as ValueSuggestionsGetFn;

export const setupValueSuggestionProvider = (core: CoreSetup): ValueSuggestionsGetFn => {
const requestSuggestions = memoize(
(index: string, field: IFieldType, query: string, boolFilter: any = [], signal?: AbortSignal) =>
(index: string, field: IFieldType, query: string, filters: any = [], signal?: AbortSignal) =>
core.http.fetch(`/api/kibana/suggestions/values/${index}`, {
method: 'POST',
body: JSON.stringify({ query, field: field.name, boolFilter }),
body: JSON.stringify({ query, field: field.name, filters }),
signal,
}),
resolver
Expand All @@ -55,12 +69,15 @@ export const setupValueSuggestionProvider = (core: CoreSetup): ValueSuggestionsG
indexPattern,
field,
query,
useTimeRange,
boolFilter,
signal,
}: ValueSuggestionsGetFnArgs): Promise<any[]> => {
const shouldSuggestValues = core!.uiSettings.get<boolean>(
UI_SETTINGS.FILTERS_EDITOR_SUGGEST_VALUES
);
useTimeRange =
useTimeRange ?? core!.uiSettings.get<boolean>(UI_SETTINGS.AUTOCOMPLETE_USE_TIMERANGE);
const { title } = indexPattern;

if (field.type === 'boolean') {
Expand All @@ -69,6 +86,9 @@ export const setupValueSuggestionProvider = (core: CoreSetup): ValueSuggestionsG
return [];
}

return await requestSuggestions(title, field, query, boolFilter, signal);
const timeFilter = useTimeRange ? getAutocompleteTimefilter(indexPattern) : undefined;
const filterQuery = timeFilter ? buildQueryFromFilters([timeFilter], indexPattern).filter : [];
const filters = [...(boolFilter ? boolFilter : []), ...filterQuery];
return await requestSuggestions(title, field, query, filters, signal);
};
};
3 changes: 3 additions & 0 deletions src/plugins/data/public/public.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -1849,6 +1849,8 @@ export interface QuerySuggestionGetFnArgs {
selectionStart: number;
// (undocumented)
signal?: AbortSignal;
// (undocumented)
useTimeRange?: boolean;
}

// Warning: (ae-missing-release-tag) "QuerySuggestionTypes" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
Expand Down Expand Up @@ -2318,6 +2320,7 @@ export const UI_SETTINGS: {
readonly INDEXPATTERN_PLACEHOLDER: "indexPattern:placeholder";
readonly FILTERS_PINNED_BY_DEFAULT: "filters:pinnedByDefault";
readonly FILTERS_EDITOR_SUGGEST_VALUES: "filterEditor:suggestValues";
readonly AUTOCOMPLETE_USE_TIMERANGE: "autocomplete:useTimeRange";
};


Expand Down
11 changes: 8 additions & 3 deletions src/plugins/data/public/query/timefilter/timefilter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,14 @@ import { PublicMethodsOf } from '@kbn/utility-types';
import { areRefreshIntervalsDifferent, areTimeRangesDifferent } from './lib/diff_time_picker_vals';
import { getForceNow } from './lib/get_force_now';
import { TimefilterConfig, InputTimeRange, TimeRangeBounds } from './types';
import { calculateBounds, getTime, RefreshInterval, TimeRange } from '../../../common';
import {
calculateBounds,
getTime,
IIndexPattern,
RefreshInterval,
TimeRange,
} from '../../../common';
import { TimeHistoryContract } from './time_history';
import { IndexPattern } from '../../index_patterns';

// TODO: remove!

Expand Down Expand Up @@ -170,7 +175,7 @@ export class Timefilter {
}
};

public createFilter = (indexPattern: IndexPattern, timeRange?: TimeRange) => {
public createFilter = (indexPattern: IIndexPattern, timeRange?: TimeRange) => {
return getTime(indexPattern, timeRange ? timeRange : this._time, {
forceNow: this.getForceNow(),
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@ export class PhraseSuggestorUI<T extends PhraseSuggestorProps> extends React.Com
field,
query,
signal: this.abortController.signal,
// Show all results in filter bar autocomplete
useTimeRange: false,
});

this.setState({ suggestions, isLoading: false });
Expand Down
10 changes: 5 additions & 5 deletions src/plugins/data/server/autocomplete/value_suggestions_route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,15 +45,15 @@ export function registerValueSuggestionsRoute(
{
field: schema.string(),
query: schema.string(),
boolFilter: schema.maybe(schema.any()),
filters: schema.maybe(schema.any()),
},
{ unknowns: 'allow' }
),
},
},
async (context, request, response) => {
const config = await config$.pipe(first()).toPromise();
const { field: fieldName, query, boolFilter } = request.body;
const { field: fieldName, query, filters } = request.body;
const { index } = request.params;
const { client } = context.core.elasticsearch.legacy;
const signal = getRequestAbortedSignal(request.events.aborted$);
Expand All @@ -66,7 +66,7 @@ export function registerValueSuggestionsRoute(
const indexPattern = await findIndexPatternById(context.core.savedObjects.client, index);

const field = indexPattern && getFieldByName(fieldName, indexPattern);
const body = await getBody(autocompleteSearchOptions, field || fieldName, query, boolFilter);
const body = await getBody(autocompleteSearchOptions, field || fieldName, query, filters);

try {
const result = await client.callAsCurrentUser('search', { index, body }, { signal });
Expand All @@ -88,7 +88,7 @@ async function getBody(
{ timeout, terminate_after }: Record<string, any>,
field: IFieldType | string,
query: string,
boolFilter: Filter[] = []
filters: Filter[] = []
) {
const isFieldObject = (f: any): f is IFieldType => Boolean(f && f.name);

Expand All @@ -108,7 +108,7 @@ async function getBody(
terminate_after,
query: {
bool: {
filter: boolFilter,
filter: filters,
},
},
aggs: {
Expand Down
1 change: 1 addition & 0 deletions src/plugins/data/server/server.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -1186,6 +1186,7 @@ export const UI_SETTINGS: {
readonly INDEXPATTERN_PLACEHOLDER: "indexPattern:placeholder";
readonly FILTERS_PINNED_BY_DEFAULT: "filters:pinnedByDefault";
readonly FILTERS_EDITOR_SUGGEST_VALUES: "filterEditor:suggestValues";
readonly AUTOCOMPLETE_USE_TIMERANGE: "autocomplete:useTimeRange";
};

// Warning: (ae-missing-release-tag) "usageProvider" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
Expand Down
12 changes: 12 additions & 0 deletions src/plugins/data/server/ui_settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -684,5 +684,17 @@ export function getUiSettings(): Record<string, UiSettingsParams<unknown>> {
}),
schema: schema.boolean(),
},
[UI_SETTINGS.AUTOCOMPLETE_USE_TIMERANGE]: {
name: i18n.translate('data.advancedSettings.autocompleteIgnoreTimerange', {
defaultMessage: 'Use time range',
description: 'Restrict autocomplete results to the current time range',
}),
value: true,
description: i18n.translate('data.advancedSettings.autocompleteIgnoreTimerangeText', {
defaultMessage:
'Disable this property to get autocomplete suggestions from your full dataset, rather than from the current time range.',
}),
schema: schema.boolean(),
},
};
}
Loading

0 comments on commit 8f08058

Please sign in to comment.