Skip to content

Commit

Permalink
[Logs UI] Use the Unified Search Bar for date range selection (#144351)
Browse files Browse the repository at this point in the history
This enables the date-picker of the unified search bar introduced into the Logs UI in #143222 and simultaneously removes the custom date picker.

closes #142767
  • Loading branch information
weltenwort authored Nov 9, 2022
1 parent 59f2ff5 commit c88a680
Show file tree
Hide file tree
Showing 24 changed files with 1,285 additions and 489 deletions.
1 change: 1 addition & 0 deletions src/plugins/kibana_utils/public/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ export {
replaceUrlHashQuery,
} from './state_management/url';
export type {
IStateStorage,
IStateSyncConfig,
ISyncStateRef,
IKbnUrlStateStorage,
Expand Down
25 changes: 19 additions & 6 deletions x-pack/plugins/infra/common/time/time_key.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,23 @@
*/

import { ascending, bisector } from 'd3-array';
import * as rt from 'io-ts';
import { pick } from 'lodash';

export interface TimeKey {
time: number;
tiebreaker: number;
gid?: string;
fromAutoReload?: boolean;
}
export const minimalTimeKeyRT = rt.type({
time: rt.number,
tiebreaker: rt.number,
});
export type MinimalTimeKey = rt.TypeOf<typeof minimalTimeKeyRT>;

export const timeKeyRT = rt.intersection([
minimalTimeKeyRT,
rt.partial({
gid: rt.string,
fromAutoReload: rt.boolean,
}),
]);
export type TimeKey = rt.TypeOf<typeof timeKeyRT>;

export interface UniqueTimeKey extends TimeKey {
gid: string;
Expand Down Expand Up @@ -95,3 +104,7 @@ export const getNextTimeKey = (timeKey: TimeKey) => ({
time: timeKey.time,
tiebreaker: timeKey.tiebreaker + 1,
});

export const isSameTimeKey = (firstKey: TimeKey | null, secondKey: TimeKey | null): boolean =>
firstKey === secondKey ||
(firstKey != null && secondKey != null && compareTimeKeys(firstKey, secondKey) === 0);
16 changes: 11 additions & 5 deletions x-pack/plugins/infra/public/apps/logs_app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { LogsPage } from '../pages/logs';
import { InfraClientStartDeps, InfraClientStartExports } from '../types';
import { CommonInfraProviders, CoreProviders } from './common_providers';
import { prepareMountElement } from './common_styles';
import { KbnUrlStateStorageFromRouterProvider } from '../utils/kbn_url_state_context';

export const renderApp = (
core: CoreStart,
Expand Down Expand Up @@ -69,11 +70,16 @@ const LogsApp: React.FC<{
triggersActionsUI={plugins.triggersActionsUi}
>
<Router history={history}>
<Switch>
<Route path="/link-to" component={LinkToLogsPage} />
{uiCapabilities?.logs?.show && <Route path="/" component={LogsPage} />}
<Route component={NotFoundPage} />
</Switch>
<KbnUrlStateStorageFromRouterProvider
history={history}
toastsService={core.notifications.toasts}
>
<Switch>
<Route path="/link-to" component={LinkToLogsPage} />
{uiCapabilities?.logs?.show && <Route path="/" component={LogsPage} />}
<Route component={NotFoundPage} />
</Switch>
</KbnUrlStateStorageFromRouterProvider>
</Router>
</CommonInfraProviders>
</CoreProviders>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,6 @@
*/

export * from './log_position_state';
export * from './with_log_position_url_state';
export * from './replace_log_position_in_query_string';
export * from './use_log_position';
export type { LogPositionUrlState } from './use_log_position_url_state_sync';
Original file line number Diff line number Diff line change
@@ -0,0 +1,287 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import moment from 'moment';
import { createInitialLogPositionState, updateStateFromUrlState } from './log_position_state';

describe('function createInitialLogPositionState', () => {
it('initializes state without url and timefilter', () => {
const initialState = createInitialLogPositionState({
initialStateFromUrl: null,
initialStateFromTimefilter: null,
now: getTestMoment().toDate(),
});

expect(initialState).toMatchInlineSnapshot(`
Object {
"latestPosition": null,
"refreshInterval": Object {
"pause": true,
"value": 5000,
},
"targetPosition": null,
"timeRange": Object {
"expression": Object {
"from": "now-1d",
"to": "now",
},
"lastChangedCompletely": 1640995200000,
},
"timestamps": Object {
"endTimestamp": 1640995200000,
"lastChangedTimestamp": 1640995200000,
"startTimestamp": 1640908800000,
},
"visiblePositions": Object {
"endKey": null,
"middleKey": null,
"pagesAfterEnd": Infinity,
"pagesBeforeStart": Infinity,
"startKey": null,
},
}
`);
});

it('initializes state from complete url state', () => {
const initialState = createInitialLogPositionState({
initialStateFromUrl: {
start: 'now-2d',
end: 'now-1d',
position: {
time: getTestMoment().subtract(36, 'hours').valueOf(),
tiebreaker: 0,
},
streamLive: false,
},
initialStateFromTimefilter: null,
now: getTestMoment().toDate(),
});

expect(initialState).toMatchInlineSnapshot(`
Object {
"latestPosition": Object {
"tiebreaker": 0,
"time": 1640865600000,
},
"refreshInterval": Object {
"pause": true,
"value": 5000,
},
"targetPosition": Object {
"tiebreaker": 0,
"time": 1640865600000,
},
"timeRange": Object {
"expression": Object {
"from": "now-2d",
"to": "now-1d",
},
"lastChangedCompletely": 1640995200000,
},
"timestamps": Object {
"endTimestamp": 1640908800000,
"lastChangedTimestamp": 1640995200000,
"startTimestamp": 1640822400000,
},
"visiblePositions": Object {
"endKey": null,
"middleKey": null,
"pagesAfterEnd": Infinity,
"pagesBeforeStart": Infinity,
"startKey": null,
},
}
`);
});

it('initializes state from from url state with just a time range', () => {
const initialState = createInitialLogPositionState({
initialStateFromUrl: {
start: 'now-2d',
end: 'now-1d',
},
initialStateFromTimefilter: null,
now: getTestMoment().toDate(),
});

expect(initialState).toMatchInlineSnapshot(`
Object {
"latestPosition": null,
"refreshInterval": Object {
"pause": true,
"value": 5000,
},
"targetPosition": null,
"timeRange": Object {
"expression": Object {
"from": "now-2d",
"to": "now-1d",
},
"lastChangedCompletely": 1640995200000,
},
"timestamps": Object {
"endTimestamp": 1640908800000,
"lastChangedTimestamp": 1640995200000,
"startTimestamp": 1640822400000,
},
"visiblePositions": Object {
"endKey": null,
"middleKey": null,
"pagesAfterEnd": Infinity,
"pagesBeforeStart": Infinity,
"startKey": null,
},
}
`);
});

it('initializes state from from url state with just a position', () => {
const initialState = createInitialLogPositionState({
initialStateFromUrl: {
position: {
time: getTestMoment().subtract(36, 'hours').valueOf(),
},
},
initialStateFromTimefilter: null,
now: getTestMoment().toDate(),
});

expect(initialState).toMatchInlineSnapshot(`
Object {
"latestPosition": Object {
"tiebreaker": 0,
"time": 1640865600000,
},
"refreshInterval": Object {
"pause": true,
"value": 5000,
},
"targetPosition": Object {
"tiebreaker": 0,
"time": 1640865600000,
},
"timeRange": Object {
"expression": Object {
"from": "2021-12-30T11:00:00.000Z",
"to": "2021-12-30T13:00:00.000Z",
},
"lastChangedCompletely": 1640995200000,
},
"timestamps": Object {
"endTimestamp": 1640869200000,
"lastChangedTimestamp": 1640995200000,
"startTimestamp": 1640862000000,
},
"visiblePositions": Object {
"endKey": null,
"middleKey": null,
"pagesAfterEnd": Infinity,
"pagesBeforeStart": Infinity,
"startKey": null,
},
}
`);
});
});

describe('function updateStateFromUrlState', () => {
it('applies a new target position that is within the date range', () => {
const initialState = createInitialTestState();
const newState = updateStateFromUrlState({
position: {
time: initialState.timestamps.startTimestamp + 1,
tiebreaker: 2,
},
})(initialState);

expect(newState).toEqual({
...initialState,
targetPosition: {
time: initialState.timestamps.startTimestamp + 1,
tiebreaker: 2,
},
latestPosition: {
time: initialState.timestamps.startTimestamp + 1,
tiebreaker: 2,
},
});
});

it('applies a new partial target position that is within the date range', () => {
const initialState = createInitialTestState();
const newState = updateStateFromUrlState({
position: {
time: initialState.timestamps.startTimestamp + 1,
},
})(initialState);

expect(newState).toEqual({
...initialState,
targetPosition: {
time: initialState.timestamps.startTimestamp + 1,
tiebreaker: 0,
},
latestPosition: {
time: initialState.timestamps.startTimestamp + 1,
tiebreaker: 0,
},
});
});

it('rejects a target position that is outside the date range', () => {
const initialState = createInitialTestState();
const newState = updateStateFromUrlState({
position: {
time: initialState.timestamps.startTimestamp - 1,
},
})(initialState);

expect(newState).toEqual({
...initialState,
targetPosition: null,
latestPosition: null,
});
});

it('applies a new time range and updates timestamps', () => {
const initialState = createInitialTestState();
const updateDate = getTestMoment().add(1, 'hour').toDate();
const newState = updateStateFromUrlState(
{
start: 'now-2d',
end: 'now-1d',
},
updateDate
)(initialState);

expect(newState).toEqual({
...initialState,
timeRange: {
expression: {
from: 'now-2d',
to: 'now-1d',
},
lastChangedCompletely: updateDate.valueOf(),
},
timestamps: {
startTimestamp: moment(updateDate).subtract(2, 'day').valueOf(),
endTimestamp: moment(updateDate).subtract(1, 'day').valueOf(),
lastChangedTimestamp: updateDate.valueOf(),
},
});
});
});

const getTestMoment = () => moment.utc('2022-01-01T00:00:00.000Z');

const createInitialTestState = () =>
createInitialLogPositionState({
initialStateFromUrl: null,
initialStateFromTimefilter: null,
now: getTestMoment().toDate(),
});
Loading

0 comments on commit c88a680

Please sign in to comment.