Skip to content
Merged
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 @@ -18,7 +18,7 @@ const createSetupContract = (): Setup => {

const createStartContract = (): Start => {
const startContract: Start = {
initializeReactEmbeddableDynamicActions: jest.fn(),
initializeEmbeddableDynamicActions: jest.fn(),
};

return startContract;
Expand Down
53 changes: 27 additions & 26 deletions x-pack/platform/plugins/shared/embeddable_enhanced/public/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import {
UiActionsEnhancedDynamicActionManager as DynamicActionManager,
} from '@kbn/ui-actions-enhanced-plugin/public';
import deepEqual from 'react-fast-compare';
import { BehaviorSubject } from 'rxjs';
import { BehaviorSubject, Observable, map } from 'rxjs';
import {
DynamicActionStorage,
type DynamicActionStorageApi,
Expand All @@ -40,19 +40,21 @@ export interface StartDependencies {
// eslint-disable-next-line @typescript-eslint/no-empty-interface
export interface SetupContract {}

export interface ReactEmbeddableDynamicActionsApi {
dynamicActionsApi: HasDynamicActions;
dynamicActionsComparator: StateComparators<DynamicActionsSerializedState>;
serializeDynamicActions: () => DynamicActionsSerializedState;
export interface EmbeddableDynamicActionsManager {
api: HasDynamicActions;
comparators: StateComparators<DynamicActionsSerializedState>;
latestState$: Observable<DynamicActionsSerializedState>;
getLatestState: () => DynamicActionsSerializedState;
reinitializeState: (lastState: DynamicActionsSerializedState) => void;
startDynamicActions: () => { stopDynamicActions: () => void };
}

export interface StartContract {
initializeReactEmbeddableDynamicActions: (
initializeEmbeddableDynamicActions: (
uuid: string,
getTitle: () => string | undefined,
state: DynamicActionsSerializedState
) => ReactEmbeddableDynamicActionsApi;
) => EmbeddableDynamicActionsManager;
}

export interface DynamicActionsSerializedState {
Expand All @@ -74,7 +76,7 @@ export class EmbeddableEnhancedPlugin
this.uiActions = plugins.uiActionsEnhanced;

return {
initializeReactEmbeddableDynamicActions: this.initializeDynamicActions.bind(this),
initializeEmbeddableDynamicActions: this.initializeDynamicActions.bind(this),
};
}

Expand All @@ -84,12 +86,7 @@ export class EmbeddableEnhancedPlugin
uuid: string,
getTitle: () => string | undefined,
state: DynamicActionsSerializedState
): {
dynamicActionsApi: HasDynamicActions;
dynamicActionsComparator: StateComparators<DynamicActionsSerializedState>;
serializeDynamicActions: () => DynamicActionsSerializedState;
startDynamicActions: () => { stopDynamicActions: () => void };
} {
): EmbeddableDynamicActionsManager {
const dynamicActionsState$ = new BehaviorSubject<DynamicActionsSerializedState['enhancements']>(
getDynamicActionsState(state.enhancements)
);
Expand All @@ -109,19 +106,23 @@ export class EmbeddableEnhancedPlugin
uiActions: this.uiActions!,
});

function getLatestState() {
return { enhancements: dynamicActionsState$.getValue() };
}

return {
dynamicActionsApi: { ...api, enhancements: { dynamicActions } },
dynamicActionsComparator: {
enhancements: [
dynamicActionsState$,
api.setDynamicActions,
(a, b) => {
return deepEqual(getDynamicActionsState(a), getDynamicActionsState(b));
},
],
},
serializeDynamicActions: () => {
return { enhancements: dynamicActionsState$.getValue() };
api: { ...api, enhancements: { dynamicActions } },
comparators: {
enhancements: (a, b) => {
return deepEqual(getDynamicActionsState(a), getDynamicActionsState(b));
}
} as StateComparators<DynamicActionsSerializedState>,
latestState$: dynamicActionsState$.pipe(
map(() => getLatestState())
),
getLatestState,
reinitializeState: (lastState: DynamicActionsSerializedState) => {
api.setDynamicActions(lastState.enhancements);
},
startDynamicActions: () => {
const stop = this.startDynamicActions(dynamicActions);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import _ from 'lodash';
import { ACTION_GLOBAL_APPLY_FILTER } from '@kbn/unified-search-plugin/public';
import { i18n } from '@kbn/i18n';
import { ActionExecutionContext } from '@kbn/ui-actions-plugin/public';
import { BehaviorSubject } from 'rxjs';
import { BehaviorSubject, combineLatest, map } from 'rxjs';
import { getTitle, StateComparators } from '@kbn/presentation-publishing';
import { createExtentFilter } from '../../common/elasticsearch_util';
import { SavedMap } from '../routes/map_page';
Expand All @@ -30,6 +30,13 @@ import { getGeoFieldsLabel } from './get_geo_fields_label';
import { MapApi, MapSerializedState } from './types';
import { setOnMapMove } from '../reducers/non_serializable_instances';

export const crossPanelActionsComparators: StateComparators<
Pick<MapSerializedState, 'isMovementSynchronized' | 'filterByMapExtent'>
> = {
isMovementSynchronized: 'referenceEquality',
filterByMapExtent: 'referenceEquality',
};

export function initializeCrossPanelActions({
controlledBy,
getActionContext,
Expand All @@ -51,15 +58,15 @@ export function initializeCrossPanelActions({
function getIsMovementSynchronized() {
return isMovementSynchronized$.value ?? true;
}
function setIsMovementSynchronized(next: boolean) {
function setIsMovementSynchronized(next: boolean | undefined) {
isMovementSynchronized$.next(next);
}

const isFilterByMapExtent$ = new BehaviorSubject<boolean | undefined>(state.filterByMapExtent);
function getIsFilterByMapExtent() {
return isFilterByMapExtent$.value ?? false;
}
function setIsFilterByMapExtent(next: boolean) {
function setIsFilterByMapExtent(next: boolean | undefined) {
isFilterByMapExtent$.next(next);
}

Expand Down Expand Up @@ -208,21 +215,26 @@ export function initializeCrossPanelActions({
}
});

function getLatestState() {
return {
isMovementSynchronized: isMovementSynchronized$.value,
filterByMapExtent: isFilterByMapExtent$.value,
};
}

return {
cleanup: () => {
mapEmbeddablesSingleton.unregister(uuid);
unsubscribeFromStore();
},
comparators: {
isMovementSynchronized: [isMovementSynchronized$, setIsMovementSynchronized],
filterByMapExtent: [isFilterByMapExtent$, setIsFilterByMapExtent],
} as StateComparators<Pick<MapSerializedState, 'isMovementSynchronized' | 'filterByMapExtent'>>,
getIsFilterByMapExtent,
serialize: () => {
return {
isMovementSynchronized: isMovementSynchronized$.value,
filterByMapExtent: isFilterByMapExtent$.value,
};
latestState$: combineLatest([isMovementSynchronized$, isFilterByMapExtent$]).pipe(
map(() => getLatestState())
),
reinitializeState: (lastSaved: MapSerializedState) => {
setIsMovementSynchronized(lastSaved.isMovementSynchronized);
setIsFilterByMapExtent(lastSaved.filterByMapExtent);
},
getLatestState,
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* 2.0.
*/

import { BehaviorSubject, debounceTime, filter, map, Subscription } from 'rxjs';
import { BehaviorSubject, combineLatest, debounceTime, filter, map, Subscription } from 'rxjs';
import fastIsEqual from 'fast-deep-equal';
import { PublishingSubject, StateComparators } from '@kbn/presentation-publishing';
import { KibanaExecutionContext } from '@kbn/core-execution-context-common';
Expand Down Expand Up @@ -58,6 +58,28 @@ function getHiddenLayerIds(state: MapStoreState) {
.map((layer) => layer.id);
}

export const reduxSyncComparators: StateComparators<
Pick<
MapSerializedState,
'hiddenLayers' | 'isLayerTOCOpen' | 'mapCenter' | 'mapBuffer' | 'openTOCDetails'
>
> = {
hiddenLayers: 'deepEquality',
isLayerTOCOpen: 'referenceEquality',
mapCenter: (a, b) => {
if (!a || !b) {
return a === b;
}

if (a.lat !== b.lat) return false;
if (a.lon !== b.lon) return false;
// Map may not restore reset zoom exactly
return Math.abs(a.zoom - b.zoom) < 0.05;
},
mapBuffer: 'skip',
openTOCDetails: 'deepEquality',
};

export function initializeReduxSync({
savedMap,
state,
Expand Down Expand Up @@ -164,6 +186,16 @@ export function initializeReduxSync({
});
}

function getLatestState() {
return {
hiddenLayers: hiddenLayers$.value,
isLayerTOCOpen: isLayerTOCOpen$.value,
mapBuffer: getMapBuffer(store.getState()),
mapCenter: mapCenterAndZoom$.value,
openTOCDetails: openTOCDetails$.value,
};
}

return {
cleanup: () => {
if (syncColorsSubscription) syncColorsSubscription.unsubscribe();
Expand Down Expand Up @@ -199,56 +231,19 @@ export function initializeReduxSync({
store.dispatch(setEventHandlers(eventHandlers));
},
},
comparators: {
// mapBuffer comparator intentionally omitted and is not part of unsaved changes check
hiddenLayers: [
hiddenLayers$,
(nextValue: string[]) => {
store.dispatch<any>(setHiddenLayers(nextValue));
},
fastIsEqual,
],
isLayerTOCOpen: [
isLayerTOCOpen$,
(nextValue: boolean) => {
store.dispatch(setIsLayerTOCOpen(nextValue));
},
],
mapCenter: [
mapCenterAndZoom$,
(nextValue: MapCenterAndZoom) => {
store.dispatch(setGotoWithCenter(nextValue));
},
(a, b) => {
if (!a || !b) {
return a === b;
}

if (a.lat !== b.lat) return false;
if (a.lon !== b.lon) return false;
// Map may not restore reset zoom exactly
return Math.abs(a.zoom - b.zoom) < 0.05;
},
],
openTOCDetails: [
openTOCDetails$,
(nextValue: string[]) => {
store.dispatch(setOpenTOCDetails(nextValue));
},
fastIsEqual,
],
} as StateComparators<
Pick<MapSerializedState, 'hiddenLayers' | 'isLayerTOCOpen' | 'mapCenter' | 'openTOCDetails'>
>,
serialize: () => {
return {
hiddenLayers: getHiddenLayerIds(store.getState()),
isLayerTOCOpen: getIsLayerTOCOpen(store.getState()),
mapBuffer: getMapBuffer(store.getState()),
mapCenter: getMapCenterAndZoom(store.getState()),
openTOCDetails: getOpenTOCDetails(store.getState()),
};
latestState$: combineLatest([
hiddenLayers$,
isLayerTOCOpen$,
mapCenterAndZoom$,
openTOCDetails$,
]).pipe(map(() => getLatestState())),
reinitializeState: (lastSaved?: MapSerializedState) => {
store.dispatch<any>(setHiddenLayers(lastSaved?.hiddenLayers ?? []));
store.dispatch(setIsLayerTOCOpen(lastSaved?.isLayerTOCOpen ?? true));
if (lastSaved?.mapCenter) store.dispatch(setGotoWithCenter(lastSaved.mapCenter));
store.dispatch(setOpenTOCDetails(lastSaved?.openTOCDetails));
},
getLatestState,
};
}

Expand Down
Loading
Loading