mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
# Backport This will backport the following commits from `main` to `8.x`: - [[maps] lazy load map actions (#210252)](https://github.com/elastic/kibana/pull/210252) <!--- Backport version: 9.6.4 --> ### Questions ? Please refer to the [Backport tool documentation](https://github.com/sorenlouv/backport) <!--BACKPORT [{"author":{"name":"Nathan Reese","email":"reese.nathan@elastic.co"},"sourceCommit":{"committedDate":"2025-02-11T16:37:34Z","message":"[maps] lazy load map actions (#210252)\n\nCo-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>\r\nCo-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>","sha":"8a30b862cc1c4aee11559f34f6c6c0c453a674e5","branchLabelMapping":{"^v9.1.0$":"main","^v8.19.0$":"8.x","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["Team:Presentation","release_note:skip","backport:version","v9.1.0","v8.19.0"],"title":"[maps] lazy load map actions","number":210252,"url":"https://github.com/elastic/kibana/pull/210252","mergeCommit":{"message":"[maps] lazy load map actions (#210252)\n\nCo-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>\r\nCo-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>","sha":"8a30b862cc1c4aee11559f34f6c6c0c453a674e5"}},"sourceBranch":"main","suggestedTargetBranches":["8.x"],"targetPullRequestStates":[{"branch":"main","label":"v9.1.0","branchLabelMappingKey":"^v9.1.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/210252","number":210252,"mergeCommit":{"message":"[maps] lazy load map actions (#210252)\n\nCo-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>\r\nCo-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>","sha":"8a30b862cc1c4aee11559f34f6c6c0c453a674e5"}},{"branch":"8.x","label":"v8.19.0","branchLabelMappingKey":"^v8.19.0$","isSourceBranch":false,"state":"NOT_CREATED"}]}] BACKPORT--> --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
c17fc1c2d4
commit
b28c80e5f6
21 changed files with 220 additions and 187 deletions
|
@ -105,7 +105,7 @@ pageLoadAssetSize:
|
|||
logsShared: 281060
|
||||
logstash: 53548
|
||||
management: 46112
|
||||
maps: 90000
|
||||
maps: 46000
|
||||
mapsEms: 26072
|
||||
metricsDataAccess: 73287
|
||||
ml: 85000
|
||||
|
|
|
@ -10,7 +10,7 @@ import { dynamic } from '@kbn/shared-ux-utility';
|
|||
import type { Props } from './passive_map';
|
||||
|
||||
const Component = dynamic(async () => {
|
||||
const { PassiveMap } = await import('./passive_map');
|
||||
const { PassiveMap } = await import('../react_embeddable/embeddable_module');
|
||||
return {
|
||||
default: PassiveMap,
|
||||
};
|
||||
|
|
|
@ -23,10 +23,8 @@ import { DEFAULT_APP_CATEGORIES } from '@kbn/core/public';
|
|||
import type { HomePublicPluginSetup } from '@kbn/home-plugin/public';
|
||||
import type { VisualizationsSetup, VisualizationsStart } from '@kbn/visualizations-plugin/public';
|
||||
import type { Plugin as ExpressionsPublicPlugin } from '@kbn/expressions-plugin/public';
|
||||
import { ADD_PANEL_TRIGGER, VISUALIZE_GEO_FIELD_TRIGGER } from '@kbn/ui-actions-plugin/public';
|
||||
import { EmbeddableSetup, EmbeddableStart } from '@kbn/embeddable-plugin/public';
|
||||
import { EmbeddableEnhancedPluginStart } from '@kbn/embeddable-enhanced-plugin/public';
|
||||
import { CONTEXT_MENU_TRIGGER } from '@kbn/embeddable-plugin/public';
|
||||
import type { SharePluginSetup, SharePluginStart } from '@kbn/share-plugin/public';
|
||||
import type { MapsEmsPluginPublicStart } from '@kbn/maps-ems-plugin/public';
|
||||
import type { DataPublicPluginSetup, DataPublicPluginStart } from '@kbn/data-plugin/public';
|
||||
|
@ -69,9 +67,6 @@ import {
|
|||
suggestEMSTermJoinConfig,
|
||||
} from './api';
|
||||
import type { MapsXPackConfig, MapsConfigType } from '../server/config';
|
||||
import { filterByMapExtentAction } from './trigger_actions/filter_by_map_extent/action';
|
||||
import { synchronizeMovementAction } from './trigger_actions/synchronize_movement/action';
|
||||
import { visualizeGeoFieldAction } from './trigger_actions/visualize_geo_field_action';
|
||||
import { APP_NAME, APP_ICON_SOLUTION, APP_ID } from '../common/constants';
|
||||
import { mapsVisTypeAlias } from './maps_vis_type_alias';
|
||||
import { featureCatalogueEntry } from './feature_catalogue_entry';
|
||||
|
@ -89,6 +84,7 @@ import { PassiveMapLazy, setupLensChoroplethChart } from './lens';
|
|||
import { CONTENT_ID, LATEST_VERSION } from '../common/content_management';
|
||||
import { setupMapEmbeddable } from './react_embeddable/setup_map_embeddable';
|
||||
import { MapRendererLazy } from './react_embeddable/map_renderer/map_renderer_lazy';
|
||||
import { registerUiActions } from './trigger_actions/register_ui_actions';
|
||||
|
||||
export interface MapsPluginSetupDependencies {
|
||||
cloud?: CloudSetup;
|
||||
|
@ -251,22 +247,7 @@ export class MapsPlugin
|
|||
setLicensingPluginStart(plugins.licensing);
|
||||
setStartServices(core, plugins);
|
||||
|
||||
if (core.application.capabilities.maps.show) {
|
||||
plugins.uiActions.addTriggerAction(VISUALIZE_GEO_FIELD_TRIGGER, visualizeGeoFieldAction);
|
||||
}
|
||||
plugins.uiActions.addTriggerAction(CONTEXT_MENU_TRIGGER, filterByMapExtentAction);
|
||||
plugins.uiActions.addTriggerAction(CONTEXT_MENU_TRIGGER, synchronizeMovementAction);
|
||||
|
||||
plugins.uiActions.registerActionAsync('addMapPanelAction', async () => {
|
||||
const { getAddMapPanelAction } = await import('./trigger_actions/add_map_panel_action');
|
||||
return getAddMapPanelAction(plugins);
|
||||
});
|
||||
plugins.uiActions.attachAction(ADD_PANEL_TRIGGER, 'addMapPanelAction');
|
||||
if (plugins.uiActions.hasTrigger('ADD_CANVAS_ELEMENT_TRIGGER')) {
|
||||
// Because Canvas is not enabled in Serverless, this trigger might not be registered - only attach
|
||||
// the create action if the Canvas-specific trigger does indeed exist.
|
||||
plugins.uiActions.attachAction('ADD_CANVAS_ELEMENT_TRIGGER', 'addMapPanelAction');
|
||||
}
|
||||
registerUiActions(core, plugins);
|
||||
|
||||
if (!core.application.capabilities.maps.save) {
|
||||
plugins.visualizations.unRegisterAlias(APP_ID);
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
export { MapRenderer } from './map_renderer/map_renderer';
|
||||
export { PassiveMap } from '../lens/passive_map';
|
||||
export { mapEmbeddableFactory } from './map_react_embeddable';
|
|
@ -10,7 +10,7 @@ import { dynamic } from '@kbn/shared-ux-utility';
|
|||
import type { Props } from './map_renderer';
|
||||
|
||||
const Component = dynamic(async () => {
|
||||
const { MapRenderer } = await import('./map_renderer');
|
||||
const { MapRenderer } = await import('../embeddable_module');
|
||||
return {
|
||||
default: MapRenderer,
|
||||
};
|
||||
|
|
|
@ -16,7 +16,7 @@ export function setupMapEmbeddable(embeddableSetup: EmbeddableSetup) {
|
|||
const startServicesPromise = untilPluginStartServicesReady();
|
||||
const [, { mapEmbeddableFactory }] = await Promise.all([
|
||||
startServicesPromise,
|
||||
import('./map_react_embeddable'),
|
||||
import('./embeddable_module'),
|
||||
]);
|
||||
|
||||
return mapEmbeddableFactory;
|
||||
|
|
|
@ -6,32 +6,30 @@
|
|||
*/
|
||||
|
||||
import type { DefaultEmbeddableApi } from '@kbn/embeddable-plugin/public';
|
||||
import { TimeRange } from '@kbn/es-query';
|
||||
import { HasInspectorAdapters } from '@kbn/inspector-plugin/public';
|
||||
import {
|
||||
apiIsOfType,
|
||||
apiPublishesTitle,
|
||||
apiPublishesUnifiedSearch,
|
||||
import type { TimeRange } from '@kbn/es-query';
|
||||
import type { HasInspectorAdapters } from '@kbn/inspector-plugin/public';
|
||||
import type {
|
||||
HasEditCapabilities,
|
||||
HasLibraryTransforms,
|
||||
HasSupportedTriggers,
|
||||
HasType,
|
||||
PublishesDataLoading,
|
||||
PublishesDataViews,
|
||||
PublishesUnifiedSearch,
|
||||
SerializedTitles,
|
||||
} from '@kbn/presentation-publishing';
|
||||
import { HasDynamicActions } from '@kbn/embeddable-enhanced-plugin/public';
|
||||
import { DynamicActionsSerializedState } from '@kbn/embeddable-enhanced-plugin/public/plugin';
|
||||
import { Observable } from 'rxjs';
|
||||
import { MapAttributes } from '../../common/content_management';
|
||||
import {
|
||||
import type { HasDynamicActions } from '@kbn/embeddable-enhanced-plugin/public';
|
||||
import type { DynamicActionsSerializedState } from '@kbn/embeddable-enhanced-plugin/public/plugin';
|
||||
import type { Observable } from 'rxjs';
|
||||
import type { MapAttributes } from '../../common/content_management';
|
||||
import type {
|
||||
LayerDescriptor,
|
||||
MapCenterAndZoom,
|
||||
MapExtent,
|
||||
MapSettings,
|
||||
} from '../../common/descriptor_types';
|
||||
import { ILayer } from '../classes/layers/layer';
|
||||
import { EventHandlers } from '../reducers/non_serializable_instances';
|
||||
import type { ILayer } from '../classes/layers/layer';
|
||||
import type { EventHandlers } from '../reducers/non_serializable_instances';
|
||||
|
||||
export type MapSerializedState = SerializedTitles &
|
||||
Partial<DynamicActionsSerializedState> & {
|
||||
|
@ -72,10 +70,6 @@ export type MapApi = DefaultEmbeddableApi<MapSerializedState> &
|
|||
|
||||
export const isMapApi = (api: unknown): api is MapApi => {
|
||||
return Boolean(
|
||||
api &&
|
||||
apiIsOfType(api, 'map') &&
|
||||
typeof (api as MapApi).getLayerList === 'function' &&
|
||||
apiPublishesTitle(api) &&
|
||||
apiPublishesUnifiedSearch(api)
|
||||
api && (api as HasType)?.type === 'map' && typeof (api as MapApi).getLayerList === 'function'
|
||||
);
|
||||
};
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
export { filterByMapExtentAction } from './filter_by_map_extent/action';
|
||||
export { synchronizeMovementAction } from './synchronize_movement/action';
|
|
@ -8,23 +8,23 @@
|
|||
import { i18n } from '@kbn/i18n';
|
||||
import {
|
||||
type EmbeddableApiContext,
|
||||
apiHasType,
|
||||
apiIsOfType,
|
||||
areTriggersDisabled,
|
||||
HasParentApi,
|
||||
HasType,
|
||||
} 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 React, { Suspense, lazy } from 'react';
|
||||
import { toMountPoint } from '@kbn/react-kibana-mount';
|
||||
import { EuiModalBody, EuiSkeletonText } from '@elastic/eui';
|
||||
import { MAP_SAVED_OBJECT_TYPE } from '../../../common/constants';
|
||||
import { isLegacyMapApi } from '../../legacy_visualizations/is_legacy_map';
|
||||
import { getCore } from '../../kibana_services';
|
||||
import { FILTER_BY_MAP_EXTENT } from './constants';
|
||||
|
||||
export const FILTER_BY_MAP_EXTENT = 'FILTER_BY_MAP_EXTENT';
|
||||
|
||||
export const isApiCompatible = (api: unknown | null): api is FilterByMapExtentActionApi =>
|
||||
Boolean(apiHasType(api));
|
||||
|
||||
function getContainerLabel(api: FilterByMapExtentActionApi | unknown) {
|
||||
return isApiCompatible(api) && api.parentApi?.type === 'dashboard'
|
||||
function getContainerLabel(api: unknown) {
|
||||
return (api as Partial<HasParentApi<Partial<HasType>>>)?.parentApi?.type === 'dashboard'
|
||||
? i18n.translate('xpack.maps.filterByMapExtentMenuItem.dashboardLabel', {
|
||||
defaultMessage: 'dashboard',
|
||||
})
|
||||
|
@ -33,7 +33,7 @@ function getContainerLabel(api: FilterByMapExtentActionApi | unknown) {
|
|||
});
|
||||
}
|
||||
|
||||
function getDisplayName(api: FilterByMapExtentActionApi | unknown) {
|
||||
function getDisplayName(api: unknown) {
|
||||
return i18n.translate('xpack.maps.filterByMapExtentMenuItem.displayName', {
|
||||
defaultMessage: 'Filter {containerLabel} by map bounds',
|
||||
values: { containerLabel: getContainerLabel(api) },
|
||||
|
@ -44,28 +44,42 @@ export const filterByMapExtentAction = createAction<EmbeddableApiContext>({
|
|||
id: FILTER_BY_MAP_EXTENT,
|
||||
type: FILTER_BY_MAP_EXTENT,
|
||||
order: 20,
|
||||
getDisplayName: ({ embeddable }: EmbeddableApiContext) => {
|
||||
return getDisplayName(embeddable);
|
||||
},
|
||||
getDisplayNameTooltip: ({ embeddable }: EmbeddableApiContext) => {
|
||||
return i18n.translate('xpack.maps.filterByMapExtentMenuItem.displayNameTooltip', {
|
||||
getDisplayName: ({ embeddable }: EmbeddableApiContext) => getDisplayName(embeddable),
|
||||
getDisplayNameTooltip: ({ embeddable }: EmbeddableApiContext) =>
|
||||
i18n.translate('xpack.maps.filterByMapExtentMenuItem.displayNameTooltip', {
|
||||
defaultMessage:
|
||||
'As you zoom and pan the map, the {containerLabel} updates to display only the data visible in the map bounds.',
|
||||
values: { containerLabel: getContainerLabel(embeddable) },
|
||||
});
|
||||
},
|
||||
getIconType: () => {
|
||||
return 'filter';
|
||||
},
|
||||
}),
|
||||
getIconType: () => 'filter',
|
||||
isCompatible: async ({ embeddable }: EmbeddableApiContext) => {
|
||||
if (!isApiCompatible(embeddable) || areTriggersDisabled(embeddable)) return false;
|
||||
return (
|
||||
apiIsOfType(embeddable, MAP_SAVED_OBJECT_TYPE) ||
|
||||
(apiHasVisualizeConfig(embeddable) && isLegacyMapApi(embeddable))
|
||||
!areTriggersDisabled(embeddable) &&
|
||||
(apiIsOfType(embeddable, MAP_SAVED_OBJECT_TYPE) ||
|
||||
(apiHasVisualizeConfig(embeddable) && isLegacyMapApi(embeddable)))
|
||||
);
|
||||
},
|
||||
execute: async ({ embeddable }: EmbeddableApiContext) => {
|
||||
const { openModal } = await import('./modal');
|
||||
openModal(getDisplayName(embeddable));
|
||||
const core = getCore();
|
||||
const LazyModal = lazy(async () => {
|
||||
const { FilterByMapExtentModal } = await import('./modal');
|
||||
return {
|
||||
default: FilterByMapExtentModal,
|
||||
};
|
||||
});
|
||||
const overlayRef = core.overlays.openModal(
|
||||
toMountPoint(
|
||||
<Suspense
|
||||
fallback={
|
||||
<EuiModalBody>
|
||||
<EuiSkeletonText />
|
||||
</EuiModalBody>
|
||||
}
|
||||
>
|
||||
<LazyModal onClose={() => overlayRef.close()} title={getDisplayName(embeddable)} />
|
||||
</Suspense>,
|
||||
core
|
||||
)
|
||||
);
|
||||
},
|
||||
});
|
|
@ -0,0 +1,8 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
export const FILTER_BY_MAP_EXTENT = 'FILTER_BY_MAP_EXTENT';
|
|
@ -14,23 +14,14 @@ import {
|
|||
EuiSwitch,
|
||||
EuiSwitchEvent,
|
||||
} from '@elastic/eui';
|
||||
import { createReactOverlays } from '@kbn/kibana-react-plugin/public';
|
||||
import { mapEmbeddablesSingleton } from '../../react_embeddable/map_embeddables_singleton';
|
||||
import { getCore } from '../../kibana_services';
|
||||
|
||||
export function openModal(title: string) {
|
||||
const { openModal: reactOverlaysOpenModal } = createReactOverlays(getCore());
|
||||
const modalSession = reactOverlaysOpenModal(
|
||||
<FilterByMapExtentModal onClose={() => modalSession.close()} title={title} />
|
||||
);
|
||||
}
|
||||
|
||||
interface Props {
|
||||
onClose: () => void;
|
||||
title: string;
|
||||
}
|
||||
|
||||
class FilterByMapExtentModal extends Component<Props> {
|
||||
export class FilterByMapExtentModal extends Component<Props> {
|
||||
_renderSwitches() {
|
||||
return mapEmbeddablesSingleton.getMapPanels().map((mapPanel) => {
|
||||
return (
|
||||
|
|
|
@ -1,12 +0,0 @@
|
|||
/*
|
||||
* 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 { HasDisableTriggers, HasParentApi, HasType } from '@kbn/presentation-publishing';
|
||||
import type { HasVisualizeConfig } from '@kbn/visualizations-plugin/public';
|
||||
|
||||
export type FilterByMapExtentActionApi = HasType<'visualization' | 'map'> &
|
||||
Partial<HasDisableTriggers & HasParentApi<HasType> & HasVisualizeConfig>;
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* 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 { CONTEXT_MENU_TRIGGER } from '@kbn/embeddable-plugin/public';
|
||||
import {
|
||||
ACTION_VISUALIZE_GEO_FIELD,
|
||||
ADD_PANEL_TRIGGER,
|
||||
VISUALIZE_GEO_FIELD_TRIGGER,
|
||||
} from '@kbn/ui-actions-plugin/public';
|
||||
import { CoreStart } from '@kbn/core/public';
|
||||
import { FILTER_BY_MAP_EXTENT } from './filter_by_map_extent/constants';
|
||||
import { SYNCHRONIZE_MOVEMENT_ACTION } from './synchronize_movement/constants';
|
||||
import type { MapsPluginStartDependencies } from '../plugin';
|
||||
|
||||
export function registerUiActions(core: CoreStart, plugins: MapsPluginStartDependencies) {
|
||||
if (core.application.capabilities.maps.show) {
|
||||
plugins.uiActions.addTriggerActionAsync(
|
||||
VISUALIZE_GEO_FIELD_TRIGGER,
|
||||
ACTION_VISUALIZE_GEO_FIELD,
|
||||
async () => {
|
||||
const { visualizeGeoFieldAction } = await import('./visualize_geo_field_action');
|
||||
return visualizeGeoFieldAction;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
plugins.uiActions.registerActionAsync('addMapPanelAction', async () => {
|
||||
const { getAddMapPanelAction } = await import('./add_map_panel_action');
|
||||
return getAddMapPanelAction(plugins);
|
||||
});
|
||||
plugins.uiActions.attachAction(ADD_PANEL_TRIGGER, 'addMapPanelAction');
|
||||
if (plugins.uiActions.hasTrigger('ADD_CANVAS_ELEMENT_TRIGGER')) {
|
||||
// Because Canvas is not enabled in Serverless, this trigger might not be registered - only attach
|
||||
// the create action if the Canvas-specific trigger does indeed exist.
|
||||
plugins.uiActions.attachAction('ADD_CANVAS_ELEMENT_TRIGGER', 'addMapPanelAction');
|
||||
}
|
||||
|
||||
plugins.uiActions.addTriggerActionAsync(CONTEXT_MENU_TRIGGER, FILTER_BY_MAP_EXTENT, async () => {
|
||||
const { filterByMapExtentAction } = await import('./context_menu_actions_module');
|
||||
return filterByMapExtentAction;
|
||||
});
|
||||
plugins.uiActions.addTriggerActionAsync(
|
||||
CONTEXT_MENU_TRIGGER,
|
||||
SYNCHRONIZE_MOVEMENT_ACTION,
|
||||
async () => {
|
||||
const { synchronizeMovementAction } = await import('./context_menu_actions_module');
|
||||
return synchronizeMovementAction;
|
||||
}
|
||||
);
|
||||
}
|
|
@ -1,45 +0,0 @@
|
|||
/*
|
||||
* 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 { i18n } from '@kbn/i18n';
|
||||
import { type EmbeddableApiContext, apiHasType } from '@kbn/presentation-publishing';
|
||||
import { createAction } from '@kbn/ui-actions-plugin/public';
|
||||
import type { SynchronizeMovementActionApi } from './types';
|
||||
|
||||
export const SYNCHRONIZE_MOVEMENT_ACTION = 'SYNCHRONIZE_MOVEMENT_ACTION';
|
||||
|
||||
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: () => {
|
||||
return i18n.translate('xpack.maps.synchronizeMovementAction.title', {
|
||||
defaultMessage: 'Synchronize map movement',
|
||||
});
|
||||
},
|
||||
getDisplayNameTooltip: () => {
|
||||
return i18n.translate('xpack.maps.synchronizeMovementAction.tooltipContent', {
|
||||
defaultMessage:
|
||||
'Synchronize maps, so that if you zoom and pan in one map, the movement is reflected in other maps',
|
||||
});
|
||||
},
|
||||
getIconType: () => {
|
||||
return 'crosshairs';
|
||||
},
|
||||
isCompatible: async ({ embeddable }: EmbeddableApiContext) => {
|
||||
if (!isApiCompatible(embeddable)) return false;
|
||||
const { isCompatible } = await import('./is_compatible');
|
||||
return isCompatible(embeddable);
|
||||
},
|
||||
execute: async () => {
|
||||
const { openModal } = await import('./modal');
|
||||
openModal();
|
||||
},
|
||||
});
|
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* 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 { i18n } from '@kbn/i18n';
|
||||
import { type EmbeddableApiContext, apiIsOfType } from '@kbn/presentation-publishing';
|
||||
import { createAction } from '@kbn/ui-actions-plugin/public';
|
||||
import { toMountPoint } from '@kbn/react-kibana-mount';
|
||||
import { isLensApi } from '@kbn/lens-plugin/public';
|
||||
import { apiHasVisualizeConfig } from '@kbn/visualizations-plugin/public';
|
||||
import { Suspense, lazy } from 'react';
|
||||
import { EuiModalBody, EuiSkeletonText } from '@elastic/eui';
|
||||
import React from 'react';
|
||||
import { getCore } from '../../kibana_services';
|
||||
import { isLegacyMapApi } from '../../legacy_visualizations/is_legacy_map';
|
||||
import { MAP_SAVED_OBJECT_TYPE } from '../../../common/constants';
|
||||
import { mapEmbeddablesSingleton } from '../../react_embeddable/map_embeddables_singleton';
|
||||
import { SYNCHRONIZE_MOVEMENT_ACTION } from './constants';
|
||||
|
||||
export const synchronizeMovementAction = createAction<EmbeddableApiContext>({
|
||||
id: SYNCHRONIZE_MOVEMENT_ACTION,
|
||||
type: SYNCHRONIZE_MOVEMENT_ACTION,
|
||||
order: 21,
|
||||
getDisplayName: () =>
|
||||
i18n.translate('xpack.maps.synchronizeMovementAction.title', {
|
||||
defaultMessage: 'Synchronize map movement',
|
||||
}),
|
||||
getDisplayNameTooltip: () =>
|
||||
i18n.translate('xpack.maps.synchronizeMovementAction.tooltipContent', {
|
||||
defaultMessage:
|
||||
'Synchronize maps, so that if you zoom and pan in one map, the movement is reflected in other maps',
|
||||
}),
|
||||
getIconType: () => 'crosshairs',
|
||||
isCompatible: async ({ embeddable }: EmbeddableApiContext) => {
|
||||
return (
|
||||
mapEmbeddablesSingleton.hasMultipleMaps() &&
|
||||
(apiIsOfType(embeddable, MAP_SAVED_OBJECT_TYPE) ||
|
||||
(isLensApi(embeddable) &&
|
||||
embeddable.getSavedVis()?.visualizationType === 'lnsChoropleth') ||
|
||||
(apiHasVisualizeConfig(embeddable) && isLegacyMapApi(embeddable)))
|
||||
);
|
||||
},
|
||||
execute: async () => {
|
||||
const core = getCore();
|
||||
const LazyModal = lazy(async () => {
|
||||
const { SynchronizeMovementModal } = await import('./modal');
|
||||
return {
|
||||
default: SynchronizeMovementModal,
|
||||
};
|
||||
});
|
||||
const overlayRef = core.overlays.openModal(
|
||||
toMountPoint(
|
||||
<Suspense
|
||||
fallback={
|
||||
<EuiModalBody>
|
||||
<EuiSkeletonText />
|
||||
</EuiModalBody>
|
||||
}
|
||||
>
|
||||
<LazyModal onClose={() => overlayRef.close()} />
|
||||
</Suspense>,
|
||||
core
|
||||
)
|
||||
);
|
||||
},
|
||||
});
|
|
@ -0,0 +1,8 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
export const SYNCHRONIZE_MOVEMENT_ACTION = 'SYNCHRONIZE_MOVEMENT_ACTION';
|
|
@ -1,25 +0,0 @@
|
|||
/*
|
||||
* 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 { apiIsOfType } from '@kbn/presentation-publishing';
|
||||
import { apiHasVisualizeConfig } from '@kbn/visualizations-plugin/public';
|
||||
import { isLensApi } from '@kbn/lens-plugin/public';
|
||||
import { MAP_SAVED_OBJECT_TYPE } from '../../../common/constants';
|
||||
import { isLegacyMapApi } from '../../legacy_visualizations/is_legacy_map';
|
||||
import { mapEmbeddablesSingleton } from '../../react_embeddable/map_embeddables_singleton';
|
||||
import type { SynchronizeMovementActionApi } from './types';
|
||||
|
||||
export function isCompatible(api: SynchronizeMovementActionApi) {
|
||||
if (!mapEmbeddablesSingleton.hasMultipleMaps()) {
|
||||
return false;
|
||||
}
|
||||
return (
|
||||
apiIsOfType(api, MAP_SAVED_OBJECT_TYPE) ||
|
||||
(isLensApi(api) && api.getSavedVis()?.visualizationType === 'lnsChoropleth') ||
|
||||
(apiHasVisualizeConfig(api) && isLegacyMapApi(api))
|
||||
);
|
||||
}
|
|
@ -15,22 +15,13 @@ import {
|
|||
EuiSwitch,
|
||||
EuiSwitchEvent,
|
||||
} from '@elastic/eui';
|
||||
import { createReactOverlays } from '@kbn/kibana-react-plugin/public';
|
||||
import { mapEmbeddablesSingleton } from '../../react_embeddable/map_embeddables_singleton';
|
||||
import { getCore } from '../../kibana_services';
|
||||
|
||||
export function openModal() {
|
||||
const { openModal: reactOverlaysOpenModal } = createReactOverlays(getCore());
|
||||
const modalSession = reactOverlaysOpenModal(
|
||||
<SynchronizeMovementModal onClose={() => modalSession.close()} />
|
||||
);
|
||||
}
|
||||
|
||||
interface Props {
|
||||
onClose: () => void;
|
||||
}
|
||||
|
||||
class SynchronizeMovementModal extends Component<Props> {
|
||||
export class SynchronizeMovementModal extends Component<Props> {
|
||||
_renderSwitches() {
|
||||
const mapPanels = mapEmbeddablesSingleton.getMapPanels();
|
||||
|
||||
|
|
|
@ -1,14 +0,0 @@
|
|||
/*
|
||||
* 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 } from '@kbn/presentation-publishing';
|
||||
import type { LensApi } from '@kbn/lens-plugin/public';
|
||||
import type { HasVisualizeConfig } from '@kbn/visualizations-plugin/public';
|
||||
|
||||
export type SynchronizeMovementActionApi =
|
||||
| HasType<'map' | 'visualization' | 'lens'>
|
||||
| Partial<LensApi | HasVisualizeConfig>;
|
|
@ -14,6 +14,7 @@ import {
|
|||
} from '@kbn/ui-actions-plugin/public';
|
||||
import { getUsageCollection } from '../kibana_services';
|
||||
import { APP_ID } from '../../common/constants';
|
||||
import { getMapsLink } from './get_maps_link';
|
||||
|
||||
import { getVisualizeCapabilities, getCore } from '../kibana_services';
|
||||
|
||||
|
@ -28,7 +29,6 @@ export const visualizeGeoFieldAction = createAction<VisualizeFieldContext>({
|
|||
return Boolean(!!getVisualizeCapabilities().show && context.dataViewSpec && context.fieldName);
|
||||
},
|
||||
getHref: async (context) => {
|
||||
const { getMapsLink } = await import('./get_maps_link');
|
||||
const { app, path } = await getMapsLink(context);
|
||||
|
||||
return getCore().application.getUrlForApp(app, {
|
||||
|
@ -37,7 +37,6 @@ export const visualizeGeoFieldAction = createAction<VisualizeFieldContext>({
|
|||
});
|
||||
},
|
||||
execute: async (context) => {
|
||||
const { getMapsLink } = await import('./get_maps_link');
|
||||
const { app, path, state } = await getMapsLink(context);
|
||||
|
||||
const usageCollection = getUsageCollection();
|
||||
|
|
|
@ -90,7 +90,8 @@
|
|||
"@kbn/embeddable-enhanced-plugin",
|
||||
"@kbn/presentation-containers",
|
||||
"@kbn/field-utils",
|
||||
"@kbn/react-hooks"
|
||||
"@kbn/react-hooks",
|
||||
"@kbn/react-kibana-mount",
|
||||
],
|
||||
"exclude": [
|
||||
"target/**/*",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue