Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import { i18n } from '@kbn/i18n';
import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public';
import { Storage } from '@kbn/kibana-utils-plugin/public';
import {
initializeUnsavedChanges,
initializeTimeRangeManager,
initializeTitleManager,
timeRangeComparators,
Expand All @@ -38,7 +37,7 @@ export const getDataTableFactory = (
services: StartDeps
): EmbeddableFactory<DataTableSerializedState, DataTableApi> => ({
type: DATA_TABLE_ID,
buildEmbeddable: async ({ initialState, finalizeApi, parentApi, uuid }) => {
buildEmbeddable: async ({ initialState, initializeStateApi, finalizeApi, parentApi, uuid }) => {
const state = initialState;
const timeRangeManager = initializeTimeRangeManager(state);
const dataLoading$ = new BehaviorSubject<boolean | undefined>(true);
Expand All @@ -60,9 +59,7 @@ export const getDataTableFactory = (
};
};

const unsavedChangesApi = initializeUnsavedChanges<DataTableSerializedState>({
uuid,
parentApi,
const containerLinkApi = initializeStateApi({
serializeState,
anyStateChange$: merge(titleManager.anyStateChange$, timeRangeManager.anyStateChange$),
getComparators: () => {
Expand All @@ -71,18 +68,17 @@ export const getDataTableFactory = (
...timeRangeComparators,
};
},
onReset: (lastSaved) => {
timeRangeManager.reinitializeState(lastSaved);
titleManager.reinitializeState(lastSaved);
applySerializedState: (nextState) => {
timeRangeManager.reinitializeState(nextState);
titleManager.reinitializeState(nextState);
},
});

const api = finalizeApi({
...timeRangeManager.api,
...titleManager.api,
...unsavedChangesApi,
...containerLinkApi,
dataLoading$,
serializeState,
});

const queryService = await initializeDataTableQueries(services, api, dataLoading$);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import {
initializeTitleManager,
titleComparators,
useBatchedPublishingSubjects,
initializeUnsavedChanges,
} from '@kbn/presentation-publishing';
import { LazyDataViewPicker, withSuspense } from '@kbn/presentation-util-plugin/public';
import {
Expand Down Expand Up @@ -85,7 +84,7 @@ export const getFieldListFactory = (
) => {
const fieldListEmbeddableFactory: EmbeddableFactory<FieldListSerializedState, FieldListApi> = {
type: FIELD_LIST_ID,
buildEmbeddable: async ({ initialState, finalizeApi, parentApi, uuid }) => {
buildEmbeddable: async ({ initialState, finalizeApi, initializeStateApi }) => {
const state = await deserializeState(dataViews, initialState);
const allDataViews = await dataViews.getIdsWithTitle();
const subscriptions = new Subscription();
Expand Down Expand Up @@ -117,19 +116,17 @@ export const getFieldListFactory = (
};
}

const unsavedChangesApi = initializeUnsavedChanges<FieldListSerializedState>({
uuid,
parentApi,
serializeState,
const stateApi = initializeStateApi({
anyStateChange$: merge(titleManager.anyStateChange$, fieldListStateManager.anyStateChange$),
getComparators: () => ({
...titleComparators,
selectedFieldNames: (a, b) => {
selectedFieldNames: (a: string[] | undefined, b: string[] | undefined) => {
return (a?.slice().sort().join(',') ?? '') === (b?.slice().sort().join(',') ?? '');
},
dataViewId: 'referenceEquality',
}),
onReset: async (lastSaved) => {
serializeState,
applySerializedState: async (lastSaved: FieldListSerializedState | undefined) => {
const lastState = await deserializeState(dataViews, lastSaved);
fieldListStateManager.reinitializeState(lastState);
titleManager.reinitializeState(lastSaved);
Expand All @@ -138,8 +135,7 @@ export const getFieldListFactory = (

const api = finalizeApi({
...titleManager.api,
...unsavedChangesApi,
serializeState,
...stateApi,
});

return {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ import {
initializeStateManager,
titleComparators,
apiIsPresentationContainer,
initializeUnsavedChanges,
} from '@kbn/presentation-publishing';
import React from 'react';
import { merge } from 'rxjs';
Expand All @@ -50,7 +49,7 @@ const bookStateComparators: StateComparators<BookState> = {
export const getSavedBookEmbeddableFactory = (core: CoreStart) => {
const savedBookEmbeddableFactory: EmbeddableFactory<BookEmbeddableState, BookApi> = {
type: BOOK_EMBEDDABLE_TYPE,
buildEmbeddable: async ({ initialState, finalizeApi, parentApi, uuid }) => {
buildEmbeddable: async ({ initialState, finalizeApi, initializeStateApi }) => {
const titleManager = initializeTitleManager(initialState);
const savedObjectId = (initialState as BookByReferenceState).savedObjectId;
const initialBookState = savedObjectId ? await loadBook(savedObjectId) : initialState;
Expand All @@ -65,12 +64,7 @@ export const getSavedBookEmbeddableFactory = (core: CoreStart) => {
...(id ? { savedObjectId: id } : bookStateManager.getLatestState()),
});

const serializeState = () => serializeBook(savedObjectId);

const unsavedChangesApi = initializeUnsavedChanges<BookEmbeddableState>({
uuid,
parentApi,
serializeState,
const stateApi = initializeStateApi({
anyStateChange$: merge(titleManager.anyStateChange$, bookStateManager.anyStateChange$),
getComparators: () => {
return {
Expand All @@ -79,14 +73,15 @@ export const getSavedBookEmbeddableFactory = (core: CoreStart) => {
savedObjectId: 'skip', // saved book id will not change over the lifetime of the embeddable.
};
},
onReset: async (lastSaved) => {
titleManager.reinitializeState(lastSaved);
if (!savedObjectId) bookStateManager.reinitializeState(lastSaved as BookState);
serializeState: () => serializeBook(savedObjectId),
applySerializedState: async (nextState) => {
titleManager.reinitializeState(nextState);
if (!savedObjectId) bookStateManager.reinitializeState(nextState as BookState);
},
});

const api = finalizeApi({
...unsavedChangesApi,
...stateApi,
...titleManager.api,
onEdit: async () => {
openLazyFlyout({
Expand Down Expand Up @@ -122,7 +117,6 @@ export const getSavedBookEmbeddableFactory = (core: CoreStart) => {
i18n.translate('embeddableExamples.savedbook.editBook.displayName', {
defaultMessage: 'book',
}),
serializeState,

// library transforms
getSavedObjectId: () => savedObjectId,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import {
initializeTimeRangeManager,
timeRangeComparators,
useBatchedPublishingSubjects,
initializeUnsavedChanges,
} from '@kbn/presentation-publishing';
import React, { useEffect } from 'react';
import { BehaviorSubject, switchMap, tap } from 'rxjs';
Expand All @@ -28,7 +27,7 @@ import type { SearchApi, Services, SearchSerializedState } from './types';
export const getSearchEmbeddableFactory = (services: Services) => {
const factory: EmbeddableFactory<SearchSerializedState, SearchApi> = {
type: SEARCH_EMBEDDABLE_TYPE,
buildEmbeddable: async ({ initialState, finalizeApi, parentApi, uuid }) => {
buildEmbeddable: async ({ initialState, finalizeApi, initializeStateApi }) => {
const timeRangeManager = initializeTimeRangeManager(initialState);
const defaultDataView = await services.dataViews.getDefaultDataView();
const dataViews$ = new BehaviorSubject<DataView[] | undefined>(
Expand All @@ -53,10 +52,7 @@ export const getSearchEmbeddableFactory = (services: Services) => {
};
}

const unsavedChangesApi = initializeUnsavedChanges({
uuid,
parentApi,
serializeState,
const stateApi = initializeStateApi({
anyStateChange$: timeRangeManager.anyStateChange$,
getComparators: () => {
/**
Expand All @@ -66,23 +62,23 @@ export const getSearchEmbeddableFactory = (services: Services) => {
*/
return timeRangeComparators;
},
onReset: (lastSaved) => {
serializeState,
applySerializedState: (nextState) => {
/**
* if this embeddable had a difference between its runtime and serialized state, we could run the 'deserializeState'
* function here before resetting. onReset can be async so to support a potential async deserialize function.
* function here before applying the state. onReset can be async to support a potential async deserialize function.
*/

timeRangeManager.reinitializeState(lastSaved);
timeRangeManager.reinitializeState(nextState);
},
});

const api = finalizeApi({
blockingError$,
dataViews$,
dataLoading$,
...unsavedChangesApi,
...stateApi,
...timeRangeManager.api,
serializeState,
});

const count$ = new BehaviorSubject<number>(0);
Expand Down
2 changes: 1 addition & 1 deletion packages/kbn-optimizer/limits.yml
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ pageLoadAssetSize:
elasticAssistant: 301540
elasticAssistantSharedState: 4881
elasticConsole: 4451
embeddable: 16634
embeddable: 19659
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I opted to update the limits here manually rather than async importing the function responsible for the increase. This is because the function is required for every embeddable on start up.

An async import of this function would require either an additional bundle, or placement of this function with another module that hosts unrelated code that isn't imported for every embeddable.

This function has been moved from a package import into the embeddable plugin.

embeddableAlertsTable: 6524
enterpriseSearch: 37565
entityStore: 9718
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export {
type ComparatorFunction,
type StateComparators,
type WithAllKeys,
type StateManager,
runComparator,
areComparatorsEqual,
diffComparators,
Expand Down Expand Up @@ -207,9 +208,7 @@ export {
type HasSerializedChildState,
} from './interfaces/containers/child_state';

export { childrenUnsavedChanges$ } from './interfaces/containers/unsaved_changes/children_unsaved_changes';

export { initializeUnsavedChanges } from './interfaces/containers/unsaved_changes/initialize_unsaved_changes';
export { childrenUnsavedChanges$ } from './interfaces/containers/container_state/children_unsaved_changes';

export {
apiCanDuplicatePanels,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,4 @@
export { shouldLogStateDiff, logStateDiff } from './state_diff_logger';
export { areComparatorsEqual, diffComparators, runComparator } from './state_comparators';
export { initializeStateManager } from './state_manager';
export type { ComparatorFunction, StateComparators, WithAllKeys } from './types';
export type { ComparatorFunction, StateComparators, WithAllKeys, StateManager } from './types';
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
import { camelCase } from 'lodash';
import { BehaviorSubject, map, merge } from 'rxjs';
import { runComparator } from './state_comparators';
import type { StateComparators, StateManager, WithAllKeys } from './types';
import type { StateManager, StateManagerInitializer, WithAllKeys } from './types';

type SubjectOf<StateType extends object> = BehaviorSubject<WithAllKeys<StateType>[keyof StateType]>;

Expand All @@ -29,9 +29,9 @@ type KeyToSubjectMap<StateType extends object> = {
* @param comparators - Optional StateComparators. When provided, subject will only emit when value changes.
*/
export const initializeStateManager = <StateType extends object>(
initialState: Partial<StateType>,
defaultState: WithAllKeys<StateType>,
comparators?: StateComparators<StateType>
initialState: StateManagerInitializer<StateType>['initialState'],
defaultState: StateManagerInitializer<StateType>['defaultState'],
comparators?: StateManagerInitializer<StateType>['comparators']
): StateManager<StateType> => {
const allState = { ...defaultState, ...initialState };
const allSubjects: Array<SubjectOf<StateType>> = [];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,12 @@ import type { SnakeToCamelCase } from '../utils/types';

export type WithAllKeys<T extends object> = { [Key in keyof Required<T>]: T[Key] };

export interface StateManagerInitializer<StateType extends object> {
initialState: Partial<StateType>;
defaultState: WithAllKeys<StateType>;
comparators?: StateComparators<StateType>;
}

export type ComparatorFunction<StateType, KeyType extends keyof StateType> = (
last: StateType[KeyType] | undefined,
current: StateType[KeyType] | undefined,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,7 @@ import { BehaviorSubject, map, merge } from 'rxjs';
import type { EmbeddableFactory } from '@kbn/embeddable-plugin/public';
import { i18n } from '@kbn/i18n';
import { openLazyFlyout } from '@kbn/presentation-util';
import {
initializeUnsavedChanges,
initializeTitleManager,
titleComparators,
} from '@kbn/presentation-publishing';
import { initializeTitleManager, titleComparators } from '@kbn/presentation-publishing';

import type { ImageEmbeddableState } from '../../server';
import { ImageEmbeddable as ImageEmbeddableComponent } from '../components/image_embeddable';
Expand All @@ -31,10 +27,11 @@ export const getImageEmbeddableFactory = () => {
type: IMAGE_EMBEDDABLE_TYPE,
buildEmbeddable: async ({
initializeDrilldownsManager,
initializeStateApi,
initialState,
finalizeApi,
uuid,
parentApi,
uuid,
}) => {
const titleManager = initializeTitleManager(initialState);

Expand All @@ -44,18 +41,7 @@ export const getImageEmbeddableFactory = () => {
const imageConfig$ = new BehaviorSubject<ImageConfig>(initialState.image_config);
const dataLoading$ = new BehaviorSubject<boolean | undefined>(true);

function serializeState() {
return {
...titleManager.getLatestState(),
...drilldownsManager.getLatestState(),
image_config: imageConfig$.getValue(),
};
}

const unsavedChangesApi = initializeUnsavedChanges<ImageEmbeddableState>({
uuid,
parentApi,
serializeState,
const stateApi = initializeStateApi({
anyStateChange$: merge(
titleManager.anyStateChange$,
imageConfig$.pipe(map(() => undefined)),
Expand All @@ -68,17 +54,22 @@ export const getImageEmbeddableFactory = () => {
image_config: 'deepEquality',
};
},
onReset: (lastSaved) => {
titleManager.reinitializeState(lastSaved);
drilldownsManager.reinitializeState(lastSaved ?? {});
if (lastSaved) imageConfig$.next(lastSaved.image_config);
serializeState: () => ({
...titleManager.getLatestState(),
...drilldownsManager.getLatestState(),
image_config: imageConfig$.getValue(),
}),
applySerializedState: (nextState) => {
titleManager.reinitializeState(nextState);
drilldownsManager.reinitializeState(nextState ?? {});
if (nextState) imageConfig$.next(nextState.image_config);
},
});

const embeddable = finalizeApi({
...titleManager.api,
...drilldownsManager.api,
...unsavedChangesApi,
...stateApi,
dataLoading$,
supportedTriggers: () => IMAGE_EMBEDDABLE_SUPPORTED_TRIGGERS,

Expand Down Expand Up @@ -106,7 +97,6 @@ export const getImageEmbeddableFactory = () => {
i18n.translate('imageEmbeddable.imageEmbeddableFactory.displayName.edit', {
defaultMessage: 'image',
}),
serializeState,
});
return {
api: embeddable,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import type { Link } from '../../server';
import type { LinksApi, ResolvedLink } from '../types';
import { linksClient } from '../content_management';
import { getMockLinksParentApi } from '../mocks';
import { getMockinitializeStateApi } from '@kbn/embeddable-plugin/public/mocks';

const getLinks = (): Link[] => [
{
Expand Down Expand Up @@ -116,6 +117,7 @@ async function buildLinksEmbeddable(state: LinksEmbeddableState) {
type: LINKS_EMBEDDABLE_TYPE,
} as LinksApi;
},
initializeStateApi: getMockinitializeStateApi(factory),
parentApi,
uuid,
});
Expand Down
Loading
Loading