mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
[embeddable refactor] initializeTimeRange utility (#179379)
Move timeRange$ logic into reusable `initializeTimeRange` method. --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
c04de5edaf
commit
61047aead0
5 changed files with 247 additions and 37 deletions
|
@ -9,9 +9,7 @@
|
|||
import { EuiCallOut } from '@elastic/eui';
|
||||
import { DataView } from '@kbn/data-views-plugin/common';
|
||||
import { ReactEmbeddableFactory } from '@kbn/embeddable-plugin/public';
|
||||
import { TimeRange } from '@kbn/es-query';
|
||||
import { useBatchedPublishingSubjects } from '@kbn/presentation-publishing';
|
||||
import fastIsEqual from 'fast-deep-equal';
|
||||
import { initializeTimeRange, useBatchedPublishingSubjects } from '@kbn/presentation-publishing';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { BehaviorSubject } from 'rxjs';
|
||||
import { SEARCH_EMBEDDABLE_ID } from './constants';
|
||||
|
@ -24,54 +22,39 @@ export const getSearchEmbeddableFactory = (services: Services) => {
|
|||
deserializeState: (state) => {
|
||||
return state.rawState as State;
|
||||
},
|
||||
buildEmbeddable: async (state, buildApi) => {
|
||||
buildEmbeddable: async (state, buildApi, uuid, parentApi) => {
|
||||
const {
|
||||
appliedTimeRange$,
|
||||
cleanupTimeRange,
|
||||
serializeTimeRange,
|
||||
timeRangeApi,
|
||||
timeRangeComparators,
|
||||
} = initializeTimeRange(state, parentApi);
|
||||
const defaultDataView = await services.dataViews.getDefaultDataView();
|
||||
const timeRange$ = new BehaviorSubject<TimeRange | undefined>(state.timeRange);
|
||||
const dataViews$ = new BehaviorSubject<DataView[] | undefined>(
|
||||
defaultDataView ? [defaultDataView] : undefined
|
||||
);
|
||||
const dataLoading$ = new BehaviorSubject<boolean | undefined>(false);
|
||||
function setTimeRange(nextTimeRange: TimeRange | undefined) {
|
||||
timeRange$.next(nextTimeRange);
|
||||
}
|
||||
|
||||
const api = buildApi(
|
||||
{
|
||||
...timeRangeApi,
|
||||
dataViews: dataViews$,
|
||||
timeRange$,
|
||||
setTimeRange,
|
||||
dataLoading: dataLoading$,
|
||||
serializeState: () => {
|
||||
return {
|
||||
rawState: {
|
||||
timeRange: timeRange$.value,
|
||||
...serializeTimeRange(),
|
||||
},
|
||||
references: [],
|
||||
};
|
||||
},
|
||||
},
|
||||
{
|
||||
timeRange: [timeRange$, setTimeRange, fastIsEqual],
|
||||
...timeRangeComparators,
|
||||
}
|
||||
);
|
||||
|
||||
const appliedTimeRange$ = new BehaviorSubject(
|
||||
timeRange$.value ?? api.parentApi?.timeRange$?.value
|
||||
);
|
||||
const subscriptions = api.timeRange$.subscribe((timeRange) => {
|
||||
appliedTimeRange$.next(timeRange ?? api.parentApi?.timeRange$?.value);
|
||||
});
|
||||
if (api.parentApi?.timeRange$) {
|
||||
subscriptions.add(
|
||||
api.parentApi?.timeRange$.subscribe((parentTimeRange) => {
|
||||
if (timeRange$?.value) {
|
||||
return;
|
||||
}
|
||||
appliedTimeRange$.next(parentTimeRange);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
api,
|
||||
Component: () => {
|
||||
|
@ -85,7 +68,7 @@ export const getSearchEmbeddableFactory = (services: Services) => {
|
|||
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
subscriptions.unsubscribe();
|
||||
cleanupTimeRange();
|
||||
};
|
||||
}, []);
|
||||
|
||||
|
|
|
@ -76,7 +76,8 @@ export {
|
|||
type PublishesTimeRange,
|
||||
type PublishesUnifiedSearch,
|
||||
type PublishesWritableUnifiedSearch,
|
||||
} from './interfaces/publishes_unified_search';
|
||||
} from './interfaces/unified_search/publishes_unified_search';
|
||||
export { initializeTimeRange } from './interfaces/unified_search/initialize_time_range';
|
||||
export {
|
||||
apiPublishesSavedObjectId,
|
||||
useSavedObjectId,
|
||||
|
|
|
@ -0,0 +1,148 @@
|
|||
/*
|
||||
* 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 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { TimeRange } from '@kbn/es-query';
|
||||
import { BehaviorSubject, skip } from 'rxjs';
|
||||
import { initializeTimeRange } from './initialize_time_range';
|
||||
|
||||
describe('initialize time range', () => {
|
||||
describe('appliedTimeRange$', () => {
|
||||
let timeRange: TimeRange | undefined;
|
||||
const parentApi = {
|
||||
timeRange$: new BehaviorSubject<TimeRange | undefined>(undefined),
|
||||
};
|
||||
|
||||
describe('local and parent time range', () => {
|
||||
beforeEach(() => {
|
||||
timeRange = {
|
||||
from: 'now-15m',
|
||||
to: 'now',
|
||||
};
|
||||
parentApi.timeRange$.next({
|
||||
from: 'now-24h',
|
||||
to: 'now',
|
||||
});
|
||||
});
|
||||
|
||||
it('should return local time range', () => {
|
||||
const { appliedTimeRange$ } = initializeTimeRange({ timeRange }, parentApi);
|
||||
expect(appliedTimeRange$.value).toEqual({
|
||||
from: 'now-15m',
|
||||
to: 'now',
|
||||
});
|
||||
});
|
||||
|
||||
it('should emit when local time range changes', async () => {
|
||||
let emitCount = 0;
|
||||
const { appliedTimeRange$, timeRangeApi } = initializeTimeRange({ timeRange }, parentApi);
|
||||
|
||||
const subscribe = appliedTimeRange$.pipe(skip(1)).subscribe(() => {
|
||||
emitCount++;
|
||||
});
|
||||
|
||||
timeRangeApi.setTimeRange({
|
||||
from: 'now-16m',
|
||||
to: 'now',
|
||||
});
|
||||
await new Promise(process.nextTick);
|
||||
|
||||
expect(emitCount).toBe(1);
|
||||
expect(appliedTimeRange$.value).toEqual({
|
||||
from: 'now-16m',
|
||||
to: 'now',
|
||||
});
|
||||
|
||||
subscribe.unsubscribe();
|
||||
});
|
||||
|
||||
it('should not emit when parent time range changes', async () => {
|
||||
let emitCount = 0;
|
||||
const { appliedTimeRange$ } = initializeTimeRange({ timeRange }, parentApi);
|
||||
|
||||
const subscribe = appliedTimeRange$.pipe(skip(1)).subscribe(() => {
|
||||
emitCount++;
|
||||
});
|
||||
|
||||
parentApi.timeRange$.next({
|
||||
from: 'now-25h',
|
||||
to: 'now',
|
||||
});
|
||||
await new Promise(process.nextTick);
|
||||
|
||||
expect(emitCount).toBe(0);
|
||||
expect(appliedTimeRange$.value).toEqual({
|
||||
from: 'now-15m',
|
||||
to: 'now',
|
||||
});
|
||||
|
||||
subscribe.unsubscribe();
|
||||
});
|
||||
|
||||
it('should emit parent time range when local time range is cleared', async () => {
|
||||
let emitCount = 0;
|
||||
const { appliedTimeRange$, timeRangeApi } = initializeTimeRange({ timeRange }, parentApi);
|
||||
|
||||
const subscribe = appliedTimeRange$.pipe(skip(1)).subscribe(() => {
|
||||
emitCount++;
|
||||
});
|
||||
|
||||
timeRangeApi.setTimeRange(undefined);
|
||||
await new Promise(process.nextTick);
|
||||
|
||||
expect(emitCount).toBe(1);
|
||||
expect(appliedTimeRange$.value).toEqual({
|
||||
from: 'now-24h',
|
||||
to: 'now',
|
||||
});
|
||||
|
||||
subscribe.unsubscribe();
|
||||
});
|
||||
});
|
||||
|
||||
describe('only parent time range', () => {
|
||||
beforeEach(() => {
|
||||
timeRange = undefined;
|
||||
parentApi.timeRange$.next({
|
||||
from: 'now-24h',
|
||||
to: 'now',
|
||||
});
|
||||
});
|
||||
|
||||
it('should return parent time range', () => {
|
||||
const { appliedTimeRange$ } = initializeTimeRange({ timeRange }, parentApi);
|
||||
expect(appliedTimeRange$.value).toEqual({
|
||||
from: 'now-24h',
|
||||
to: 'now',
|
||||
});
|
||||
});
|
||||
|
||||
it('should emit when parent time range changes', async () => {
|
||||
let emitCount = 0;
|
||||
const { appliedTimeRange$ } = initializeTimeRange({ timeRange }, parentApi);
|
||||
|
||||
const subscribe = appliedTimeRange$.pipe(skip(1)).subscribe(() => {
|
||||
emitCount++;
|
||||
});
|
||||
|
||||
parentApi.timeRange$.next({
|
||||
from: 'now-25h',
|
||||
to: 'now',
|
||||
});
|
||||
await new Promise(process.nextTick);
|
||||
|
||||
expect(emitCount).toBe(1);
|
||||
expect(appliedTimeRange$.value).toEqual({
|
||||
from: 'now-25h',
|
||||
to: 'now',
|
||||
});
|
||||
|
||||
subscribe.unsubscribe();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
* 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 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { BehaviorSubject } from 'rxjs';
|
||||
import fastIsEqual from 'fast-deep-equal';
|
||||
import { TimeRange } from '@kbn/es-query';
|
||||
import { PublishingSubject } from '../../publishing_subject';
|
||||
import { StateComparators } from '../../comparators';
|
||||
import {
|
||||
apiPublishesTimeRange,
|
||||
PublishesTimeRange,
|
||||
PublishesWritableTimeRange,
|
||||
} from './publishes_unified_search';
|
||||
|
||||
export interface SerializedTimeRange {
|
||||
timeRange: TimeRange | undefined;
|
||||
}
|
||||
|
||||
export const initializeTimeRange = (
|
||||
rawState: SerializedTimeRange,
|
||||
parentApi?: unknown
|
||||
): {
|
||||
appliedTimeRange$: PublishingSubject<TimeRange | undefined>;
|
||||
cleanupTimeRange: () => void;
|
||||
serializeTimeRange: () => SerializedTimeRange;
|
||||
timeRangeApi: PublishesWritableTimeRange;
|
||||
timeRangeComparators: StateComparators<SerializedTimeRange>;
|
||||
} => {
|
||||
const timeRange$ = new BehaviorSubject<TimeRange | undefined>(rawState.timeRange);
|
||||
function setTimeRange(nextTimeRange: TimeRange | undefined) {
|
||||
timeRange$.next(nextTimeRange);
|
||||
}
|
||||
const appliedTimeRange$ = new BehaviorSubject(
|
||||
timeRange$.value ?? (parentApi as Partial<PublishesTimeRange>)?.timeRange$?.value
|
||||
);
|
||||
|
||||
const subscriptions = timeRange$.subscribe((timeRange) => {
|
||||
appliedTimeRange$.next(
|
||||
timeRange ?? (parentApi as Partial<PublishesTimeRange>)?.timeRange$?.value
|
||||
);
|
||||
});
|
||||
if (apiPublishesTimeRange(parentApi)) {
|
||||
subscriptions.add(
|
||||
parentApi?.timeRange$.subscribe((parentTimeRange) => {
|
||||
if (timeRange$?.value) {
|
||||
return;
|
||||
}
|
||||
appliedTimeRange$.next(parentTimeRange);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
appliedTimeRange$,
|
||||
cleanupTimeRange: () => {
|
||||
subscriptions.unsubscribe();
|
||||
},
|
||||
serializeTimeRange: () => ({
|
||||
timeRange: timeRange$.value,
|
||||
}),
|
||||
timeRangeComparators: {
|
||||
timeRange: [timeRange$, setTimeRange, fastIsEqual],
|
||||
} as StateComparators<SerializedTimeRange>,
|
||||
timeRangeApi: {
|
||||
timeRange$,
|
||||
setTimeRange,
|
||||
},
|
||||
};
|
||||
};
|
|
@ -7,23 +7,27 @@
|
|||
*/
|
||||
|
||||
import { TimeRange, Filter, Query, AggregateQuery } from '@kbn/es-query';
|
||||
import { PublishingSubject } from '../publishing_subject';
|
||||
import { PublishingSubject } from '../../publishing_subject';
|
||||
|
||||
export interface PublishesTimeRange {
|
||||
timeRange$: PublishingSubject<TimeRange | undefined>;
|
||||
}
|
||||
|
||||
export type PublishesWritableTimeRange = PublishesTimeRange & {
|
||||
setTimeRange: (timeRange: TimeRange | undefined) => void;
|
||||
};
|
||||
|
||||
export type PublishesUnifiedSearch = PublishesTimeRange & {
|
||||
isCompatibleWithUnifiedSearch?: () => boolean;
|
||||
filters$: PublishingSubject<Filter[] | undefined>;
|
||||
query$: PublishingSubject<Query | AggregateQuery | undefined>;
|
||||
};
|
||||
|
||||
export type PublishesWritableUnifiedSearch = PublishesUnifiedSearch & {
|
||||
setTimeRange: (timeRange: TimeRange | undefined) => void;
|
||||
setFilters: (filters: Filter[] | undefined) => void;
|
||||
setQuery: (query: Query | undefined) => void;
|
||||
};
|
||||
export type PublishesWritableUnifiedSearch = PublishesUnifiedSearch &
|
||||
PublishesWritableTimeRange & {
|
||||
setFilters: (filters: Filter[] | undefined) => void;
|
||||
setQuery: (query: Query | undefined) => void;
|
||||
};
|
||||
|
||||
export const apiPublishesTimeRange = (
|
||||
unknownApi: null | unknown
|
Loading…
Add table
Add a link
Reference in a new issue