From 2dd060c85fc393beb15a61e0ce8bac8e23a62ad7 Mon Sep 17 00:00:00 2001 From: Caue Marcondes Date: Wed, 28 Jan 2026 14:18:35 -0500 Subject: [PATCH 1/7] [Traces] Remove APM unified trace waterall embeddable registration --- .../services/discover_features/types.ts | 19 +- .../full_screen_waterfall/index.test.tsx | 126 ++-------- .../full_screen_waterfall/index.tsx | 104 ++++---- .../components/trace_waterfall/index.test.tsx | 67 ----- .../components/trace_waterfall/index.tsx | 51 ++-- .../traces/doc_viewer_overview/overview.tsx | 2 +- .../packages/shared/kbn-apm-types/index.ts | 2 + .../src/focused_trace_waterfall.ts} | 8 +- .../kbn-apm-types/src/full_trace_waterfall.ts | 23 ++ .../focused_trace_waterfall_fetcher.tsx} | 26 +- .../full_trace_waterfall_fetcher.tsx} | 33 +-- .../shared}/trace_waterfall/loading.tsx | 0 .../embeddable/register_embeddables.tsx | 9 - .../react_embeddable_factory.tsx | 232 ------------------ .../plugins/apm/public/plugin.ts | 14 +- 15 files changed, 185 insertions(+), 531 deletions(-) delete mode 100644 src/platform/plugins/shared/unified_doc_viewer/public/components/observability/traces/components/trace_waterfall/index.test.tsx rename x-pack/{solutions/observability/plugins/apm/public/embeddable/trace_waterfall/constant.ts => platform/packages/shared/kbn-apm-types/src/focused_trace_waterfall.ts} (66%) create mode 100644 x-pack/platform/packages/shared/kbn-apm-types/src/full_trace_waterfall.ts rename x-pack/solutions/observability/plugins/apm/public/{embeddable/trace_waterfall/focused_trace_waterfall_embeddable.tsx => components/shared/focused_trace_waterfall/focused_trace_waterfall_fetcher.tsx} (65%) rename x-pack/solutions/observability/plugins/apm/public/{embeddable/trace_waterfall/trace_waterfall_embeddable.tsx => components/shared/trace_waterfall/full_trace_waterfall_fetcher.tsx} (72%) rename x-pack/solutions/observability/plugins/apm/public/{embeddable => components/shared}/trace_waterfall/loading.tsx (100%) delete mode 100644 x-pack/solutions/observability/plugins/apm/public/embeddable/trace_waterfall/react_embeddable_factory.tsx diff --git a/src/platform/plugins/shared/discover_shared/public/services/discover_features/types.ts b/src/platform/plugins/shared/discover_shared/public/services/discover_features/types.ts index 593fe0970ffc9..583116f6472b4 100644 --- a/src/platform/plugins/shared/discover_shared/public/services/discover_features/types.ts +++ b/src/platform/plugins/shared/discover_shared/public/services/discover_features/types.ts @@ -16,9 +16,10 @@ import type { ErrorsByTraceId, TraceRootSpan, UnifiedSpanDocument, + FocusedTraceWaterfallProps, + FullTraceWaterfallProps, } from '@kbn/apm-types'; -import type { ProcessorEvent } from '@kbn/apm-types-shared'; -import type { HistogramItem } from '@kbn/apm-types-shared'; +import type { HistogramItem, ProcessorEvent } from '@kbn/apm-types-shared'; import type { DataView } from '@kbn/data-views-plugin/common'; import type React from 'react'; import type { IndicatorType } from '@kbn/slo-schema'; @@ -126,6 +127,16 @@ export type SecuritySolutionFeature = /** **************** Observability Traces ****************/ +interface ObservabilityFocusedTraceWaterfallFeature { + id: 'observability-focused-trace-waterfall'; + render: (props: FocusedTraceWaterfallProps) => JSX.Element; +} + +interface ObservabilityFullTraceWaterfallFeature { + id: 'observability-full-trace-waterfall'; + render: (props: FullTraceWaterfallProps) => JSX.Element; +} + export interface ObservabilityTracesSpanLinksFeature { id: 'observability-traces-fetch-span-links'; fetchSpanLinks: ( @@ -224,7 +235,9 @@ export type ObservabilityTracesFeature = | ObservabilityTracesFetchRootSpanByTraceIdFeature | ObservabilityTracesFetchSpanFeature | ObservabilityTracesFetchLatencyOverallTransactionDistributionFeature - | ObservabilityTracesFetchLatencyOverallSpanDistributionFeature; + | ObservabilityTracesFetchLatencyOverallSpanDistributionFeature + | ObservabilityFocusedTraceWaterfallFeature + | ObservabilityFullTraceWaterfallFeature; /** ****************************************************************************************/ diff --git a/src/platform/plugins/shared/unified_doc_viewer/public/components/observability/traces/components/full_screen_waterfall/index.test.tsx b/src/platform/plugins/shared/unified_doc_viewer/public/components/observability/traces/components/full_screen_waterfall/index.test.tsx index 00f9daa373de7..103cdccf2a613 100644 --- a/src/platform/plugins/shared/unified_doc_viewer/public/components/observability/traces/components/full_screen_waterfall/index.test.tsx +++ b/src/platform/plugins/shared/unified_doc_viewer/public/components/observability/traces/components/full_screen_waterfall/index.test.tsx @@ -7,14 +7,12 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import React from 'react'; -import { render, screen, act, waitFor } from '@testing-library/react'; -import { - FullScreenWaterfall, - type FullScreenWaterfallProps, - EUI_FLYOUT_BODY_OVERFLOW_CLASS, -} from '.'; import { dataViewMock } from '@kbn/discover-utils/src/__mocks__'; +import { render, screen } from '@testing-library/react'; +import React from 'react'; +import { FullScreenWaterfall, type FullScreenWaterfallProps } from '.'; +import { setUnifiedDocViewerServices } from '../../../../../plugin'; +import type { UnifiedDocViewerServices } from '../../../../../types'; let capturedCallbacks: any = null; @@ -62,32 +60,25 @@ describe('FullScreenWaterfall', () => { onExitFullScreen: jest.fn(), }; + beforeAll(() => { + setUnifiedDocViewerServices({ + discoverShared: { + features: { + registry: { + getById: () => ({ + render: () =>
FullTraceWaterfall
, + }), + }, + }, + }, + } as unknown as UnifiedDocViewerServices); + }); + beforeEach(() => { jest.clearAllMocks(); capturedCallbacks = null; }); - it('should render APM trace waterfall embeddable with hidden chrome', () => { - render(); - - const embeddable = screen.getByTestId('embeddableRenderer'); - expect(embeddable).toHaveAttribute('data-type', 'APM_TRACE_WATERFALL_EMBEDDABLE'); - expect(embeddable).toHaveAttribute('data-hide-panel-chrome', 'true'); - }); - - it('wraps EmbeddableRenderer with CSS override for proper layout', () => { - const { container } = render(); - - const embeddable = container.querySelector('[data-test-subj="embeddableRenderer"]'); - expect(embeddable).toBeInTheDocument(); - - const wrapper = embeddable?.parentElement; - expect(wrapper).toHaveStyleRule('width', '100%'); - expect(wrapper).toHaveStyleRule('display', 'block!important', { - target: '.embPanel__content', - }); - }); - it('should not display nested flyouts initially', () => { render(); @@ -95,82 +86,15 @@ describe('FullScreenWaterfall', () => { expect(screen.queryByTestId('logsFlyout')).not.toBeInTheDocument(); }); - describe('nested flyout interactions', () => { - it('should display span details when clicking a waterfall node', () => { - render(); - - act(() => { - capturedCallbacks.onNodeClick('test-span-id'); - }); - - const spanFlyout = screen.getByTestId('spanFlyout'); - expect(spanFlyout).toHaveAttribute('data-trace-id', 'test-trace-id'); - expect(spanFlyout).toHaveAttribute('data-span-id', 'test-span-id'); - expect(spanFlyout).not.toHaveAttribute('data-active-section'); - expect(screen.queryByTestId('logsFlyout')).not.toBeInTheDocument(); - }); - - it('should display span errors table when clicking an error with multiple occurrences', () => { - render(); - - act(() => { - capturedCallbacks.onErrorClick({ - traceId: 'test-trace-id', - docId: 'test-error-doc-id', - errorCount: 5, - }); - }); - - const spanFlyout = screen.getByTestId('spanFlyout'); - expect(spanFlyout).toHaveAttribute('data-active-section', 'errors-table'); - expect(screen.queryByTestId('logsFlyout')).not.toBeInTheDocument(); - }); - - it('should display log details when clicking a single error', () => { - render(); - - act(() => { - capturedCallbacks.onErrorClick({ - traceId: 'test-trace-id', - docId: 'test-doc-id', - errorCount: 1, - errorDocId: 'test-error-log-id', - }); - }); - - expect(screen.getByTestId('logsFlyout')).toHaveAttribute('data-id', 'test-error-log-id'); - expect(screen.queryByTestId('spanFlyout')).not.toBeInTheDocument(); - }); - - it('should not open any flyout when clicking a single error without errorDocId', () => { - render(); - - act(() => { - capturedCallbacks.onErrorClick({ - traceId: 'test-trace-id', - docId: 'test-doc-id', - errorCount: 1, - }); - }); + it('should display the full trace waterfall', () => { + render(); - expect(screen.queryByTestId('spanFlyout')).not.toBeInTheDocument(); - expect(screen.queryByTestId('logsFlyout')).not.toBeInTheDocument(); - }); + expect(screen.getByTestId('fullTraceWaterfall')).toBeInTheDocument(); }); - describe('scrollElement integration', () => { - it('should pass scrollElement with correct EUI class to embeddable', async () => { - render(); - - await waitFor(() => { - expect(screen.getByTestId('embeddableRenderer')).toBeInTheDocument(); - }); + it('should not display the full trace waterfall', () => { + render(); - expect(capturedCallbacks.scrollElement).not.toBeNull(); - expect(capturedCallbacks.scrollElement).toBeInstanceOf(Element); - expect( - capturedCallbacks.scrollElement.classList.contains(EUI_FLYOUT_BODY_OVERFLOW_CLASS) - ).toBe(true); - }); + expect(screen.queryByTestId('fullTraceWaterfall')).not.toBeInTheDocument(); }); }); diff --git a/src/platform/plugins/shared/unified_doc_viewer/public/components/observability/traces/components/full_screen_waterfall/index.tsx b/src/platform/plugins/shared/unified_doc_viewer/public/components/observability/traces/components/full_screen_waterfall/index.tsx index 389ce18c57cca..72d4738da60a9 100644 --- a/src/platform/plugins/shared/unified_doc_viewer/public/components/observability/traces/components/full_screen_waterfall/index.tsx +++ b/src/platform/plugins/shared/unified_doc_viewer/public/components/observability/traces/components/full_screen_waterfall/index.tsx @@ -12,19 +12,18 @@ import { EuiFlyoutBody, EuiFlyoutHeader, EuiTitle, - useGeneratedHtmlId, useEuiTheme, + useGeneratedHtmlId, } from '@elastic/eui'; -import { css } from '@emotion/react'; -import { EmbeddableRenderer } from '@kbn/embeddable-plugin/public'; import { i18n } from '@kbn/i18n'; import type { DocViewRenderProps } from '@kbn/unified-doc-viewer/types'; import React, { useCallback, useState } from 'react'; +import { getUnifiedDocViewerServices } from '../../../../../plugin'; import type { TraceOverviewSections } from '../../doc_viewer_overview/overview'; -import type { spanFlyoutId as spanFlyoutIdType } from './waterfall_flyout/span_flyout'; -import { SpanFlyout, spanFlyoutId } from './waterfall_flyout/span_flyout'; import type { logsFlyoutId as logsFlyoutIdType } from './waterfall_flyout/logs_flyout'; import { LogsFlyout, logsFlyoutId } from './waterfall_flyout/logs_flyout'; +import type { spanFlyoutId as spanFlyoutIdType } from './waterfall_flyout/span_flyout'; +import { SpanFlyout, spanFlyoutId } from './waterfall_flyout/span_flyout'; export const EUI_FLYOUT_BODY_OVERFLOW_CLASS = 'euiFlyoutBody__overflow'; @@ -45,6 +44,10 @@ export const FullScreenWaterfall = ({ serviceName, onExitFullScreen, }: FullScreenWaterfallProps) => { + const { discoverShared } = getUnifiedDocViewerServices(); + const FullTraceWaterfall = discoverShared.features.registry.getById( + 'observability-full-trace-waterfall' + )?.render; const { euiTheme } = useEuiTheme(); const [docId, setDocId] = useState(null); const [docIndex, setDocIndex] = useState(undefined); @@ -85,43 +88,6 @@ export const FullScreenWaterfall = ({ } }, []); - const getParentApi = useCallback(() => { - return { - getSerializedStateForChild: () => ({ - traceId, - rangeFrom, - rangeTo, - serviceName, - scrollElement, - onErrorClick: (params: { - traceId: string; - docId: string; - errorCount: number; - errorDocId?: string; - docIndex?: string; - }) => { - if (params.errorCount > 1) { - setActiveFlyoutId(spanFlyoutId); - setActiveSection('errors-table'); - setDocId(params.docId); - setDocIndex(undefined); - } else if (params.errorDocId) { - setActiveFlyoutId(logsFlyoutId); - setDocId(params.errorDocId); - setDocIndex(params.docIndex); - } - }, - onNodeClick: (nodeSpanId: string) => { - setActiveSection(undefined); - setDocId(nodeSpanId); - setDocIndex(undefined); - setActiveFlyoutId(spanFlyoutId); - }, - mode: 'full', - }), - }; - }, [traceId, rangeFrom, rangeTo, serviceName, scrollElement]); - function handleCloseFlyout() { setActiveFlyoutId(null); setActiveSection(undefined); @@ -129,6 +95,36 @@ export const FullScreenWaterfall = ({ setDocIndex(undefined); } + function handleNodeClick(nodeSpanId: string) { + setActiveSection(undefined); + setDocId(nodeSpanId); + setDocIndex(undefined); + setActiveFlyoutId(spanFlyoutId); + } + + function handleErrorClick(params: { + traceId: string; + docId: string; + errorCount: number; + errorDocId?: string; + docIndex?: string; + }) { + if (params.errorCount > 1) { + setActiveFlyoutId(spanFlyoutId); + setActiveSection('errors-table'); + setDocId(params.docId); + setDocIndex(undefined); + } else if (params.errorDocId) { + setActiveFlyoutId(logsFlyoutId); + setDocId(params.errorDocId); + setDocIndex(params.docIndex); + } + } + + if (!FullTraceWaterfall) { + return null; + } + return ( - {scrollElement ? ( - + {scrollElement && serviceName ? ( + ) : null} diff --git a/src/platform/plugins/shared/unified_doc_viewer/public/components/observability/traces/components/trace_waterfall/index.test.tsx b/src/platform/plugins/shared/unified_doc_viewer/public/components/observability/traces/components/trace_waterfall/index.test.tsx deleted file mode 100644 index fc26d1e28bd68..0000000000000 --- a/src/platform/plugins/shared/unified_doc_viewer/public/components/observability/traces/components/trace_waterfall/index.test.tsx +++ /dev/null @@ -1,67 +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", the "GNU Affero General Public License v3.0 only", and the "Server Side - * Public License v 1"; you may not use this file except in compliance with, at - * your election, the "Elastic License 2.0", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import React from 'react'; -import { render } from '@testing-library/react'; -import { TraceWaterfall } from '.'; -import { createStubDataView } from '@kbn/data-views-plugin/common/data_view.stub'; - -jest.mock('../../../../../plugin', () => ({ - getUnifiedDocViewerServices: () => ({ - data: { - query: { - timefilter: { - timefilter: { - getAbsoluteTime: () => ({ from: '2024-01-01', to: '2024-01-02' }), - }, - }, - }, - }, - }), -})); - -jest.mock('@kbn/embeddable-plugin/public', () => ({ - EmbeddableRenderer: () =>
, -})); - -jest.mock('../full_screen_waterfall', () => ({ - FullScreenWaterfall: () => null, -})); - -jest.mock('./full_screen_waterfall_tour_step', () => ({ - TraceWaterfallTourStep: () => null, -})); - -jest.mock('../../../../..', () => ({ - ContentFrameworkSection: ({ children }: { children: React.ReactNode }) =>
{children}
, -})); - -describe('TraceWaterfall', () => { - const dataView = createStubDataView({ - spec: { - id: 'test-dataview', - title: 'test-pattern', - timeFieldName: '@timestamp', - }, - }); - - it('wraps EmbeddableRenderer with CSS override for proper layout', () => { - const { container } = render(); - - const embeddable = container.querySelector('[data-test-subj="embeddable-renderer"]'); - expect(embeddable).toBeInTheDocument(); - - // Verify the wrapper exists with the CSS override - const wrapper = embeddable?.parentElement; - expect(wrapper).toHaveStyleRule('width', '100%'); - expect(wrapper).toHaveStyleRule('display', 'block!important', { - target: '.embPanel__content', - }); - }); -}); diff --git a/src/platform/plugins/shared/unified_doc_viewer/public/components/observability/traces/components/trace_waterfall/index.tsx b/src/platform/plugins/shared/unified_doc_viewer/public/components/observability/traces/components/trace_waterfall/index.tsx index 08aededd90cca..3d090f41007b1 100644 --- a/src/platform/plugins/shared/unified_doc_viewer/public/components/observability/traces/components/trace_waterfall/index.tsx +++ b/src/platform/plugins/shared/unified_doc_viewer/public/components/observability/traces/components/trace_waterfall/index.tsx @@ -7,12 +7,10 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import { EmbeddableRenderer } from '@kbn/embeddable-plugin/public'; +import { EuiDelayRender } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import type { DocViewRenderProps } from '@kbn/unified-doc-viewer/types'; -import React, { useCallback, useState } from 'react'; -import { EuiDelayRender } from '@elastic/eui'; -import { css } from '@emotion/react'; +import React, { useState } from 'react'; import { ContentFrameworkSection } from '../../../../..'; import { getUnifiedDocViewerServices } from '../../../../../plugin'; import { FullScreenWaterfall } from '../full_screen_waterfall'; @@ -39,22 +37,16 @@ const sectionTitle = i18n.translate('unifiedDocViewer.observability.traces.trace }); export function TraceWaterfall({ traceId, docId, serviceName, dataView }: Props) { - const { data } = getUnifiedDocViewerServices(); + const { data, discoverShared } = getUnifiedDocViewerServices(); + const FocusedTraceWaterfall = discoverShared.features.registry.getById( + 'observability-focused-trace-waterfall' + )?.render; const [showFullScreenWaterfall, setShowFullScreenWaterfall] = useState(false); const { from: rangeFrom, to: rangeTo } = data.query.timefilter.timefilter.getAbsoluteTime(); - const getParentApi = useCallback( - () => ({ - getSerializedStateForChild: () => ({ - traceId, - rangeFrom, - rangeTo, - docId, - mode: 'summary', - }), - }), - [docId, rangeFrom, rangeTo, traceId] - ); + if (!FocusedTraceWaterfall) { + return null; + } const actionId = 'traceWaterfallFullScreenAction'; return ( @@ -86,25 +78,14 @@ export function TraceWaterfall({ traceId, docId, serviceName, dataView }: Props) }, ]} > - {/* TODO: This is a workaround for layout issues when using hidePanelChrome outside of Dashboard. - The PresentationPanel applies flex styles (.embPanel__content) that cause width: 0 in non-Dashboard contexts. - This should be removed once PresentationPanel properly supports hidePanelChrome as an out-of-the-box solution. - Issue: https://github.com/elastic/kibana/issues/248307 - */} -
- -
+ ) : null} void; + onErrorClick?: FullTraceWaterfallOnErrorClick; +} + +export type FullTraceWaterfallOnErrorClick = (params: { + traceId: string; + docId: string; + errorCount: number; + errorDocId?: string; + docIndex?: string; +}) => void; diff --git a/x-pack/solutions/observability/plugins/apm/public/embeddable/trace_waterfall/focused_trace_waterfall_embeddable.tsx b/x-pack/solutions/observability/plugins/apm/public/components/shared/focused_trace_waterfall/focused_trace_waterfall_fetcher.tsx similarity index 65% rename from x-pack/solutions/observability/plugins/apm/public/embeddable/trace_waterfall/focused_trace_waterfall_embeddable.tsx rename to x-pack/solutions/observability/plugins/apm/public/components/shared/focused_trace_waterfall/focused_trace_waterfall_fetcher.tsx index 78079947003c8..3ad65c5469a76 100644 --- a/x-pack/solutions/observability/plugins/apm/public/embeddable/trace_waterfall/focused_trace_waterfall_embeddable.tsx +++ b/x-pack/solutions/observability/plugins/apm/public/components/shared/focused_trace_waterfall/focused_trace_waterfall_fetcher.tsx @@ -4,19 +4,27 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { EuiCallOut } from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; import React from 'react'; -import { FocusedTraceWaterfall } from '../../components/shared/focused_trace_waterfall'; -import { isPending, useFetcher } from '../../hooks/use_fetcher'; -import { Loading } from './loading'; -import type { ApmTraceWaterfallEmbeddableFocusedProps } from './react_embeddable_factory'; -export function FocusedTraceWaterfallEmbeddable({ +import { i18n } from '@kbn/i18n'; +import type { FocusedTraceWaterfallProps } from '@kbn/apm-types'; +import type { CoreStart } from '@kbn/core/public'; +import { EuiCallOut } from '@elastic/eui'; +import { isPending, useFetcher } from '../../../hooks/use_fetcher'; +import { createCallApmApi } from '../../../services/rest/create_call_apm_api'; +import { FocusedTraceWaterfall } from '.'; +import { Loading } from '../trace_waterfall/loading'; + +export function createFocusedTraceWaterfallFetcher({ core }: { core: CoreStart }) { + createCallApmApi(core); + return (props: FocusedTraceWaterfallProps) => ; +} + +function FocusedTraceWaterfallFetcher({ + traceId, rangeFrom, rangeTo, - traceId, docId, -}: Omit) { +}: FocusedTraceWaterfallProps) { const { data, status } = useFetcher( (callApmApi) => { return callApmApi('GET /internal/apm/unified_traces/{traceId}/summary', { diff --git a/x-pack/solutions/observability/plugins/apm/public/embeddable/trace_waterfall/trace_waterfall_embeddable.tsx b/x-pack/solutions/observability/plugins/apm/public/components/shared/trace_waterfall/full_trace_waterfall_fetcher.tsx similarity index 72% rename from x-pack/solutions/observability/plugins/apm/public/embeddable/trace_waterfall/trace_waterfall_embeddable.tsx rename to x-pack/solutions/observability/plugins/apm/public/components/shared/trace_waterfall/full_trace_waterfall_fetcher.tsx index 1d83955991516..83ae40c306eb3 100644 --- a/x-pack/solutions/observability/plugins/apm/public/embeddable/trace_waterfall/trace_waterfall_embeddable.tsx +++ b/x-pack/solutions/observability/plugins/apm/public/components/shared/trace_waterfall/full_trace_waterfall_fetcher.tsx @@ -4,27 +4,31 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ + +import { i18n } from '@kbn/i18n'; import React from 'react'; +import type { CoreStart } from '@kbn/core/public'; +import type { FullTraceWaterfallProps } from '@kbn/apm-types'; import { EuiCallOut } from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; -import { isPending, useFetcher } from '../../hooks/use_fetcher'; +import { createCallApmApi } from '../../../services/rest/create_call_apm_api'; +import { isPending, useFetcher } from '../../../hooks/use_fetcher'; import { Loading } from './loading'; -import type { ApmTraceWaterfallEmbeddableEntryProps } from './react_embeddable_factory'; -import { TraceWaterfall } from '../../components/shared/trace_waterfall'; +import { TraceWaterfall } from '.'; -export function TraceWaterfallEmbeddable({ - serviceName, +export function createFullTraceWaterfallFetcher({ core }: { core: CoreStart }) { + createCallApmApi(core); + return (props: FullTraceWaterfallProps) => ; +} + +export function FullTraceWaterfallFetcher({ + traceId, rangeFrom, rangeTo, - traceId, + serviceName, scrollElement, onNodeClick, - getRelatedErrorsHref, onErrorClick, - mode, -}: ApmTraceWaterfallEmbeddableEntryProps) { - const isFiltered = mode === 'filtered'; - +}: FullTraceWaterfallProps) { const { data, status } = useFetcher( (callApmApi) => { return callApmApi('GET /internal/apm/unified_traces/{traceId}', { @@ -33,12 +37,11 @@ export function TraceWaterfallEmbeddable({ query: { start: rangeFrom, end: rangeTo, - serviceName: isFiltered ? serviceName : undefined, }, }, }); }, - [rangeFrom, rangeTo, traceId, isFiltered, serviceName] + [rangeFrom, rangeTo, traceId] ); if (isPending(status)) { @@ -65,12 +68,10 @@ export function TraceWaterfallEmbeddable({ errors={data.errors} onClick={onNodeClick} scrollElement={scrollElement} - getRelatedErrorsHref={getRelatedErrorsHref} isEmbeddable showLegend serviceName={serviceName} onErrorClick={onErrorClick} - isFiltered={isFiltered} agentMarks={data.agentMarks} showCriticalPathControl /> diff --git a/x-pack/solutions/observability/plugins/apm/public/embeddable/trace_waterfall/loading.tsx b/x-pack/solutions/observability/plugins/apm/public/components/shared/trace_waterfall/loading.tsx similarity index 100% rename from x-pack/solutions/observability/plugins/apm/public/embeddable/trace_waterfall/loading.tsx rename to x-pack/solutions/observability/plugins/apm/public/components/shared/trace_waterfall/loading.tsx diff --git a/x-pack/solutions/observability/plugins/apm/public/embeddable/register_embeddables.tsx b/x-pack/solutions/observability/plugins/apm/public/embeddable/register_embeddables.tsx index 2823e62a321f6..60627b81c8da0 100644 --- a/x-pack/solutions/observability/plugins/apm/public/embeddable/register_embeddables.tsx +++ b/x-pack/solutions/observability/plugins/apm/public/embeddable/register_embeddables.tsx @@ -13,7 +13,6 @@ import { APM_ALERTING_LATENCY_CHART_EMBEDDABLE, APM_ALERTING_THROUGHPUT_CHART_EMBEDDABLE, } from './alerting/constants'; -import { APM_TRACE_WATERFALL_EMBEDDABLE } from './trace_waterfall/constant'; export async function registerEmbeddables( deps: Omit @@ -50,12 +49,4 @@ export async function registerEmbeddables( pluginsStart, }); }); - - registerReactEmbeddableFactory(APM_TRACE_WATERFALL_EMBEDDABLE, async () => { - const { getApmTraceWaterfallEmbeddableFactory } = await import( - './trace_waterfall/react_embeddable_factory' - ); - - return getApmTraceWaterfallEmbeddableFactory({ ...deps, coreStart, pluginsStart }); - }); } diff --git a/x-pack/solutions/observability/plugins/apm/public/embeddable/trace_waterfall/react_embeddable_factory.tsx b/x-pack/solutions/observability/plugins/apm/public/embeddable/trace_waterfall/react_embeddable_factory.tsx deleted file mode 100644 index 79464828356d4..0000000000000 --- a/x-pack/solutions/observability/plugins/apm/public/embeddable/trace_waterfall/react_embeddable_factory.tsx +++ /dev/null @@ -1,232 +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 { DefaultEmbeddableApi, EmbeddableFactory } from '@kbn/embeddable-plugin/public'; -import type { SerializedTitles } from '@kbn/presentation-publishing'; -import { - initializeTitleManager, - titleComparators, - useBatchedPublishingSubjects, -} from '@kbn/presentation-publishing'; -import React from 'react'; -import { BehaviorSubject, map, merge } from 'rxjs'; -import { initializeUnsavedChanges } from '@kbn/presentation-containers'; -import { KibanaSectionErrorBoundary } from '@kbn/shared-ux-error-boundary'; -import { i18n } from '@kbn/i18n'; -import type { IWaterfallGetRelatedErrorsHref } from '../../../common/waterfall/typings'; -import { ApmEmbeddableContext } from '../embeddable_context'; -import type { EmbeddableDeps } from '../types'; -import { APM_TRACE_WATERFALL_EMBEDDABLE } from './constant'; -import { TraceWaterfallEmbeddable } from './trace_waterfall_embeddable'; -import { FocusedTraceWaterfallEmbeddable } from './focused_trace_waterfall_embeddable'; -import type { OnErrorClick } from '../../components/shared/trace_waterfall/trace_waterfall_context'; - -interface BaseProps { - traceId: string; - rangeFrom: string; - rangeTo: string; -} - -export interface ApmTraceWaterfallEmbeddableFocusedProps extends BaseProps, SerializedTitles { - docId: string; - mode: 'summary'; -} - -export interface ApmTraceWaterfallEmbeddableEntryProps extends BaseProps, SerializedTitles { - serviceName: string; - displayLimit?: number; - scrollElement?: Element; - onNodeClick?: (nodeSpanId: string) => void; - getRelatedErrorsHref?: IWaterfallGetRelatedErrorsHref; - onErrorClick?: OnErrorClick; - mode: 'full' | 'filtered'; -} - -export type ApmTraceWaterfallEmbeddableProps = - | ApmTraceWaterfallEmbeddableFocusedProps - | ApmTraceWaterfallEmbeddableEntryProps; - -export const getApmTraceWaterfallEmbeddableFactory = (deps: EmbeddableDeps) => { - const factory: EmbeddableFactory< - ApmTraceWaterfallEmbeddableProps, - DefaultEmbeddableApi - > = { - type: APM_TRACE_WATERFALL_EMBEDDABLE, - buildEmbeddable: async ({ initialState, finalizeApi, uuid, parentApi }) => { - const state = initialState; - const titleManager = initializeTitleManager(state); - const serviceName$ = new BehaviorSubject('serviceName' in state ? state.serviceName : ''); - const traceId$ = new BehaviorSubject(state.traceId); - const rangeFrom$ = new BehaviorSubject(state.rangeFrom); - const rangeTo$ = new BehaviorSubject(state.rangeTo); - const mode$ = new BehaviorSubject(state.mode); - const displayLimit$ = new BehaviorSubject('displayLimit' in state ? state.displayLimit : 0); - const docId$ = new BehaviorSubject('docId' in state ? state.docId : ''); - const scrollElement$ = new BehaviorSubject( - 'scrollElement' in state ? state.scrollElement : undefined - ); - const onNodeClick$ = new BehaviorSubject( - 'onNodeClick' in state ? state.onNodeClick : undefined - ); - const getRelatedErrorsHref$ = new BehaviorSubject( - 'getRelatedErrorsHref' in state ? state.getRelatedErrorsHref : undefined - ); - const onErrorClick$ = new BehaviorSubject( - 'onErrorClick' in state ? state.onErrorClick : undefined - ); - - function serializeState() { - return { - ...titleManager.getLatestState(), - serviceName: serviceName$.getValue(), - traceId: traceId$.getValue(), - rangeFrom: rangeFrom$.getValue(), - rangeTo: rangeTo$.getValue(), - displayLimit: displayLimit$.getValue(), - docId: docId$.getValue(), - scrollElement: scrollElement$.getValue(), - onNodeClick: onNodeClick$.getValue(), - getRelatedErrorsHref: getRelatedErrorsHref$.getValue(), - onErrorClick: onErrorClick$.getValue(), - mode: mode$.getValue(), - }; - } - - const unsavedChangesApi = initializeUnsavedChanges({ - uuid, - parentApi, - serializeState, - anyStateChange$: merge( - titleManager.anyStateChange$, - serviceName$, - traceId$, - rangeFrom$, - rangeTo$, - displayLimit$, - docId$, - scrollElement$, - onNodeClick$, - getRelatedErrorsHref$, - onErrorClick$, - mode$ - ).pipe(map(() => undefined)), - getComparators: () => { - return { - ...titleComparators, - serviceName: 'referenceEquality', - traceId: 'referenceEquality', - rangeFrom: 'referenceEquality', - rangeTo: 'referenceEquality', - displayLimit: 'referenceEquality', - docId: 'referenceEquality', - scrollElement: 'referenceEquality', - onNodeClick: 'referenceEquality', - getRelatedErrorsHref: 'referenceEquality', - onErrorClick: 'referenceEquality', - mode: 'referenceEquality', - }; - }, - onReset: (lastSaved) => { - titleManager.reinitializeState(lastSaved); - - // reset base state - traceId$.next(lastSaved?.traceId ?? ''); - rangeFrom$.next(lastSaved?.rangeFrom ?? ''); - rangeTo$.next(lastSaved?.rangeTo ?? ''); - mode$.next(lastSaved?.mode ?? 'summary'); - - // reset entry state - const entryState = lastSaved as ApmTraceWaterfallEmbeddableEntryProps; - serviceName$.next(entryState?.serviceName ?? ''); - displayLimit$.next(entryState?.displayLimit ?? 0); - scrollElement$.next(entryState?.scrollElement ?? undefined); - onNodeClick$.next(entryState?.onNodeClick ?? undefined); - getRelatedErrorsHref$.next(entryState?.getRelatedErrorsHref ?? undefined); - onErrorClick$.next(entryState?.onErrorClick ?? undefined); - - // reset focused state - const focusedState = lastSaved as ApmTraceWaterfallEmbeddableFocusedProps; - docId$.next(focusedState?.docId ?? ''); - }, - }); - - const api = finalizeApi({ - ...unsavedChangesApi, - ...titleManager.api, - serializeState, - }); - - return { - api, - Component: () => { - const [ - serviceName, - traceId, - rangeFrom, - rangeTo, - displayLimit, - docId, - scrollElement, - onNodeClick, - getRelatedErrorsHref, - onErrorClick, - mode, - ] = useBatchedPublishingSubjects( - serviceName$, - traceId$, - rangeFrom$, - rangeTo$, - displayLimit$, - docId$, - scrollElement$, - onNodeClick$, - getRelatedErrorsHref$, - onErrorClick$, - mode$ - ); - const content = - mode === 'summary' ? ( - - ) : ( - - ); - - return ( - - - {content} - - - ); - }, - }; - }, - }; - return factory; -}; diff --git a/x-pack/solutions/observability/plugins/apm/public/plugin.ts b/x-pack/solutions/observability/plugins/apm/public/plugin.ts index cd218e5770699..5aff0e9b16493 100644 --- a/x-pack/solutions/observability/plugins/apm/public/plugin.ts +++ b/x-pack/solutions/observability/plugins/apm/public/plugin.ts @@ -100,6 +100,8 @@ import { featureCatalogueEntry } from './feature_catalogue_entry'; import { APMServiceDetailLocator } from './locator/service_detail_locator'; import type { ITelemetryClient } from './services/telemetry'; import { TelemetryService } from './services/telemetry'; +import { createFocusedTraceWaterfallFetcher } from './components/shared/focused_trace_waterfall/focused_trace_waterfall_fetcher'; +import { createFullTraceWaterfallFetcher } from './components/shared/trace_waterfall/full_trace_waterfall_fetcher'; export type ApmPluginSetup = ReturnType; export type ApmPluginStart = ReturnType; @@ -519,7 +521,7 @@ export class ApmPlugin implements Plugin { } public start(core: CoreStart, plugins: ApmPluginStartDeps) { - const { fleet } = plugins; + const { fleet, discoverShared } = plugins; plugins.observabilityAIAssistant?.service.register(async ({ registerRenderFunction }) => { const mod = await import('./assistant_functions'); @@ -529,6 +531,16 @@ export class ApmPlugin implements Plugin { }); }); + discoverShared.features.registry.register({ + id: 'observability-focused-trace-waterfall', + render: createFocusedTraceWaterfallFetcher({ core }), + }); + + discoverShared.features.registry.register({ + id: 'observability-full-trace-waterfall', + render: createFullTraceWaterfallFetcher({ core }), + }); + if (fleet) { const agentEnrollmentExtensionData = getApmEnrollmentFlyoutData(); From 1667c7e574008a7a3ad8ae24146cf1ebe990d68f Mon Sep 17 00:00:00 2001 From: Caue Marcondes Date: Wed, 28 Jan 2026 14:45:25 -0500 Subject: [PATCH 2/7] fixing ci --- .../full_screen_waterfall/index.test.tsx | 20 ------------------- 1 file changed, 20 deletions(-) diff --git a/src/platform/plugins/shared/unified_doc_viewer/public/components/observability/traces/components/full_screen_waterfall/index.test.tsx b/src/platform/plugins/shared/unified_doc_viewer/public/components/observability/traces/components/full_screen_waterfall/index.test.tsx index 103cdccf2a613..35318da3b303d 100644 --- a/src/platform/plugins/shared/unified_doc_viewer/public/components/observability/traces/components/full_screen_waterfall/index.test.tsx +++ b/src/platform/plugins/shared/unified_doc_viewer/public/components/observability/traces/components/full_screen_waterfall/index.test.tsx @@ -14,25 +14,6 @@ import { FullScreenWaterfall, type FullScreenWaterfallProps } from '.'; import { setUnifiedDocViewerServices } from '../../../../../plugin'; import type { UnifiedDocViewerServices } from '../../../../../types'; -let capturedCallbacks: any = null; - -jest.mock('@kbn/embeddable-plugin/public', () => ({ - EmbeddableRenderer: ({ type, getParentApi, hidePanelChrome }: any) => { - const api = getParentApi(); - capturedCallbacks = api.getSerializedStateForChild(); - - return ( -
- Embeddable Renderer Mock -
- ); - }, -})); - jest.mock('./waterfall_flyout/span_flyout', () => ({ SpanFlyout: ({ traceId, spanId, _, activeSection }: any) => (
{ beforeEach(() => { jest.clearAllMocks(); - capturedCallbacks = null; }); it('should not display nested flyouts initially', () => { From 42bb4f475cca36abe81ae442ac365ed0d044a668 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cau=C3=AA=20Marcondes?= <55978943+cauemarcondes@users.noreply.github.com> Date: Thu, 29 Jan 2026 09:14:44 -0500 Subject: [PATCH 3/7] Update src/platform/plugins/shared/unified_doc_viewer/public/components/observability/traces/components/full_screen_waterfall/index.test.tsx Co-authored-by: Nathan L Smith --- .../traces/components/full_screen_waterfall/index.test.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/platform/plugins/shared/unified_doc_viewer/public/components/observability/traces/components/full_screen_waterfall/index.test.tsx b/src/platform/plugins/shared/unified_doc_viewer/public/components/observability/traces/components/full_screen_waterfall/index.test.tsx index 35318da3b303d..d1ff9504f4073 100644 --- a/src/platform/plugins/shared/unified_doc_viewer/public/components/observability/traces/components/full_screen_waterfall/index.test.tsx +++ b/src/platform/plugins/shared/unified_doc_viewer/public/components/observability/traces/components/full_screen_waterfall/index.test.tsx @@ -72,7 +72,8 @@ describe('FullScreenWaterfall', () => { expect(screen.getByTestId('fullTraceWaterfall')).toBeInTheDocument(); }); - it('should not display the full trace waterfall', () => { + describe('when service name is undefined', () => { + it('does not display the full trace waterfall', () => { render(); expect(screen.queryByTestId('fullTraceWaterfall')).not.toBeInTheDocument(); From 0d4d595b1194fae469621b32d1b9d396e73b518b Mon Sep 17 00:00:00 2001 From: Caue Marcondes Date: Thu, 29 Jan 2026 09:20:16 -0500 Subject: [PATCH 4/7] PR comments --- .../traces/components/full_screen_waterfall/index.tsx | 5 ++--- ...l_fetcher.tsx => focused_trace_waterfall_renderer.tsx} | 6 +++--- ...fall_fetcher.tsx => full_trace_waterfall_renderer.tsx} | 6 +++--- .../solutions/observability/plugins/apm/public/plugin.ts | 8 ++++---- 4 files changed, 12 insertions(+), 13 deletions(-) rename x-pack/solutions/observability/plugins/apm/public/components/shared/focused_trace_waterfall/{focused_trace_waterfall_fetcher.tsx => focused_trace_waterfall_renderer.tsx} (91%) rename x-pack/solutions/observability/plugins/apm/public/components/shared/trace_waterfall/{full_trace_waterfall_fetcher.tsx => full_trace_waterfall_renderer.tsx} (93%) diff --git a/src/platform/plugins/shared/unified_doc_viewer/public/components/observability/traces/components/full_screen_waterfall/index.tsx b/src/platform/plugins/shared/unified_doc_viewer/public/components/observability/traces/components/full_screen_waterfall/index.tsx index 72d4738da60a9..e032d163eb542 100644 --- a/src/platform/plugins/shared/unified_doc_viewer/public/components/observability/traces/components/full_screen_waterfall/index.tsx +++ b/src/platform/plugins/shared/unified_doc_viewer/public/components/observability/traces/components/full_screen_waterfall/index.tsx @@ -74,7 +74,6 @@ export const FullScreenWaterfall = ({ * Obtains the EUI flyout scroll container for the trace waterfall embeddable. * * This pattern is necessary because: - * - Embeddables are constructed once with immutable initial state * - EUI components don't expose refs, requiring a wrapper div with closest() * - scrollElement must be available before the embeddable initializes (conditional render below) * @@ -82,7 +81,7 @@ export const FullScreenWaterfall = ({ * TODO: Once the EUI team implements a scrollRef prop (or exposes refs on EUIFlyoutBody, Issue: 2564 in kibana-team repository), * we can replace this workaround with a direct ref usage. */ - const embeddableContainerRef = useCallback((node: HTMLDivElement | null) => { + const waterfallContainerRef = useCallback((node: HTMLDivElement | null) => { if (node) { setScrollElement(node.closest(`.${EUI_FLYOUT_BODY_OVERFLOW_CLASS}`) ?? null); } @@ -149,7 +148,7 @@ export const FullScreenWaterfall = ({ This should be removed once PresentationPanel properly supports hidePanelChrome as an out-of-the-box solution. Issue: https://github.com/elastic/kibana/issues/248307 */} -
+
{scrollElement && serviceName ? ( ; + return (props: FocusedTraceWaterfallProps) => ; } -function FocusedTraceWaterfallFetcher({ +function FocusedTraceWaterfallRenderer({ traceId, rangeFrom, rangeTo, diff --git a/x-pack/solutions/observability/plugins/apm/public/components/shared/trace_waterfall/full_trace_waterfall_fetcher.tsx b/x-pack/solutions/observability/plugins/apm/public/components/shared/trace_waterfall/full_trace_waterfall_renderer.tsx similarity index 93% rename from x-pack/solutions/observability/plugins/apm/public/components/shared/trace_waterfall/full_trace_waterfall_fetcher.tsx rename to x-pack/solutions/observability/plugins/apm/public/components/shared/trace_waterfall/full_trace_waterfall_renderer.tsx index 83ae40c306eb3..1e92c3e2c05ea 100644 --- a/x-pack/solutions/observability/plugins/apm/public/components/shared/trace_waterfall/full_trace_waterfall_fetcher.tsx +++ b/x-pack/solutions/observability/plugins/apm/public/components/shared/trace_waterfall/full_trace_waterfall_renderer.tsx @@ -15,12 +15,12 @@ import { isPending, useFetcher } from '../../../hooks/use_fetcher'; import { Loading } from './loading'; import { TraceWaterfall } from '.'; -export function createFullTraceWaterfallFetcher({ core }: { core: CoreStart }) { +export function createFullTraceWaterfallRenderer({ core }: { core: CoreStart }) { createCallApmApi(core); - return (props: FullTraceWaterfallProps) => ; + return (props: FullTraceWaterfallProps) => ; } -export function FullTraceWaterfallFetcher({ +export function FullTraceWaterfallRenderer({ traceId, rangeFrom, rangeTo, diff --git a/x-pack/solutions/observability/plugins/apm/public/plugin.ts b/x-pack/solutions/observability/plugins/apm/public/plugin.ts index 5aff0e9b16493..0babce53f74d9 100644 --- a/x-pack/solutions/observability/plugins/apm/public/plugin.ts +++ b/x-pack/solutions/observability/plugins/apm/public/plugin.ts @@ -100,8 +100,8 @@ import { featureCatalogueEntry } from './feature_catalogue_entry'; import { APMServiceDetailLocator } from './locator/service_detail_locator'; import type { ITelemetryClient } from './services/telemetry'; import { TelemetryService } from './services/telemetry'; -import { createFocusedTraceWaterfallFetcher } from './components/shared/focused_trace_waterfall/focused_trace_waterfall_fetcher'; -import { createFullTraceWaterfallFetcher } from './components/shared/trace_waterfall/full_trace_waterfall_fetcher'; +import { createFocusedTraceWaterfallRenderer } from './components/shared/focused_trace_waterfall/focused_trace_waterfall_renderer'; +import { createFullTraceWaterfallRenderer } from './components/shared/trace_waterfall/full_trace_waterfall_renderer'; export type ApmPluginSetup = ReturnType; export type ApmPluginStart = ReturnType; @@ -533,12 +533,12 @@ export class ApmPlugin implements Plugin { discoverShared.features.registry.register({ id: 'observability-focused-trace-waterfall', - render: createFocusedTraceWaterfallFetcher({ core }), + render: createFocusedTraceWaterfallRenderer({ core }), }); discoverShared.features.registry.register({ id: 'observability-full-trace-waterfall', - render: createFullTraceWaterfallFetcher({ core }), + render: createFullTraceWaterfallRenderer({ core }), }); if (fleet) { From 699310c5b4ceddd8c6f1962484abb62c9ee82da4 Mon Sep 17 00:00:00 2001 From: Caue Marcondes Date: Thu, 29 Jan 2026 10:17:21 -0500 Subject: [PATCH 5/7] lazy loading --- .../focused_trace_waterfall_renderer.tsx | 9 +------ ...reate_focused_trace_waterfall_renderer.tsx | 25 +++++++++++++++++++ .../full_trace_waterfall_renderer.tsx | 13 +++------- ...y_create_full_trace_waterfall_renderer.tsx | 25 +++++++++++++++++++ .../plugins/apm/public/plugin.ts | 8 +++--- 5 files changed, 58 insertions(+), 22 deletions(-) create mode 100644 x-pack/solutions/observability/plugins/apm/public/components/shared/focused_trace_waterfall/lazy_create_focused_trace_waterfall_renderer.tsx create mode 100644 x-pack/solutions/observability/plugins/apm/public/components/shared/trace_waterfall/lazy_create_full_trace_waterfall_renderer.tsx diff --git a/x-pack/solutions/observability/plugins/apm/public/components/shared/focused_trace_waterfall/focused_trace_waterfall_renderer.tsx b/x-pack/solutions/observability/plugins/apm/public/components/shared/focused_trace_waterfall/focused_trace_waterfall_renderer.tsx index 7d478b0c48f90..0e404db13109c 100644 --- a/x-pack/solutions/observability/plugins/apm/public/components/shared/focused_trace_waterfall/focused_trace_waterfall_renderer.tsx +++ b/x-pack/solutions/observability/plugins/apm/public/components/shared/focused_trace_waterfall/focused_trace_waterfall_renderer.tsx @@ -7,19 +7,12 @@ import React from 'react'; import { i18n } from '@kbn/i18n'; import type { FocusedTraceWaterfallProps } from '@kbn/apm-types'; -import type { CoreStart } from '@kbn/core/public'; import { EuiCallOut } from '@elastic/eui'; import { isPending, useFetcher } from '../../../hooks/use_fetcher'; -import { createCallApmApi } from '../../../services/rest/create_call_apm_api'; import { FocusedTraceWaterfall } from '.'; import { Loading } from '../trace_waterfall/loading'; -export function createFocusedTraceWaterfallRenderer({ core }: { core: CoreStart }) { - createCallApmApi(core); - return (props: FocusedTraceWaterfallProps) => ; -} - -function FocusedTraceWaterfallRenderer({ +export function FocusedTraceWaterfallRenderer({ traceId, rangeFrom, rangeTo, diff --git a/x-pack/solutions/observability/plugins/apm/public/components/shared/focused_trace_waterfall/lazy_create_focused_trace_waterfall_renderer.tsx b/x-pack/solutions/observability/plugins/apm/public/components/shared/focused_trace_waterfall/lazy_create_focused_trace_waterfall_renderer.tsx new file mode 100644 index 0000000000000..84eff0520a5e3 --- /dev/null +++ b/x-pack/solutions/observability/plugins/apm/public/components/shared/focused_trace_waterfall/lazy_create_focused_trace_waterfall_renderer.tsx @@ -0,0 +1,25 @@ +/* + * 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 React from 'react'; + +import { dynamic } from '@kbn/shared-ux-utility'; +import type { CoreStart } from '@kbn/core/public'; +import type { FocusedTraceWaterfallProps } from '@kbn/apm-types'; +import { createCallApmApi } from '../../../services/rest/create_call_apm_api'; + +const LazyFocusedTraceWaterfallRendererComponent = dynamic(() => + import('./focused_trace_waterfall_renderer').then((mod) => ({ + default: mod.FocusedTraceWaterfallRenderer, + })) +); + +export function createLazyFocusedTraceWaterfallRenderer({ core }: { core: CoreStart }) { + createCallApmApi(core); + return (props: FocusedTraceWaterfallProps) => { + return ; + }; +} diff --git a/x-pack/solutions/observability/plugins/apm/public/components/shared/trace_waterfall/full_trace_waterfall_renderer.tsx b/x-pack/solutions/observability/plugins/apm/public/components/shared/trace_waterfall/full_trace_waterfall_renderer.tsx index 1e92c3e2c05ea..c7715863aeb81 100644 --- a/x-pack/solutions/observability/plugins/apm/public/components/shared/trace_waterfall/full_trace_waterfall_renderer.tsx +++ b/x-pack/solutions/observability/plugins/apm/public/components/shared/trace_waterfall/full_trace_waterfall_renderer.tsx @@ -5,20 +5,13 @@ * 2.0. */ +import { EuiCallOut } from '@elastic/eui'; +import type { FullTraceWaterfallProps } from '@kbn/apm-types'; import { i18n } from '@kbn/i18n'; import React from 'react'; -import type { CoreStart } from '@kbn/core/public'; -import type { FullTraceWaterfallProps } from '@kbn/apm-types'; -import { EuiCallOut } from '@elastic/eui'; -import { createCallApmApi } from '../../../services/rest/create_call_apm_api'; +import { TraceWaterfall } from '.'; import { isPending, useFetcher } from '../../../hooks/use_fetcher'; import { Loading } from './loading'; -import { TraceWaterfall } from '.'; - -export function createFullTraceWaterfallRenderer({ core }: { core: CoreStart }) { - createCallApmApi(core); - return (props: FullTraceWaterfallProps) => ; -} export function FullTraceWaterfallRenderer({ traceId, diff --git a/x-pack/solutions/observability/plugins/apm/public/components/shared/trace_waterfall/lazy_create_full_trace_waterfall_renderer.tsx b/x-pack/solutions/observability/plugins/apm/public/components/shared/trace_waterfall/lazy_create_full_trace_waterfall_renderer.tsx new file mode 100644 index 0000000000000..a0b276268f966 --- /dev/null +++ b/x-pack/solutions/observability/plugins/apm/public/components/shared/trace_waterfall/lazy_create_full_trace_waterfall_renderer.tsx @@ -0,0 +1,25 @@ +/* + * 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 React from 'react'; + +import { dynamic } from '@kbn/shared-ux-utility'; +import type { FullTraceWaterfallProps } from '@kbn/apm-types/src/full_trace_waterfall'; +import type { CoreStart } from '@kbn/core/public'; +import { createCallApmApi } from '../../../services/rest/create_call_apm_api'; + +const LazyFullTraceWaterfallRendererComponent = dynamic(() => + import('./full_trace_waterfall_renderer').then((mod) => ({ + default: mod.FullTraceWaterfallRenderer, + })) +); + +export function createLazyFullTraceWaterfallRenderer({ core }: { core: CoreStart }) { + createCallApmApi(core); + return (props: FullTraceWaterfallProps) => { + return ; + }; +} diff --git a/x-pack/solutions/observability/plugins/apm/public/plugin.ts b/x-pack/solutions/observability/plugins/apm/public/plugin.ts index 0babce53f74d9..917842cf147d5 100644 --- a/x-pack/solutions/observability/plugins/apm/public/plugin.ts +++ b/x-pack/solutions/observability/plugins/apm/public/plugin.ts @@ -100,8 +100,8 @@ import { featureCatalogueEntry } from './feature_catalogue_entry'; import { APMServiceDetailLocator } from './locator/service_detail_locator'; import type { ITelemetryClient } from './services/telemetry'; import { TelemetryService } from './services/telemetry'; -import { createFocusedTraceWaterfallRenderer } from './components/shared/focused_trace_waterfall/focused_trace_waterfall_renderer'; -import { createFullTraceWaterfallRenderer } from './components/shared/trace_waterfall/full_trace_waterfall_renderer'; +import { createLazyFocusedTraceWaterfallRenderer } from './components/shared/focused_trace_waterfall/lazy_create_focused_trace_waterfall_renderer'; +import { createLazyFullTraceWaterfallRenderer } from './components/shared/trace_waterfall/lazy_create_full_trace_waterfall_renderer'; export type ApmPluginSetup = ReturnType; export type ApmPluginStart = ReturnType; @@ -533,12 +533,12 @@ export class ApmPlugin implements Plugin { discoverShared.features.registry.register({ id: 'observability-focused-trace-waterfall', - render: createFocusedTraceWaterfallRenderer({ core }), + render: createLazyFocusedTraceWaterfallRenderer({ core }), }); discoverShared.features.registry.register({ id: 'observability-full-trace-waterfall', - render: createFullTraceWaterfallRenderer({ core }), + render: createLazyFullTraceWaterfallRenderer({ core }), }); if (fleet) { From c78de94bf5bdba02d68858555cc2d95536f38a6a Mon Sep 17 00:00:00 2001 From: Caue Marcondes Date: Thu, 29 Jan 2026 10:44:05 -0500 Subject: [PATCH 6/7] fix ci --- .../traces/components/full_screen_waterfall/index.test.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/platform/plugins/shared/unified_doc_viewer/public/components/observability/traces/components/full_screen_waterfall/index.test.tsx b/src/platform/plugins/shared/unified_doc_viewer/public/components/observability/traces/components/full_screen_waterfall/index.test.tsx index d1ff9504f4073..4f2903ea2061c 100644 --- a/src/platform/plugins/shared/unified_doc_viewer/public/components/observability/traces/components/full_screen_waterfall/index.test.tsx +++ b/src/platform/plugins/shared/unified_doc_viewer/public/components/observability/traces/components/full_screen_waterfall/index.test.tsx @@ -74,8 +74,9 @@ describe('FullScreenWaterfall', () => { describe('when service name is undefined', () => { it('does not display the full trace waterfall', () => { - render(); + render(); - expect(screen.queryByTestId('fullTraceWaterfall')).not.toBeInTheDocument(); + expect(screen.queryByTestId('fullTraceWaterfall')).not.toBeInTheDocument(); + }); }); }); From ea741c13063bef9b7c210dd871d8de44ee50d42e Mon Sep 17 00:00:00 2001 From: Caue Marcondes Date: Thu, 29 Jan 2026 14:38:23 -0500 Subject: [PATCH 7/7] fixing bundle size --- .../focused_trace_waterfall_renderer.tsx | 17 +++++++++++------ ..._create_focused_trace_waterfall_renderer.tsx | 4 +--- .../full_trace_waterfall_renderer.tsx | 13 ++++++++++++- ...azy_create_full_trace_waterfall_renderer.tsx | 7 ++----- 4 files changed, 26 insertions(+), 15 deletions(-) diff --git a/x-pack/solutions/observability/plugins/apm/public/components/shared/focused_trace_waterfall/focused_trace_waterfall_renderer.tsx b/x-pack/solutions/observability/plugins/apm/public/components/shared/focused_trace_waterfall/focused_trace_waterfall_renderer.tsx index 0e404db13109c..3fbc3a589a8bf 100644 --- a/x-pack/solutions/observability/plugins/apm/public/components/shared/focused_trace_waterfall/focused_trace_waterfall_renderer.tsx +++ b/x-pack/solutions/observability/plugins/apm/public/components/shared/focused_trace_waterfall/focused_trace_waterfall_renderer.tsx @@ -8,16 +8,21 @@ import React from 'react'; import { i18n } from '@kbn/i18n'; import type { FocusedTraceWaterfallProps } from '@kbn/apm-types'; import { EuiCallOut } from '@elastic/eui'; +import type { CoreStart } from '@kbn/core/public'; +import useEffectOnce from 'react-use/lib/useEffectOnce'; import { isPending, useFetcher } from '../../../hooks/use_fetcher'; import { FocusedTraceWaterfall } from '.'; import { Loading } from '../trace_waterfall/loading'; +import { createCallApmApi } from '../../../services/rest/create_call_apm_api'; -export function FocusedTraceWaterfallRenderer({ - traceId, - rangeFrom, - rangeTo, - docId, -}: FocusedTraceWaterfallProps) { +interface Props extends FocusedTraceWaterfallProps { + core: CoreStart; +} + +export function FocusedTraceWaterfallRenderer({ traceId, rangeFrom, rangeTo, docId, core }: Props) { + useEffectOnce(() => { + createCallApmApi(core); + }); const { data, status } = useFetcher( (callApmApi) => { return callApmApi('GET /internal/apm/unified_traces/{traceId}/summary', { diff --git a/x-pack/solutions/observability/plugins/apm/public/components/shared/focused_trace_waterfall/lazy_create_focused_trace_waterfall_renderer.tsx b/x-pack/solutions/observability/plugins/apm/public/components/shared/focused_trace_waterfall/lazy_create_focused_trace_waterfall_renderer.tsx index 84eff0520a5e3..448e89f41ee4a 100644 --- a/x-pack/solutions/observability/plugins/apm/public/components/shared/focused_trace_waterfall/lazy_create_focused_trace_waterfall_renderer.tsx +++ b/x-pack/solutions/observability/plugins/apm/public/components/shared/focused_trace_waterfall/lazy_create_focused_trace_waterfall_renderer.tsx @@ -9,7 +9,6 @@ import React from 'react'; import { dynamic } from '@kbn/shared-ux-utility'; import type { CoreStart } from '@kbn/core/public'; import type { FocusedTraceWaterfallProps } from '@kbn/apm-types'; -import { createCallApmApi } from '../../../services/rest/create_call_apm_api'; const LazyFocusedTraceWaterfallRendererComponent = dynamic(() => import('./focused_trace_waterfall_renderer').then((mod) => ({ @@ -18,8 +17,7 @@ const LazyFocusedTraceWaterfallRendererComponent = dynamic(() => ); export function createLazyFocusedTraceWaterfallRenderer({ core }: { core: CoreStart }) { - createCallApmApi(core); return (props: FocusedTraceWaterfallProps) => { - return ; + return ; }; } diff --git a/x-pack/solutions/observability/plugins/apm/public/components/shared/trace_waterfall/full_trace_waterfall_renderer.tsx b/x-pack/solutions/observability/plugins/apm/public/components/shared/trace_waterfall/full_trace_waterfall_renderer.tsx index c7715863aeb81..5e7af44a66bfb 100644 --- a/x-pack/solutions/observability/plugins/apm/public/components/shared/trace_waterfall/full_trace_waterfall_renderer.tsx +++ b/x-pack/solutions/observability/plugins/apm/public/components/shared/trace_waterfall/full_trace_waterfall_renderer.tsx @@ -9,9 +9,16 @@ import { EuiCallOut } from '@elastic/eui'; import type { FullTraceWaterfallProps } from '@kbn/apm-types'; import { i18n } from '@kbn/i18n'; import React from 'react'; +import type { CoreStart } from '@kbn/core/public'; +import useEffectOnce from 'react-use/lib/useEffectOnce'; import { TraceWaterfall } from '.'; import { isPending, useFetcher } from '../../../hooks/use_fetcher'; import { Loading } from './loading'; +import { createCallApmApi } from '../../../services/rest/create_call_apm_api'; + +interface Props extends FullTraceWaterfallProps { + core: CoreStart; +} export function FullTraceWaterfallRenderer({ traceId, @@ -21,7 +28,11 @@ export function FullTraceWaterfallRenderer({ scrollElement, onNodeClick, onErrorClick, -}: FullTraceWaterfallProps) { + core, +}: Props) { + useEffectOnce(() => { + createCallApmApi(core); + }); const { data, status } = useFetcher( (callApmApi) => { return callApmApi('GET /internal/apm/unified_traces/{traceId}', { diff --git a/x-pack/solutions/observability/plugins/apm/public/components/shared/trace_waterfall/lazy_create_full_trace_waterfall_renderer.tsx b/x-pack/solutions/observability/plugins/apm/public/components/shared/trace_waterfall/lazy_create_full_trace_waterfall_renderer.tsx index a0b276268f966..af8263d083067 100644 --- a/x-pack/solutions/observability/plugins/apm/public/components/shared/trace_waterfall/lazy_create_full_trace_waterfall_renderer.tsx +++ b/x-pack/solutions/observability/plugins/apm/public/components/shared/trace_waterfall/lazy_create_full_trace_waterfall_renderer.tsx @@ -5,11 +5,9 @@ * 2.0. */ import React from 'react'; - import { dynamic } from '@kbn/shared-ux-utility'; -import type { FullTraceWaterfallProps } from '@kbn/apm-types/src/full_trace_waterfall'; import type { CoreStart } from '@kbn/core/public'; -import { createCallApmApi } from '../../../services/rest/create_call_apm_api'; +import type { FullTraceWaterfallProps } from '@kbn/apm-types'; const LazyFullTraceWaterfallRendererComponent = dynamic(() => import('./full_trace_waterfall_renderer').then((mod) => ({ @@ -18,8 +16,7 @@ const LazyFullTraceWaterfallRendererComponent = dynamic(() => ); export function createLazyFullTraceWaterfallRenderer({ core }: { core: CoreStart }) { - createCallApmApi(core); return (props: FullTraceWaterfallProps) => { - return ; + return ; }; }