[Maps] decouple SYNCHRONIZE_MOVEMENT_ACTION from Embeddable framework (#175642)

Part of https://github.com/elastic/kibana/issues/175138 and prerequisite
for https://github.com/elastic/kibana/issues/174960

PR decouples SYNCHRONIZE_MOVEMENT_ACTION from Embeddable framework by
migrating to sets of composable interfaces.

---------

Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
Co-authored-by: Devon Thomson <devon.thomson@elastic.co>
This commit is contained in:
Nathan Reese 2024-01-29 16:37:55 -07:00 committed by GitHub
parent d51fddb332
commit 5b386140e1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 73 additions and 48 deletions

View file

@ -21,7 +21,7 @@ export const apiHasType = (api: unknown | null): api is HasType => {
export const apiIsOfType = <T extends string = string>(
api: unknown | null,
typeToCheck: string
typeToCheck: T
): api is HasType<T> => {
return Boolean(api && (api as HasType).type) && (api as HasType).type === typeToCheck;
};

View file

@ -6,13 +6,18 @@
* Side Public License, v 1.
*/
import { type HasType, apiIsOfType } from '@kbn/presentation-publishing';
import { VisParams } from '../../types';
import Vis from '../../vis';
export interface HasVisualizeConfig {
export type HasVisualizeConfig = HasType<'visualization'> & {
getVis: () => Vis<VisParams>;
}
};
export const apiHasVisualizeConfig = (api: unknown): api is HasVisualizeConfig => {
return Boolean(api && typeof (api as HasVisualizeConfig).getVis === 'function');
return Boolean(
api &&
apiIsOfType(api, 'visualization') &&
typeof (api as HasVisualizeConfig).getVis === 'function'
);
};

View file

@ -67,7 +67,8 @@
"@kbn/logging",
"@kbn/content-management-table-list-view-common",
"@kbn/chart-expressions-common",
"@kbn/shared-ux-utility"
"@kbn/shared-ux-utility",
"@kbn/presentation-publishing"
],
"exclude": [
"target/**/*",

View file

@ -6,3 +6,5 @@
*/
export * from './embeddable';
export { type HasLensConfig, apiHasLensConfig } from './interfaces/has_lens_config';

View file

@ -0,0 +1,19 @@
/*
* 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 { type HasType, apiIsOfType } from '@kbn/presentation-publishing';
import { Document } from '../../persistence';
export type HasLensConfig = HasType<'lens'> & {
getSavedVis: () => Readonly<Document | undefined>;
};
export const apiHasLensConfig = (api: unknown): api is HasLensConfig => {
return Boolean(
api && apiIsOfType(api, 'lens') && typeof (api as HasLensConfig).getSavedVis === 'function'
);
};

View file

@ -7,6 +7,7 @@
import { LensPlugin } from './plugin';
export { apiHasLensConfig } from './embeddable/interfaces/has_lens_config';
export type {
EmbeddableComponentProps,
EmbeddableComponent,
@ -109,6 +110,7 @@ export type {
export type { InlineEditLensEmbeddableContext } from './trigger_actions/open_lens_config/in_app_embeddable_edit/types';
export type {
HasLensConfig,
LensEmbeddableInput,
LensSavedObjectAttributes,
Embeddable,

View file

@ -107,7 +107,8 @@
"@kbn/shared-ux-utility",
"@kbn/text-based-editor",
"@kbn/managed-content-badge",
"@kbn/sort-predicates"
"@kbn/sort-predicates",
"@kbn/presentation-publishing"
],
"exclude": ["target/**/*"]
}

View file

@ -5,10 +5,8 @@
* 2.0.
*/
import type { HasType } from '@kbn/presentation-publishing';
import { Embeddable } from '@kbn/embeddable-plugin/public';
import type { HasVisualizeConfig, VisualizeEmbeddable } from '@kbn/visualizations-plugin/public';
import { apiHasVisualizeConfig } from '@kbn/visualizations-plugin/public';
export function isLegacyMap(embeddable: Embeddable) {
return (
@ -18,11 +16,6 @@ export function isLegacyMap(embeddable: Embeddable) {
);
}
type LegacyMapApi = HasType & Partial<HasVisualizeConfig>;
export function isLegacyMapApi(api: LegacyMapApi) {
if (api.type !== 'visualization' || !apiHasVisualizeConfig(api)) {
return false;
}
export function isLegacyMapApi(api: HasVisualizeConfig) {
return ['region_map', 'tile_map'].includes(api.getVis().type?.name);
}

View file

@ -6,8 +6,9 @@
*/
import { i18n } from '@kbn/i18n';
import { type EmbeddableApiContext, apiHasType } from '@kbn/presentation-publishing';
import { type EmbeddableApiContext, apiHasType, apiIsOfType } from '@kbn/presentation-publishing';
import { createAction } from '@kbn/ui-actions-plugin/public';
import { apiHasVisualizeConfig } from '@kbn/visualizations-plugin/public';
import { type FilterByMapExtentActionApi } from './types';
import { MAP_SAVED_OBJECT_TYPE } from '../../../common/constants';
import { isLegacyMapApi } from '../../legacy_visualizations/is_legacy_map';
@ -52,10 +53,11 @@ export const filterByMapExtentAction = createAction<EmbeddableApiContext>({
return 'filter';
},
isCompatible: async ({ embeddable }: EmbeddableApiContext) => {
if (!isApiCompatible(embeddable)) return false;
return embeddable.disableTriggers
? false
: embeddable.type === MAP_SAVED_OBJECT_TYPE || isLegacyMapApi(embeddable);
if (!isApiCompatible(embeddable) || embeddable.disableTriggers) return false;
return (
apiIsOfType(embeddable, MAP_SAVED_OBJECT_TYPE) ||
(apiHasVisualizeConfig(embeddable) && isLegacyMapApi(embeddable))
);
},
execute: async ({ embeddable }: EmbeddableApiContext) => {
const { openModal } = await import('./modal');

View file

@ -8,5 +8,5 @@
import type { HasDisableTriggers, HasParentApi, HasType } from '@kbn/presentation-publishing';
import type { HasVisualizeConfig } from '@kbn/visualizations-plugin/public';
export type FilterByMapExtentActionApi = HasType &
export type FilterByMapExtentActionApi = HasType<'visualization' | 'map'> &
Partial<HasDisableTriggers & HasParentApi<HasType> & HasVisualizeConfig>;

View file

@ -6,16 +6,20 @@
*/
import { i18n } from '@kbn/i18n';
import { type EmbeddableApiContext, apiHasType } from '@kbn/presentation-publishing';
import { createAction } from '@kbn/ui-actions-plugin/public';
import type { SynchronizeMovementActionContext } from './types';
import type { SynchronizeMovementActionApi } from './types';
export const SYNCHRONIZE_MOVEMENT_ACTION = 'SYNCHRONIZE_MOVEMENT_ACTION';
export const synchronizeMovementAction = createAction<SynchronizeMovementActionContext>({
export const isApiCompatible = (api: unknown | null): api is SynchronizeMovementActionApi =>
Boolean(apiHasType(api));
export const synchronizeMovementAction = createAction<EmbeddableApiContext>({
id: SYNCHRONIZE_MOVEMENT_ACTION,
type: SYNCHRONIZE_MOVEMENT_ACTION,
order: 21,
getDisplayName: ({ embeddable }: SynchronizeMovementActionContext) => {
getDisplayName: () => {
return i18n.translate('xpack.maps.synchronizeMovementAction.title', {
defaultMessage: 'Synchronize map movement',
});
@ -29,11 +33,12 @@ export const synchronizeMovementAction = createAction<SynchronizeMovementActionC
getIconType: () => {
return 'crosshairs';
},
isCompatible: async (context: SynchronizeMovementActionContext) => {
isCompatible: async ({ embeddable }: EmbeddableApiContext) => {
if (!isApiCompatible(embeddable)) return false;
const { isCompatible } = await import('./is_compatible');
return isCompatible(context);
return isCompatible(embeddable);
},
execute: async (context: SynchronizeMovementActionContext) => {
execute: async () => {
const { openModal } = await import('./modal');
openModal();
},

View file

@ -5,28 +5,21 @@
* 2.0.
*/
import type { Embeddable as LensEmbeddable } from '@kbn/lens-plugin/public';
import { apiIsOfType } from '@kbn/presentation-publishing';
import { apiHasVisualizeConfig } from '@kbn/visualizations-plugin/public';
import { apiHasLensConfig } from '@kbn/lens-plugin/public';
import { MAP_SAVED_OBJECT_TYPE } from '../../../common/constants';
import { isLegacyMap } from '../../legacy_visualizations/is_legacy_map';
import { isLegacyMapApi } from '../../legacy_visualizations/is_legacy_map';
import { mapEmbeddablesSingleton } from '../../embeddable/map_embeddables_singleton';
import type { SynchronizeMovementActionContext } from './types';
import type { SynchronizeMovementActionApi } from './types';
export function isCompatible({ embeddable }: SynchronizeMovementActionContext) {
export function isCompatible(api: SynchronizeMovementActionApi) {
if (!mapEmbeddablesSingleton.hasMultipleMaps()) {
return false;
}
if (
embeddable.type === 'lens' &&
typeof (embeddable as LensEmbeddable).getSavedVis === 'function' &&
(embeddable as LensEmbeddable).getSavedVis()?.visualizationType === 'lnsChoropleth'
) {
return true;
}
if (isLegacyMap(embeddable)) {
return true;
}
return embeddable.type === MAP_SAVED_OBJECT_TYPE;
return (
apiIsOfType(api, MAP_SAVED_OBJECT_TYPE) ||
(apiHasLensConfig(api) && api.getSavedVis()?.visualizationType === 'lnsChoropleth') ||
(apiHasVisualizeConfig(api) && isLegacyMapApi(api))
);
}

View file

@ -5,8 +5,10 @@
* 2.0.
*/
import type { Embeddable, EmbeddableInput } from '@kbn/embeddable-plugin/public';
import type { HasType } from '@kbn/presentation-publishing';
import type { HasLensConfig } from '@kbn/lens-plugin/public';
import type { HasVisualizeConfig } from '@kbn/visualizations-plugin/public';
export interface SynchronizeMovementActionContext {
embeddable: Embeddable<EmbeddableInput>;
}
export type SynchronizeMovementActionApi =
| HasType<'map' | 'visualization' | 'lens'>
| Partial<HasLensConfig | HasVisualizeConfig>;