Skip to content

Commit

Permalink
[Lens] Bind all time fields to the time picker (#63874)
Browse files Browse the repository at this point in the history
* Bind non primary time fields to timepicker

* Fix typescript argument types

* Allow auto interval on all fields

* Remove lens_auto_date function

* Fix existing jest tests and add test todos

* Remove lens_auto_date from esarchives

* Add TimeBuckets jest tests

* Fix typo in esarchiver

* Address review feedback

* Make code a bit better readable

* Fix default time field retrieval

* Fix TS errors

* Add esaggs interpreter tests

* Change public API doc of data plugin

* Add toExpression tests for index pattern datasource

* Add migration stub

* Add full migration

* Fix naming inconsistency in esaggs

* Fix naming issue

* Revert archives to un-migrated version

* Ignore expressions that are already migrated

* test: remove extra spaces and  timeField=\\"products.created_on\\"} to timeField=\"products.created_on\"}

* Rename all timeField -> timeFields

* Combine duplicate functions

* Fix boolean error and add test for it

* Commit API changes

Co-authored-by: Wylie Conlon <[email protected]>
Co-authored-by: Elastic Machine <[email protected]>
Co-authored-by: Marta Bondyra <[email protected]>
  • Loading branch information
4 people authored Apr 30, 2020
1 parent a907c9b commit 9b65cbd
Show file tree
Hide file tree
Showing 26 changed files with 635 additions and 251 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@
<b>Signature:</b>

```typescript
export declare function getTime(indexPattern: IIndexPattern | undefined, timeRange: TimeRange, forceNow?: Date): import("../..").RangeFilter | undefined;
export declare function getTime(indexPattern: IIndexPattern | undefined, timeRange: TimeRange, options?: {
forceNow?: Date;
fieldName?: string;
}): import("../..").RangeFilter | undefined;
```

## Parameters
Expand All @@ -16,7 +19,7 @@ export declare function getTime(indexPattern: IIndexPattern | undefined, timeRan
| --- | --- | --- |
| indexPattern | <code>IIndexPattern &#124; undefined</code> | |
| timeRange | <code>TimeRange</code> | |
| forceNow | <code>Date</code> | |
| options | <code>{</code><br/><code> forceNow?: Date;</code><br/><code> fieldName?: string;</code><br/><code>}</code> | |

<b>Returns:</b>

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<!-- 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; [IIndexPattern](./kibana-plugin-plugins-data-public.iindexpattern.md) &gt; [getTimeField](./kibana-plugin-plugins-data-public.iindexpattern.gettimefield.md)

## IIndexPattern.getTimeField() method

<b>Signature:</b>

```typescript
getTimeField?(): IFieldType | undefined;
```
<b>Returns:</b>
`IFieldType | undefined`
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,9 @@ export interface IIndexPattern
| [title](./kibana-plugin-plugins-data-public.iindexpattern.title.md) | <code>string</code> | |
| [type](./kibana-plugin-plugins-data-public.iindexpattern.type.md) | <code>string</code> | |

## Methods

| Method | Description |
| --- | --- |
| [getTimeField()](./kibana-plugin-plugins-data-public.iindexpattern.gettimefield.md) | |

Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
| [getEsPreference(uiSettings, sessionId)](./kibana-plugin-plugins-data-public.getespreference.md) | |
| [getQueryLog(uiSettings, storage, appName, language)](./kibana-plugin-plugins-data-public.getquerylog.md) | |
| [getSearchErrorType({ message })](./kibana-plugin-plugins-data-public.getsearcherrortype.md) | |
| [getTime(indexPattern, timeRange, forceNow)](./kibana-plugin-plugins-data-public.gettime.md) | |
| [getTime(indexPattern, timeRange, options)](./kibana-plugin-plugins-data-public.gettime.md) | |
| [plugin(initializerContext)](./kibana-plugin-plugins-data-public.plugin.md) | |

## Interfaces
Expand Down
1 change: 1 addition & 0 deletions src/plugins/data/common/index_patterns/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ export interface IIndexPattern {
id?: string;
type?: string;
timeFieldName?: string;
getTimeField?(): IFieldType | undefined;
fieldFormatMap?: Record<
string,
{
Expand Down
7 changes: 6 additions & 1 deletion src/plugins/data/public/public.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -699,7 +699,10 @@ export function getSearchErrorType({ message }: Pick<SearchError, 'message'>): "
// Warning: (ae-missing-release-tag) "getTime" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public (undocumented)
export function getTime(indexPattern: IIndexPattern | undefined, timeRange: TimeRange, forceNow?: Date): import("../..").RangeFilter | undefined;
export function getTime(indexPattern: IIndexPattern | undefined, timeRange: TimeRange, options?: {
forceNow?: Date;
fieldName?: string;
}): import("../..").RangeFilter | undefined;

// Warning: (ae-missing-release-tag) "IAggConfig" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
Expand Down Expand Up @@ -842,6 +845,8 @@ export interface IIndexPattern {
// (undocumented)
fields: IFieldType[];
// (undocumented)
getTimeField?(): IFieldType | undefined;
// (undocumented)
id?: string;
// (undocumented)
timeFieldName?: string;
Expand Down
38 changes: 38 additions & 0 deletions src/plugins/data/public/query/timefilter/get_time.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,5 +51,43 @@ describe('get_time', () => {
});
clock.restore();
});

test('build range filter for non-primary field', () => {
const clock = sinon.useFakeTimers(moment.utc([2000, 1, 1, 0, 0, 0, 0]).valueOf());

const filter = getTime(
{
id: 'test',
title: 'test',
timeFieldName: 'date',
fields: [
{
name: 'date',
type: 'date',
esTypes: ['date'],
aggregatable: true,
searchable: true,
filterable: true,
},
{
name: 'myCustomDate',
type: 'date',
esTypes: ['date'],
aggregatable: true,
searchable: true,
filterable: true,
},
],
} as any,
{ from: 'now-60y', to: 'now' },
{ fieldName: 'myCustomDate' }
);
expect(filter!.range.myCustomDate).toEqual({
gte: '1940-02-01T00:00:00.000Z',
lte: '2000-02-01T00:00:00.000Z',
format: 'strict_date_optional_time',
});
clock.restore();
});
});
});
27 changes: 18 additions & 9 deletions src/plugins/data/public/query/timefilter/get_time.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

import dateMath from '@elastic/datemath';
import { IIndexPattern } from '../..';
import { TimeRange, IFieldType, buildRangeFilter } from '../../../common';
import { TimeRange, buildRangeFilter } from '../../../common';

interface CalculateBoundsOptions {
forceNow?: Date;
Expand All @@ -35,18 +35,27 @@ export function calculateBounds(timeRange: TimeRange, options: CalculateBoundsOp
export function getTime(
indexPattern: IIndexPattern | undefined,
timeRange: TimeRange,
options?: { forceNow?: Date; fieldName?: string }
) {
return createTimeRangeFilter(
indexPattern,
timeRange,
options?.fieldName || indexPattern?.timeFieldName,
options?.forceNow
);
}

function createTimeRangeFilter(
indexPattern: IIndexPattern | undefined,
timeRange: TimeRange,
fieldName?: string,
forceNow?: Date
) {
if (!indexPattern) {
// in CI, we sometimes seem to fail here.
return;
}

const timefield: IFieldType | undefined = indexPattern.fields.find(
field => field.name === indexPattern.timeFieldName
);

if (!timefield) {
const field = indexPattern.fields.find(f => f.name === (fieldName || indexPattern.timeFieldName));
if (!field) {
return;
}

Expand All @@ -55,7 +64,7 @@ export function getTime(
return;
}
return buildRangeFilter(
timefield,
field,
{
...(bounds.min && { gte: bounds.min.toISOString() }),
...(bounds.max && { lte: bounds.max.toISOString() }),
Expand Down
2 changes: 1 addition & 1 deletion src/plugins/data/public/query/timefilter/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,6 @@ export { TimefilterService, TimefilterSetup } from './timefilter_service';
export * from './types';
export { Timefilter, TimefilterContract } from './timefilter';
export { TimeHistory, TimeHistoryContract } from './time_history';
export { getTime } from './get_time';
export { getTime, calculateBounds } from './get_time';
export { changeTimeFilter } from './lib/change_time_filter';
export { extractTimeFilter } from './lib/extract_time_filter';
4 changes: 3 additions & 1 deletion src/plugins/data/public/query/timefilter/timefilter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,9 @@ export class Timefilter {
};

public createFilter = (indexPattern: IndexPattern, timeRange?: TimeRange) => {
return getTime(indexPattern, timeRange ? timeRange : this._time, this.getForceNow());
return getTime(indexPattern, timeRange ? timeRange : this._time, {
forceNow: this.getForceNow(),
});
};

public getBounds(): TimeRangeBounds {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ const updateTimeBuckets = (
customBuckets?: IBucketDateHistogramAggConfig['buckets']
) => {
const bounds =
agg.params.timeRange && agg.fieldIsTimeField()
agg.params.timeRange && (agg.fieldIsTimeField() || agg.params.interval === 'auto')
? timefilter.calculateBounds(agg.params.timeRange)
: undefined;
const buckets = customBuckets || agg.buckets;
Expand Down
43 changes: 37 additions & 6 deletions src/plugins/data/public/search/expressions/esaggs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,15 @@ import { Adapters } from '../../../../../plugins/inspector/public';
import { IAggConfigs } from '../aggs';
import { ISearchSource } from '../search_source';
import { tabifyAggResponse } from '../tabify';
import { Filter, Query, serializeFieldFormat, TimeRange } from '../../../common';
import { FilterManager, getTime } from '../../query';
import {
Filter,
Query,
serializeFieldFormat,
TimeRange,
IIndexPattern,
isRangeFilter,
} from '../../../common';
import { FilterManager, calculateBounds, getTime } from '../../query';
import { getSearchService, getQueryService, getIndexPatterns } from '../../services';
import { buildTabularInspectorData } from './build_tabular_inspector_data';
import { getRequestInspectorStats, getResponseInspectorStats, serializeAggConfig } from './utils';
Expand All @@ -42,6 +49,8 @@ export interface RequestHandlerParams {
searchSource: ISearchSource;
aggs: IAggConfigs;
timeRange?: TimeRange;
timeFields?: string[];
indexPattern?: IIndexPattern;
query?: Query;
filters?: Filter[];
forceFetch: boolean;
Expand All @@ -65,12 +74,15 @@ interface Arguments {
partialRows: boolean;
includeFormatHints: boolean;
aggConfigs: string;
timeFields?: string[];
}

const handleCourierRequest = async ({
searchSource,
aggs,
timeRange,
timeFields,
indexPattern,
query,
filters,
forceFetch,
Expand Down Expand Up @@ -111,9 +123,19 @@ const handleCourierRequest = async ({
return aggs.onSearchRequestStart(paramSearchSource, options);
});

if (timeRange) {
// If timeFields have been specified, use the specified ones, otherwise use primary time field of index
// pattern if it's available.
const defaultTimeField = indexPattern?.getTimeField?.();
const defaultTimeFields = defaultTimeField ? [defaultTimeField.name] : [];
const allTimeFields = timeFields && timeFields.length > 0 ? timeFields : defaultTimeFields;

// If a timeRange has been specified and we had at least one timeField available, create range
// filters for that those time fields
if (timeRange && allTimeFields.length > 0) {
timeFilterSearchSource.setField('filter', () => {
return getTime(searchSource.getField('index'), timeRange);
return allTimeFields
.map(fieldName => getTime(indexPattern, timeRange, { fieldName }))
.filter(isRangeFilter);
});
}

Expand Down Expand Up @@ -181,11 +203,13 @@ const handleCourierRequest = async ({

(searchSource as any).finalResponse = resp;

const parsedTimeRange = timeRange ? getTime(aggs.indexPattern, timeRange) : null;
const parsedTimeRange = timeRange ? calculateBounds(timeRange) : null;
const tabifyParams = {
metricsAtAllLevels,
partialRows,
timeRange: parsedTimeRange ? parsedTimeRange.range : undefined,
timeRange: parsedTimeRange
? { from: parsedTimeRange.min, to: parsedTimeRange.max, timeFields: allTimeFields }
: undefined,
};

const tabifyCacheHash = calculateObjectHash({ tabifyAggs: aggs, ...tabifyParams });
Expand Down Expand Up @@ -242,6 +266,11 @@ export const esaggs = (): ExpressionFunctionDefinition<typeof name, Input, Argum
default: '""',
help: '',
},
timeFields: {
types: ['string'],
help: '',
multi: true,
},
},
async fn(input, args, { inspectorAdapters, abortSignal }) {
const indexPatterns = getIndexPatterns();
Expand All @@ -261,9 +290,11 @@ export const esaggs = (): ExpressionFunctionDefinition<typeof name, Input, Argum
const response = await handleCourierRequest({
searchSource,
aggs,
indexPattern,
timeRange: get(input, 'timeRange', undefined),
query: get(input, 'query', undefined),
filters: get(input, 'filters', undefined),
timeFields: args.timeFields,
forceFetch: true,
metricsAtAllLevels: args.metricsAtAllLevels,
partialRows: args.partialRows,
Expand Down
Loading

0 comments on commit 9b65cbd

Please sign in to comment.