Replace legacy MapEmbeddable with MapComponent in Obs UX solution (#182841)

## Summary

Replaces the Maps embeddable with a new MapComponent in the
Observability UX solution.

The Maps plugin now provides an easier to use MapComponent for
consumers. The legacy MapEmbeddable factory is also being removed as
part of https://github.com/elastic/kibana/issues/174960 which requires
making changes to consumers.


### For maintainers

- [ ] This was checked for breaking API changes and was [labeled
appropriately](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)
This commit is contained in:
Nick Peihl 2024-05-09 15:20:50 -04:00 committed by GitHub
parent 99e7bd3ff5
commit 49a5d5ecd0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 35 additions and 109 deletions

View file

@ -13,6 +13,7 @@ import { ViewMode } from '@kbn/embeddable-plugin/public';
import type { LayerDescriptor, MapCenterAndZoom, MapSettings } from '../../common/descriptor_types';
import { MapEmbeddable } from './map_embeddable';
import { createBasemapLayerDescriptor } from '../classes/layers/create_basemap_layer_descriptor';
import { RenderToolTipContent } from '../classes/tooltips/tooltip_property';
export interface Props {
title?: string;
@ -25,6 +26,7 @@ export interface Props {
isLayerTOCOpen?: boolean;
mapCenter?: MapCenterAndZoom;
onInitialRenderComplete?: () => void;
getTooltipRenderer?: () => RenderToolTipContent;
/*
* Set to false to exclude sharing attributes 'data-*'.
*/
@ -65,6 +67,10 @@ export class MapComponent extends Component<Props> {
timeRange: this.props.timeRange,
});
if (this.props.getTooltipRenderer) {
this._mapEmbeddable.setRenderTooltipContent(this.props.getTooltipRenderer());
}
if (this.props.onInitialRenderComplete) {
this._mapEmbeddable
.getOnRenderComplete$()

View file

@ -10,7 +10,6 @@ import React from 'react';
import { EmbeddedMap } from './embedded_map';
import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public';
import { embeddablePluginMock } from '@kbn/embeddable-plugin/public/mocks';
describe('Embedded Map', () => {
test('it renders', () => {
@ -26,19 +25,13 @@ describe('Embedded Map', () => {
});
});
const mockEmbeddable = embeddablePluginMock.createStartContract();
mockEmbeddable.getEmbeddableFactory = jest.fn().mockImplementation(() => ({
create: () => ({
reload: jest.fn(),
setRenderTooltipContent: jest.fn(),
setLayerList: jest.fn(),
}),
}));
const mockMapsStartService = {
Map: jest.fn().mockImplementation(() => <div data-test-subj="mockMap" />),
};
const mockCore: () => any[] = () => {
const core = {
embeddable: mockEmbeddable,
maps: mockMapsStartService,
};
return [core];

View file

@ -5,13 +5,9 @@
* 2.0.
*/
import React, { useEffect, useState, useRef } from 'react';
import { v4 as uuidv4 } from 'uuid';
import React from 'react';
import styled from 'styled-components';
import { MapEmbeddable, MapEmbeddableInput } from '@kbn/maps-plugin/public';
import { MAP_SAVED_OBJECT_TYPE } from '@kbn/maps-plugin/common';
import { ErrorEmbeddable, ViewMode, isErrorEmbeddable } from '@kbn/embeddable-plugin/public';
import type { RenderTooltipContentParams } from '@kbn/maps-plugin/public';
import { useLayerList } from './use_layer_list';
import { useLegacyUrlParams } from '../../../../context/url_params_context/use_url_params';
@ -38,7 +34,7 @@ const EmbeddedPanel = styled.div`
`;
export function EmbeddedMapComponent() {
const { rangeId, urlParams } = useLegacyUrlParams();
const { urlParams } = useLegacyUrlParams();
const { start, end, serviceName } = urlParams;
@ -46,35 +42,7 @@ export function EmbeddedMapComponent() {
const layerList = useLayerList();
const [embeddable, setEmbeddable] = useState<MapEmbeddable | ErrorEmbeddable | undefined>();
const embeddableRoot: React.RefObject<HTMLDivElement> = useRef<HTMLDivElement>(null);
const { embeddable: embeddablePlugin, maps } = useKibanaServices();
if (!embeddablePlugin) {
throw new Error('Embeddable start plugin not found');
}
const factory = embeddablePlugin.getEmbeddableFactory(MAP_SAVED_OBJECT_TYPE);
const input: MapEmbeddableInput = {
attributes: { title: '' },
id: uuidv4(),
filters: mapFilters,
viewMode: ViewMode.VIEW,
isLayerTOCOpen: false,
query: {
query: 'transaction.type : "page-load"',
language: 'kuery',
},
...(start && {
timeRange: {
from: new Date(start!).toISOString(),
to: new Date(end!).toISOString(),
},
}),
hideFilterActions: true,
};
const { maps } = useKibanaServices();
function renderTooltipContent({
addFilters,
@ -95,71 +63,30 @@ export function EmbeddedMapComponent() {
return <MapToolTip {...props} features={features} />;
}
useEffect(() => {
if (embeddable != null && serviceName) {
embeddable.updateInput({ filters: mapFilters });
embeddable.reload();
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [mapFilters]);
// DateRange updated useEffect
useEffect(() => {
if (embeddable != null && start != null && end != null) {
const timeRange = {
from: new Date(start).toISOString(),
to: new Date(end).toISOString(),
};
embeddable.updateInput({ timeRange });
embeddable.reload();
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [start, end, rangeId]);
useEffect(() => {
async function setupEmbeddable() {
if (!factory) {
throw new Error('Map embeddable not found.');
}
const embeddableObject: any = await factory.create({
...input,
title: 'Visitors by region',
});
if (embeddableObject && !isErrorEmbeddable(embeddableObject)) {
embeddableObject.setRenderTooltipContent(renderTooltipContent);
const basemapLayerDescriptor = maps
? await maps.createLayerDescriptors.createBasemapLayerDescriptor()
: null;
if (basemapLayerDescriptor) {
layerList.unshift(basemapLayerDescriptor);
}
await embeddableObject.setLayerList(layerList);
}
setEmbeddable(embeddableObject);
}
setupEmbeddable();
// we want this effect to execute exactly once after the component mounts
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
// We can only render after embeddable has already initialized
useEffect(() => {
if (embeddableRoot.current && embeddable && serviceName) {
embeddable.render(embeddableRoot.current);
}
}, [embeddable, embeddableRoot, serviceName]);
return (
<EmbeddedPanel>
<div
data-test-subj="xpack.ux.regionMap.embeddedPanel"
className="embPanel__content"
ref={embeddableRoot}
/>
<div data-test-subj="xpack.ux.regionMap.embeddedPanel" className="embPanel__content">
{serviceName &&
maps &&
maps.Map({
title: 'Visitors by region',
filters: mapFilters,
isLayerTOCOpen: false,
query: {
query: 'transaction.type : "page-load"',
language: 'kuery',
},
...(start && {
timeRange: {
from: new Date(start!).toISOString(),
to: new Date(end!).toISOString(),
},
}),
hideFilterActions: true,
layerList,
getTooltipRenderer: () => renderTooltipContent,
})}
</div>
</EmbeddedPanel>
);
}