Skip to content

Commit d3303f2

Browse files
authored
[Search] Search Sessions with relative time range (#84405)
1 parent 02695ef commit d3303f2

File tree

48 files changed

+672
-276
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+672
-276
lines changed

docs/development/plugins/data/public/kibana-plugin-plugins-data-public.datapublicpluginstart.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ export interface DataPublicPluginStart
2020
| [autocomplete](./kibana-plugin-plugins-data-public.datapublicpluginstart.autocomplete.md) | <code>AutocompleteStart</code> | autocomplete service [AutocompleteStart](./kibana-plugin-plugins-data-public.autocompletestart.md) |
2121
| [fieldFormats](./kibana-plugin-plugins-data-public.datapublicpluginstart.fieldformats.md) | <code>FieldFormatsStart</code> | field formats service [FieldFormatsStart](./kibana-plugin-plugins-data-public.fieldformatsstart.md) |
2222
| [indexPatterns](./kibana-plugin-plugins-data-public.datapublicpluginstart.indexpatterns.md) | <code>IndexPatternsContract</code> | index patterns service [IndexPatternsContract](./kibana-plugin-plugins-data-public.indexpatternscontract.md) |
23+
| [nowProvider](./kibana-plugin-plugins-data-public.datapublicpluginstart.nowprovider.md) | <code>NowProviderPublicContract</code> | |
2324
| [query](./kibana-plugin-plugins-data-public.datapublicpluginstart.query.md) | <code>QueryStart</code> | query service [QueryStart](./kibana-plugin-plugins-data-public.querystart.md) |
2425
| [search](./kibana-plugin-plugins-data-public.datapublicpluginstart.search.md) | <code>ISearchStart</code> | search service [ISearchStart](./kibana-plugin-plugins-data-public.isearchstart.md) |
2526
| [ui](./kibana-plugin-plugins-data-public.datapublicpluginstart.ui.md) | <code>DataPublicPluginStartUi</code> | prewired UI components [DataPublicPluginStartUi](./kibana-plugin-plugins-data-public.datapublicpluginstartui.md) |
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
2+
3+
[Home](./index.md) &gt; [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) &gt; [DataPublicPluginStart](./kibana-plugin-plugins-data-public.datapublicpluginstart.md) &gt; [nowProvider](./kibana-plugin-plugins-data-public.datapublicpluginstart.nowprovider.md)
4+
5+
## DataPublicPluginStart.nowProvider property
6+
7+
<b>Signature:</b>
8+
9+
```typescript
10+
nowProvider: NowProviderPublicContract;
11+
```

src/plugins/dashboard/public/application/dashboard_app.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,10 +173,14 @@ export function DashboardApp({
173173
).subscribe(() => refreshDashboardContainer())
174174
);
175175
subscriptions.add(
176-
data.search.session.onRefresh$.subscribe(() => {
176+
merge(
177+
data.search.session.onRefresh$,
178+
data.query.timefilter.timefilter.getAutoRefreshFetch$()
179+
).subscribe(() => {
177180
setLastReloadTime(() => new Date().getTime());
178181
})
179182
);
183+
180184
dashboardStateManager.registerChangeListener(() => {
181185
// we aren't checking dirty state because there are changes the container needs to know about
182186
// that won't make the dashboard "dirty" - like a view mode change.

src/plugins/dashboard/public/application/lib/session_restoration.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,17 +43,22 @@ function getUrlGeneratorState({
4343
data,
4444
getAppState,
4545
getDashboardId,
46-
forceAbsoluteTime, // TODO: not implemented
46+
forceAbsoluteTime,
4747
}: {
4848
data: DataPublicPluginStart;
4949
getAppState: () => DashboardAppState;
5050
getDashboardId: () => string;
51+
/**
52+
* Can force time range from time filter to convert from relative to absolute time range
53+
*/
5154
forceAbsoluteTime: boolean;
5255
}): DashboardUrlGeneratorState {
5356
const appState = getAppState();
5457
return {
5558
dashboardId: getDashboardId(),
56-
timeRange: data.query.timefilter.timefilter.getTime(),
59+
timeRange: forceAbsoluteTime
60+
? data.query.timefilter.timefilter.getAbsoluteTime()
61+
: data.query.timefilter.timefilter.getTime(),
5762
filters: data.query.filterManager.getFilters(),
5863
query: data.query.queryString.formatQuery(appState.query),
5964
savedQuery: appState.savedQuery,

src/plugins/data/common/query/timefilter/get_time.test.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919

2020
import moment from 'moment';
2121
import sinon from 'sinon';
22-
import { getTime } from './get_time';
22+
import { getTime, getAbsoluteTimeRange } from './get_time';
2323

2424
describe('get_time', () => {
2525
describe('getTime', () => {
@@ -90,4 +90,19 @@ describe('get_time', () => {
9090
clock.restore();
9191
});
9292
});
93+
describe('getAbsoluteTimeRange', () => {
94+
test('should forward absolute timerange as is', () => {
95+
const from = '2000-01-01T00:00:00.000Z';
96+
const to = '2000-02-01T00:00:00.000Z';
97+
expect(getAbsoluteTimeRange({ from, to })).toEqual({ from, to });
98+
});
99+
100+
test('should convert relative to absolute', () => {
101+
const clock = sinon.useFakeTimers(moment.utc([2000, 1, 0, 0, 0, 0, 0]).valueOf());
102+
const from = '2000-01-01T00:00:00.000Z';
103+
const to = moment.utc(clock.now).toISOString();
104+
expect(getAbsoluteTimeRange({ from, to: 'now' })).toEqual({ from, to });
105+
clock.restore();
106+
});
107+
});
93108
});

src/plugins/data/common/query/timefilter/get_time.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,17 @@ export function calculateBounds(
3434
};
3535
}
3636

37+
export function getAbsoluteTimeRange(
38+
timeRange: TimeRange,
39+
{ forceNow }: { forceNow?: Date } = {}
40+
): TimeRange {
41+
const { min, max } = calculateBounds(timeRange, { forceNow });
42+
return {
43+
from: min ? min.toISOString() : timeRange.from,
44+
to: max ? max.toISOString() : timeRange.to,
45+
};
46+
}
47+
3748
export function getTime(
3849
indexPattern: IIndexPattern | undefined,
3950
timeRange: TimeRange,

src/plugins/data/common/search/expressions/esaggs/esaggs_fn.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ export interface EsaggsStartDependencies {
6262
deserializeFieldFormat: FormatFactory;
6363
indexPatterns: IndexPatternsContract;
6464
searchSource: ISearchStartSearchSource;
65+
getNow?: () => Date;
6566
}
6667

6768
/** @internal */
@@ -118,7 +119,8 @@ export async function handleEsaggsRequest(
118119
args: Arguments,
119120
params: RequestHandlerParams
120121
): Promise<Datatable> {
121-
const resolvedTimeRange = input?.timeRange && calculateBounds(input.timeRange);
122+
const resolvedTimeRange =
123+
input?.timeRange && calculateBounds(input.timeRange, { forceNow: params.getNow?.() });
122124

123125
const response = await handleRequest(params);
124126

src/plugins/data/common/search/expressions/esaggs/request_handler.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ export interface RequestHandlerParams {
5151
searchSourceService: ISearchStartSearchSource;
5252
timeFields?: string[];
5353
timeRange?: TimeRange;
54+
getNow?: () => Date;
5455
}
5556

5657
export const handleRequest = async ({
@@ -67,7 +68,9 @@ export const handleRequest = async ({
6768
searchSourceService,
6869
timeFields,
6970
timeRange,
71+
getNow,
7072
}: RequestHandlerParams) => {
73+
const forceNow = getNow?.();
7174
const searchSource = await searchSourceService.create();
7275

7376
searchSource.setField('index', indexPattern);
@@ -115,7 +118,7 @@ export const handleRequest = async ({
115118
if (timeRange && allTimeFields.length > 0) {
116119
timeFilterSearchSource.setField('filter', () => {
117120
return allTimeFields
118-
.map((fieldName) => getTime(indexPattern, timeRange, { fieldName }))
121+
.map((fieldName) => getTime(indexPattern, timeRange, { fieldName, forceNow }))
119122
.filter(isRangeFilter);
120123
});
121124
}
@@ -183,7 +186,7 @@ export const handleRequest = async ({
183186
}
184187
}
185188

186-
const parsedTimeRange = timeRange ? calculateBounds(timeRange) : null;
189+
const parsedTimeRange = timeRange ? calculateBounds(timeRange, { forceNow }) : null;
187190
const tabifyParams = {
188191
metricsAtAllLevels,
189192
partialRows,

src/plugins/data/public/mocks.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import { fieldFormatsServiceMock } from './field_formats/mocks';
2222
import { searchServiceMock } from './search/mocks';
2323
import { queryServiceMock } from './query/mocks';
2424
import { AutocompleteStart, AutocompleteSetup } from './autocomplete';
25+
import { createNowProviderMock } from './now_provider/mocks';
2526

2627
export type Setup = jest.Mocked<ReturnType<Plugin['setup']>>;
2728
export type Start = jest.Mocked<ReturnType<Plugin['start']>>;
@@ -76,6 +77,7 @@ const createStartContract = (): Start => {
7677
get: jest.fn().mockReturnValue(Promise.resolve({})),
7778
clearCache: jest.fn(),
7879
} as unknown) as IndexPatternsContract,
80+
nowProvider: createNowProviderMock(),
7981
};
8082
};
8183

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/*
2+
* Licensed to Elasticsearch B.V. under one or more contributor
3+
* license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright
5+
* ownership. Elasticsearch B.V. licenses this file to you under
6+
* the Apache License, Version 2.0 (the "License"); you may
7+
* not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
export {
21+
NowProvider,
22+
NowProviderInternalContract,
23+
NowProviderPublicContract,
24+
} from './now_provider';

0 commit comments

Comments
 (0)