From bea0a11f1b94814a4756047c17708615837a7375 Mon Sep 17 00:00:00 2001 From: Adam Tackett Date: Thu, 19 Sep 2024 20:36:07 -0700 Subject: [PATCH 01/10] bug fix services data picker, ui fixes Signed-off-by: Adam Tackett --- .../__snapshots__/top_menu.test.tsx.snap | 210 ++++++------------ .../components/metrics/top_menu/top_menu.tsx | 15 +- .../components/dashboard_controls.tsx | 25 ++- .../__snapshots__/search_bar.test.tsx.snap | 10 +- .../components/common/search_bar.tsx | 1 + .../__snapshots__/service_view.test.tsx.snap | 17 +- .../components/services/service_view.tsx | 47 ++-- .../components/services/services_content.tsx | 3 +- .../__snapshots__/trace_view.test.tsx.snap | 2 +- .../components/traces/trace_view.tsx | 2 +- public/components/trace_analytics/home.tsx | 65 ++++-- 11 files changed, 165 insertions(+), 232 deletions(-) diff --git a/public/components/metrics/top_menu/__tests__/__snapshots__/top_menu.test.tsx.snap b/public/components/metrics/top_menu/__tests__/__snapshots__/top_menu.test.tsx.snap index f36ead4f2..8ff95fdbd 100644 --- a/public/components/metrics/top_menu/__tests__/__snapshots__/top_menu.test.tsx.snap +++ b/public/components/metrics/top_menu/__tests__/__snapshots__/top_menu.test.tsx.snap @@ -385,11 +385,10 @@ exports[`Metrics Top Menu Component renders Top Menu Component when enabled 1`] className="euiFlexGroup euiFlexGroup--gutterSmall euiFlexGroup--directionRow euiFlexGroup--responsive" >
- -
- - - - - - - - - - - -
-
+ +
+ + + +
+
diff --git a/public/components/metrics/top_menu/top_menu.tsx b/public/components/metrics/top_menu/top_menu.tsx index c1da76368..f7e00db67 100644 --- a/public/components/metrics/top_menu/top_menu.tsx +++ b/public/components/metrics/top_menu/top_menu.tsx @@ -4,6 +4,7 @@ */ import { + EuiButtonIcon, EuiCompressedFieldText, EuiCompressedSelect, EuiCompressedSuperDatePicker, @@ -52,13 +53,25 @@ export const TopMenu = () => { - + dispatch(setDateSpan(dateSpan))} recentlyUsedRanges={dateSpanFilter.recentlyUsedRanges} + showUpdateButton={false} + /> + + + dispatch(setDateSpan(dateSpanFilter))} + size="s" + data-test-subj="superDatePickerApplyTimeButton" + data-click-metric-element="metrics.refresh_button" /> diff --git a/public/components/overview/components/dashboard_controls.tsx b/public/components/overview/components/dashboard_controls.tsx index 6847b1fcb..8c4864dfa 100644 --- a/public/components/overview/components/dashboard_controls.tsx +++ b/public/components/overview/components/dashboard_controls.tsx @@ -7,6 +7,7 @@ import { EuiButtonIcon, EuiFlexGroup, EuiFlexItem, + EuiIcon, EuiLink, EuiSuperDatePicker, EuiText, @@ -48,15 +49,23 @@ export function DashboardControls() { }; return isDashboardSelected ? ( - - - -

- redirectToDashboards('/view/' + dashboardState?.dashboardId)}> - {dashboardState?.dashboardTitle} + + + + + +

{dashboardState?.dashboardTitle}

+
+
+ + redirectToDashboards('/view/' + dashboardState?.dashboardId)} + external={true} + > + -

- +
+
diff --git a/public/components/trace_analytics/components/common/__tests__/__snapshots__/search_bar.test.tsx.snap b/public/components/trace_analytics/components/common/__tests__/__snapshots__/search_bar.test.tsx.snap index 97ae72f57..05a380fcc 100644 --- a/public/components/trace_analytics/components/common/__tests__/__snapshots__/search_bar.test.tsx.snap +++ b/public/components/trace_analytics/components/common/__tests__/__snapshots__/search_bar.test.tsx.snap @@ -46,7 +46,7 @@ exports[`Search bar components renders date picker 1`] = ` }, ] } - compressed={false} + compressed={true} dateFormat="" end="now" isAutoRefreshOnly={false} @@ -73,7 +73,7 @@ exports[`Search bar components renders date picker 1`] = ` >
diff --git a/public/components/trace_analytics/components/common/search_bar.tsx b/public/components/trace_analytics/components/common/search_bar.tsx index 7c24014a6..6af85ed70 100644 --- a/public/components/trace_analytics/components/common/search_bar.tsx +++ b/public/components/trace_analytics/components/common/search_bar.tsx @@ -24,6 +24,7 @@ export const renderDatePicker = ( ) => { return ( - - - Name - - - order - - diff --git a/public/components/trace_analytics/components/services/service_view.tsx b/public/components/trace_analytics/components/services/service_view.tsx index e5470d086..8ada47351 100644 --- a/public/components/trace_analytics/components/services/service_view.tsx +++ b/public/components/trace_analytics/components/services/service_view.tsx @@ -26,10 +26,7 @@ import { } from '@elastic/eui'; import round from 'lodash/round'; import React, { useEffect, useMemo, useState } from 'react'; -import { - DataSourceManagementPluginSetup, - DataSourceViewConfig, -} from '../../../../../../../src/plugins/data_source_management/public'; +import { DataSourceManagementPluginSetup } from '../../../../../../../src/plugins/data_source_management/public'; import { DataSourceOption } from '../../../../../../../src/plugins/data_source_management/public/components/data_source_menu/types'; import { DEFAULT_DATA_SOURCE_NAME, @@ -37,9 +34,7 @@ import { } from '../../../../../common/constants/data_sources'; import { observabilityLogsID } from '../../../../../common/constants/shared'; import { setNavBreadCrumbs } from '../../../../../common/utils/set_nav_bread_crumbs'; -import { dataSourceFilterFn } from '../../../../../common/utils/shared'; import { coreRefs } from '../../../../framework/core_refs'; -import { HeaderControlledComponentsWrapper } from '../../../../plugin_helpers/plugin_headerControl'; import { TraceAnalyticsComponentDeps } from '../../home'; import { handleServiceMapRequest, @@ -53,6 +48,8 @@ import { SpanDetailFlyout } from '../traces/span_detail_flyout'; import { SpanDetailTable } from '../traces/span_detail_table'; import { ServiceMetrics } from './service_metrics'; +const newNavigation = coreRefs.chrome?.navGroup.getNavGroupEnabled(); + interface ServiceViewProps extends TraceAnalyticsComponentDeps { serviceName: string; addFilter: (filter: FilterType) => void; @@ -122,9 +119,8 @@ export function ServiceView(props: ServiceViewProps) { }, ] ); - }, [props.serviceName]); - - const DataSourceMenu = props.dataSourceManagement?.ui?.getDataSourceMenu(); + props.setDataSourceMenuSelectable?.(false); + }, [props.serviceName, props.setDataSourceMenuSelectable]); const redirectToServicePage = (service: string) => { window.location.href = `#/services/${service}`; @@ -228,7 +224,7 @@ export function ServiceView(props: ServiceViewProps) { {_page === 'serviceFlyout' ? ( - {serviceHeader} + {!newNavigation ? serviceHeader : null} {renderDatePicker(startTime, setStartTime, endTime, setEndTime)} - ) : coreRefs?.chrome?.navGroup.getNavGroupEnabled() ? ( - ) : ( - {serviceHeader} + {!newNavigation ? serviceHeader : null} {renderDatePicker(startTime, setStartTime, endTime, setEndTime)} @@ -261,29 +253,20 @@ export function ServiceView(props: ServiceViewProps) { const renderOverview = () => { return ( <> - {props.dataSourceEnabled && ( - - )} - - Name - - {props.serviceName || '-'} - - + {newNavigation && ( + + Name + + {props.serviceName || '-'} + + + )} {mode === 'data_prepper' || mode === 'custom_data_prepper' ? ( Number of connected services diff --git a/public/components/trace_analytics/components/services/services_content.tsx b/public/components/trace_analytics/components/services/services_content.tsx index 4108c91dd..d1bf6edf0 100644 --- a/public/components/trace_analytics/components/services/services_content.tsx +++ b/public/components/trace_analytics/components/services/services_content.tsx @@ -73,7 +73,8 @@ export function ServicesContent(props: ServicesProps) { })), ]); setRedirect(false); - }, [mode]); + props.setDataSourceMenuSelectable?.(true); + }, [mode, props.setDataSourceMenuSelectable, props.currentSelectedService]); useEffect(() => { let newFilteredService = ''; diff --git a/public/components/trace_analytics/components/traces/__tests__/__snapshots__/trace_view.test.tsx.snap b/public/components/trace_analytics/components/traces/__tests__/__snapshots__/trace_view.test.tsx.snap index e51feab60..c29e76ed4 100644 --- a/public/components/trace_analytics/components/traces/__tests__/__snapshots__/trace_view.test.tsx.snap +++ b/public/components/trace_analytics/components/traces/__tests__/__snapshots__/trace_view.test.tsx.snap @@ -21,7 +21,7 @@ exports[`Trace view component renders trace view 1`] = ` {renderTitle(props.traceId)} - + {renderOverview(fields)} diff --git a/public/components/trace_analytics/home.tsx b/public/components/trace_analytics/home.tsx index 042064020..86130cc43 100644 --- a/public/components/trace_analytics/home.tsx +++ b/public/components/trace_analytics/home.tsx @@ -18,6 +18,7 @@ import { import { DataSourceManagementPluginSetup, DataSourceSelectableConfig, + DataSourceViewConfig, } from '../../../../../src/plugins/data_source_management/public'; import { TraceAnalyticsMode } from '../../../common/types/trace_analytics'; import { dataSourceFilterFn } from '../../../common/utils/shared'; @@ -72,6 +73,8 @@ export interface TraceAnalyticsComponentDeps extends TraceAnalyticsCoreDeps, Sea spanMode: TraceAnalyticsMode; spanDataSourceMDSId: string; }) => void; + setDataSourceMenuSelectable?: React.Dispatch>; + currentSelectedService?: string; } export const Home = (props: HomeProps) => { @@ -115,9 +118,9 @@ export const Home = (props: HomeProps) => { if (!text) text = ''; setToasts([...toasts, { id: new Date().toISOString(), title, text, color } as Toast]); }; - const [dataSourceMDSId, setDataSourceMDSId] = useState([{ id: '', label: '' }]); const [currentSelectedService, setCurrentSelectedService] = useState(''); + const [dataSourceMenuSelectable, setDataSourceMenuSelectable] = useState(true); // Navigate a valid routes when suffixed with '/traces' and '/services' // Route defaults to traces page @@ -134,6 +137,10 @@ export const Home = (props: HomeProps) => { DataSourceSelectableConfig >(); + const DataSourceMenuView = props.dataSourceManagement?.ui?.getDataSourceMenu< + DataSourceViewConfig + >(); + const onSelectedDataSource = (e) => { const dataConnectionId = e[0] ? e[0].id : undefined; const dataConnectionLabel = e[0] ? e[0].label : undefined; @@ -142,20 +149,40 @@ export const Home = (props: HomeProps) => { }; const dataSourceMenuComponent = useMemo(() => { - return ( - - ); - }, [props.setActionMenu, props.savedObjectsMDSClient.client, props.notifications]); + if (!dataSourceMenuSelectable) { + return ( + + ); + } else { + return ( + + ); + } + }, [ + dataSourceMenuSelectable, + props.setActionMenu, + props.savedObjectsMDSClient.client, + props.notifications, + ]); useEffect(() => { handleDataPrepperIndicesExistRequest( @@ -290,6 +317,8 @@ export const Home = (props: HomeProps) => { savedObjectsMDSClient: props.savedObjectsMDSClient, attributesFilterFields, setSpanFlyout, + setDataSourceMenuSelectable, + currentSelectedService, }; let flyout; @@ -314,6 +343,7 @@ export const Home = (props: HomeProps) => { }} toastLifeTimeMs={6000} /> + {props.dataSourceEnabled && dataSourceMenuComponent} { render={(_routerProps) => !isNavGroupEnabled ? ( - {props.dataSourceEnabled && dataSourceMenuComponent} { ) : ( <> - {props.dataSourceEnabled && dataSourceMenuComponent} - { render={(_routerProps) => !isNavGroupEnabled ? ( - {props.dataSourceEnabled && dataSourceMenuComponent} { ) : ( <> - {props.dataSourceEnabled && dataSourceMenuComponent} Date: Thu, 19 Sep 2024 21:05:34 -0700 Subject: [PATCH 02/10] add tooltip to the re-direct Signed-off-by: Adam Tackett --- .../overview/components/dashboard_controls.tsx | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/public/components/overview/components/dashboard_controls.tsx b/public/components/overview/components/dashboard_controls.tsx index 8c4864dfa..077e8712b 100644 --- a/public/components/overview/components/dashboard_controls.tsx +++ b/public/components/overview/components/dashboard_controls.tsx @@ -16,6 +16,7 @@ import { import { OnTimeChangeProps } from '@opensearch-project/oui/src/eui_components/date_picker/super_date_picker/super_date_picker'; import React from 'react'; import { useObservable } from 'react-use'; +import { FormattedMessage } from '@osd/i18n/react'; import { coreRefs } from '../../../framework/core_refs'; import { HOME_CONTENT_AREAS } from '../../../plugin_helpers/plugin_overview'; import { redirectToDashboards } from '../../getting_started/components/utils'; @@ -58,12 +59,18 @@ export function DashboardControls() { - redirectToDashboards('/view/' + dashboardState?.dashboardId)} - external={true} + + } > - - + redirectToDashboards('/view/' + dashboardState?.dashboardId)} + external={true} + > + + +
From f84379aef963bc43df2495c852905eeddbe20b56 Mon Sep 17 00:00:00 2001 From: Adam Tackett Date: Thu, 19 Sep 2024 21:17:07 -0700 Subject: [PATCH 03/10] fix services view page revert Signed-off-by: Adam Tackett --- .../__snapshots__/service_view.test.tsx.snap | 15 +++++++ .../components/services/service_view.tsx | 43 +++++++++++++------ 2 files changed, 46 insertions(+), 12 deletions(-) diff --git a/public/components/trace_analytics/components/services/__tests__/__snapshots__/service_view.test.tsx.snap b/public/components/trace_analytics/components/services/__tests__/__snapshots__/service_view.test.tsx.snap index 98e899464..eee380aed 100644 --- a/public/components/trace_analytics/components/services/__tests__/__snapshots__/service_view.test.tsx.snap +++ b/public/components/trace_analytics/components/services/__tests__/__snapshots__/service_view.test.tsx.snap @@ -97,6 +97,21 @@ exports[`Service view component renders service view 1`] = ` + + + Name + + + order + + diff --git a/public/components/trace_analytics/components/services/service_view.tsx b/public/components/trace_analytics/components/services/service_view.tsx index 8ada47351..e57214401 100644 --- a/public/components/trace_analytics/components/services/service_view.tsx +++ b/public/components/trace_analytics/components/services/service_view.tsx @@ -26,7 +26,10 @@ import { } from '@elastic/eui'; import round from 'lodash/round'; import React, { useEffect, useMemo, useState } from 'react'; -import { DataSourceManagementPluginSetup } from '../../../../../../../src/plugins/data_source_management/public'; +import { + DataSourceManagementPluginSetup, + DataSourceViewConfig, +} from '../../../../../../../src/plugins/data_source_management/public'; import { DataSourceOption } from '../../../../../../../src/plugins/data_source_management/public/components/data_source_menu/types'; import { DEFAULT_DATA_SOURCE_NAME, @@ -34,7 +37,9 @@ import { } from '../../../../../common/constants/data_sources'; import { observabilityLogsID } from '../../../../../common/constants/shared'; import { setNavBreadCrumbs } from '../../../../../common/utils/set_nav_bread_crumbs'; +import { dataSourceFilterFn } from '../../../../../common/utils/shared'; import { coreRefs } from '../../../../framework/core_refs'; +import { HeaderControlledComponentsWrapper } from '../../../../plugin_helpers/plugin_headerControl'; import { TraceAnalyticsComponentDeps } from '../../home'; import { handleServiceMapRequest, @@ -119,8 +124,9 @@ export function ServiceView(props: ServiceViewProps) { }, ] ); - props.setDataSourceMenuSelectable?.(false); - }, [props.serviceName, props.setDataSourceMenuSelectable]); + }, [props.serviceName]); + + const DataSourceMenu = props.dataSourceManagement?.ui?.getDataSourceMenu(); const redirectToServicePage = (service: string) => { window.location.href = `#/services/${service}`; @@ -238,9 +244,13 @@ export function ServiceView(props: ServiceViewProps) { {renderDatePicker(startTime, setStartTime, endTime, setEndTime)} + ) : coreRefs?.chrome?.navGroup.getNavGroupEnabled() ? ( + ) : ( - {!newNavigation ? serviceHeader : null} + {serviceHeader} {renderDatePicker(startTime, setStartTime, endTime, setEndTime)} @@ -253,20 +263,29 @@ export function ServiceView(props: ServiceViewProps) { const renderOverview = () => { return ( <> + {props.dataSourceEnabled && ( + + )} - {newNavigation && ( - - Name - - {props.serviceName || '-'} - - - )} + + Name + + {props.serviceName || '-'} + + {mode === 'data_prepper' || mode === 'custom_data_prepper' ? ( Number of connected services From b11af64cc7061dc809cd5c147ff290abd6139df4 Mon Sep 17 00:00:00 2001 From: Adam Tackett Date: Thu, 19 Sep 2024 21:22:09 -0700 Subject: [PATCH 04/10] fix services view page revert Signed-off-by: Adam Tackett --- .../trace_analytics/components/services/service_view.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/components/trace_analytics/components/services/service_view.tsx b/public/components/trace_analytics/components/services/service_view.tsx index e57214401..286350cce 100644 --- a/public/components/trace_analytics/components/services/service_view.tsx +++ b/public/components/trace_analytics/components/services/service_view.tsx @@ -250,7 +250,7 @@ export function ServiceView(props: ServiceViewProps) { /> ) : ( - {serviceHeader} + {!newNavigation ? serviceHeader : null} {renderDatePicker(startTime, setStartTime, endTime, setEndTime)} From 27defbd641c5f8de96b35fc3c90a7ee9796857b0 Mon Sep 17 00:00:00 2001 From: Adam Tackett Date: Fri, 20 Sep 2024 04:23:38 -0700 Subject: [PATCH 05/10] fix services view Signed-off-by: Adam Tackett --- .../components/services/service_view.tsx | 28 ++++--------------- 1 file changed, 5 insertions(+), 23 deletions(-) diff --git a/public/components/trace_analytics/components/services/service_view.tsx b/public/components/trace_analytics/components/services/service_view.tsx index 286350cce..37850327a 100644 --- a/public/components/trace_analytics/components/services/service_view.tsx +++ b/public/components/trace_analytics/components/services/service_view.tsx @@ -26,10 +26,7 @@ import { } from '@elastic/eui'; import round from 'lodash/round'; import React, { useEffect, useMemo, useState } from 'react'; -import { - DataSourceManagementPluginSetup, - DataSourceViewConfig, -} from '../../../../../../../src/plugins/data_source_management/public'; +import { DataSourceManagementPluginSetup } from '../../../../../../../src/plugins/data_source_management/public'; import { DataSourceOption } from '../../../../../../../src/plugins/data_source_management/public/components/data_source_menu/types'; import { DEFAULT_DATA_SOURCE_NAME, @@ -37,7 +34,6 @@ import { } from '../../../../../common/constants/data_sources'; import { observabilityLogsID } from '../../../../../common/constants/shared'; import { setNavBreadCrumbs } from '../../../../../common/utils/set_nav_bread_crumbs'; -import { dataSourceFilterFn } from '../../../../../common/utils/shared'; import { coreRefs } from '../../../../framework/core_refs'; import { HeaderControlledComponentsWrapper } from '../../../../plugin_helpers/plugin_headerControl'; import { TraceAnalyticsComponentDeps } from '../../home'; @@ -53,8 +49,6 @@ import { SpanDetailFlyout } from '../traces/span_detail_flyout'; import { SpanDetailTable } from '../traces/span_detail_table'; import { ServiceMetrics } from './service_metrics'; -const newNavigation = coreRefs.chrome?.navGroup.getNavGroupEnabled(); - interface ServiceViewProps extends TraceAnalyticsComponentDeps { serviceName: string; addFilter: (filter: FilterType) => void; @@ -124,9 +118,8 @@ export function ServiceView(props: ServiceViewProps) { }, ] ); - }, [props.serviceName]); - - const DataSourceMenu = props.dataSourceManagement?.ui?.getDataSourceMenu(); + props.setDataSourceMenuSelectable?.(false); + }, [props.serviceName, props.setDataSourceMenuSelectable]); const redirectToServicePage = (service: string) => { window.location.href = `#/services/${service}`; @@ -230,7 +223,7 @@ export function ServiceView(props: ServiceViewProps) { {_page === 'serviceFlyout' ? ( - {!newNavigation ? serviceHeader : null} + {serviceHeader} ) : ( - {!newNavigation ? serviceHeader : null} + {serviceHeader} {renderDatePicker(startTime, setStartTime, endTime, setEndTime)} @@ -263,17 +256,6 @@ export function ServiceView(props: ServiceViewProps) { const renderOverview = () => { return ( <> - {props.dataSourceEnabled && ( - - )} From 5d865cfacfedbe089dd49e16e01b2c57f826f128 Mon Sep 17 00:00:00 2001 From: Adam Tackett Date: Fri, 27 Sep 2024 10:17:22 -0700 Subject: [PATCH 06/10] applied comments Signed-off-by: Adam Tackett --- public/components/trace_analytics/home.tsx | 51 ++++++++++------------ 1 file changed, 23 insertions(+), 28 deletions(-) diff --git a/public/components/trace_analytics/home.tsx b/public/components/trace_analytics/home.tsx index e790dbf8e..6c324977a 100644 --- a/public/components/trace_analytics/home.tsx +++ b/public/components/trace_analytics/home.tsx @@ -150,34 +150,29 @@ export const Home = (props: HomeProps) => { }; const dataSourceMenuComponent = useMemo(() => { - if (!dataSourceMenuSelectable) { - return ( - - ); - } else { - return ( - - ); - } + const sharedProps = { + setMenuMountPoint: props.setActionMenu, + componentConfig: { + activeOption: dataSourceMDSId, + fullWidth: true, + dataSourceFilter: dataSourceFilterFn, + }, + }; + + return dataSourceMenuSelectable ? ( + + ) : ( + + ); }, [ dataSourceMenuSelectable, props.setActionMenu, From e484e45ea7a7a016b8df5436bd124d4df6b899af Mon Sep 17 00:00:00 2001 From: Adam Tackett Date: Fri, 27 Sep 2024 16:36:14 -0700 Subject: [PATCH 07/10] fix traces bug Signed-off-by: Adam Tackett --- .../components/traces/trace_view.tsx | 23 ++++--------------- .../components/traces/traces_content.tsx | 4 +++- public/components/trace_analytics/home.tsx | 1 + 3 files changed, 9 insertions(+), 19 deletions(-) diff --git a/public/components/trace_analytics/components/traces/trace_view.tsx b/public/components/trace_analytics/components/traces/trace_view.tsx index fcb7a5ee4..470730978 100644 --- a/public/components/trace_analytics/components/traces/trace_view.tsx +++ b/public/components/trace_analytics/components/traces/trace_view.tsx @@ -20,14 +20,10 @@ import { import round from 'lodash/round'; import React, { useEffect, useState } from 'react'; import { MountPoint } from '../../../../../../../src/core/public'; -import { - DataSourceManagementPluginSetup, - DataSourceViewConfig, -} from '../../../../../../../src/plugins/data_source_management/public'; +import { DataSourceManagementPluginSetup } from '../../../../../../../src/plugins/data_source_management/public'; import { DataSourceOption } from '../../../../../../../src/plugins/data_source_management/public/components/data_source_menu/types'; import { TraceAnalyticsMode } from '../../../../../common/types/trace_analytics'; import { setNavBreadCrumbs } from '../../../../../common/utils/set_nav_bread_crumbs'; -import { dataSourceFilterFn } from '../../../../../common/utils/shared'; import { coreRefs } from '../../../../framework/core_refs'; import { TraceAnalyticsCoreDeps } from '../../home'; import { handleServiceMapRequest } from '../../requests/services_request_handler'; @@ -49,6 +45,7 @@ interface TraceViewProps extends TraceAnalyticsCoreDeps { dataSourceMDSId: DataSourceOption[]; dataSourceManagement: DataSourceManagementPluginSetup; setActionMenu: (menuMount: MountPoint | undefined) => void; + setDataSourceMenuSelectable?: React.Dispatch>; } export function TraceView(props: TraceViewProps) { @@ -67,7 +64,6 @@ export function TraceView(props: TraceViewProps) { ); }; - const DataSourceMenu = props.dataSourceManagement?.ui?.getDataSourceMenu(); const renderOverview = (fields: any) => { return ( @@ -256,22 +252,13 @@ export function TraceView(props: TraceViewProps) { }, ] ); + props.setDataSourceMenuSelectable?.(false); refresh(); - }, [props.mode]); + }, [props.mode, props.setDataSourceMenuSelectable]); + return ( <> - {props.dataSourceEnabled && ( - - )} {renderTitle(props.traceId)} diff --git a/public/components/trace_analytics/components/traces/traces_content.tsx b/public/components/trace_analytics/components/traces/traces_content.tsx index 828c70058..82c77641b 100644 --- a/public/components/trace_analytics/components/traces/traces_content.tsx +++ b/public/components/trace_analytics/components/traces/traces_content.tsx @@ -103,7 +103,8 @@ export function TracesContent(props: TracesProps) { (mode === 'data_prepper' && dataPrepperIndicesExist) || (mode === 'jaeger' && jaegerIndicesExist)) ) - refresh(); + props.setDataSourceMenuSelectable?.(true); + refresh(); }, [ filters, appConfigs, @@ -113,6 +114,7 @@ export function TracesContent(props: TracesProps) { dataPrepperIndicesExist, includeMetrics, tracesTableMode, + props.setDataSourceMenuSelectable, ]); const onToggle = (isOpen: boolean) => { diff --git a/public/components/trace_analytics/home.tsx b/public/components/trace_analytics/home.tsx index 6c324977a..2b60876e0 100644 --- a/public/components/trace_analytics/home.tsx +++ b/public/components/trace_analytics/home.tsx @@ -395,6 +395,7 @@ export const Home = (props: HomeProps) => { notifications={props.notifications} dataSourceEnabled={props.dataSourceEnabled} savedObjectsMDSClient={props.savedObjectsMDSClient} + setDataSourceMenuSelectable={setDataSourceMenuSelectable} /> )} /> From 32fcf79ecf17d4dcd139f6830af57b5f6d8ee237 Mon Sep 17 00:00:00 2001 From: Adam Tackett Date: Thu, 3 Oct 2024 10:46:22 -0700 Subject: [PATCH 08/10] Fix bugs and add url redirection and testing Signed-off-by: Adam Tackett --- common/constants/shared.ts | 4 +- .../__tests__/legacy_route_helpers.test.tsx | 164 +++++++++++++ .../components/common/legacy_route_helpers.ts | 76 +++++- .../components/services/service_view.tsx | 20 +- public/components/trace_analytics/home.tsx | 217 +++++++++--------- public/plugin.tsx | 20 +- 6 files changed, 389 insertions(+), 112 deletions(-) create mode 100644 public/components/trace_analytics/components/common/__tests__/legacy_route_helpers.test.tsx diff --git a/common/constants/shared.ts b/common/constants/shared.ts index b5ef687b1..a21ad65e9 100644 --- a/common/constants/shared.ts +++ b/common/constants/shared.ts @@ -60,13 +60,13 @@ export const observabilityMetricsTitle = 'Metrics'; export const observabilityMetricsPluginOrder = 5092; export const observabilityTracesNewNavID = 'observability-traces-nav'; -export const observabilityTracesNewNavURL = observabilityTracesNewNavID + '#/traces'; +export const observabilityTracesNewNavURL = observabilityTracesNewNavID; export const observabilityTracesID = 'observability-traces'; export const observabilityTracesTitle = 'Traces'; export const observabilityTracesPluginOrder = 5093; export const observabilityServicesNewNavID = 'observability-services-nav'; -export const observabilityServicesNewNavURL = observabilityServicesNewNavID + '#/services'; +export const observabilityServicesNewNavURL = observabilityServicesNewNavID; export const observabilityServicesID = 'observability-services'; export const observabilityServicesTitle = 'Services'; export const observabilityServicesPluginOrder = 5092; diff --git a/public/components/trace_analytics/components/common/__tests__/legacy_route_helpers.test.tsx b/public/components/trace_analytics/components/common/__tests__/legacy_route_helpers.test.tsx new file mode 100644 index 000000000..5c61767f7 --- /dev/null +++ b/public/components/trace_analytics/components/common/__tests__/legacy_route_helpers.test.tsx @@ -0,0 +1,164 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { + convertLegacyTraceAnalyticsUrl, + convertTraceAnalyticsNewNavUrl, +} from '../legacy_route_helpers'; +import { + observabilityTracesID, + observabilityTracesNewNavID, + observabilityServicesNewNavID, +} from '../../../../../../common/constants/shared'; +import { coreRefs } from '../../../../../framework/core_refs'; + +describe('ConvertLegacyTraceAnalyticsUrl', () => { + it('should convert legacy URL correctly', () => { + const location = { + pathname: '/app/trace-analytics-dashboards', + hash: '#/traces', + search: '?param1=value1', + } as Location; + + const result = convertLegacyTraceAnalyticsUrl(location); + expect(result).toBe(`/app/${observabilityTracesID}#/traces?param1=value1`); + }); + + it('should handle URL with existing hash parameters', () => { + const location = { + pathname: '/app/trace-analytics-dashboards', + hash: '#/traces?existing=param', + search: '?param1=value1', + } as Location; + + const result = convertLegacyTraceAnalyticsUrl(location); + expect(result).toBe(`/app/${observabilityTracesID}#/traces?existing=param¶m1=value1`); + }); +}); + +describe('ConvertTraceAnalyticsNewNavUrl', () => { + let originalLocation; + + beforeEach(() => { + // Save the original window.location object + originalLocation = window.location; + + // Mock window.location.assign + Object.defineProperty(window, 'location', { + value: { + assign: jest.fn(), + }, + writable: true, + }); + }); + + afterEach(() => { + // Restore the original window.location object after each test + window.location = originalLocation; + }); + + it('should redirect to the new navigation traces URL if trace ID is present and new nav is enabled', () => { + const locationMock = { + pathname: `/app/${observabilityTracesID}`, + hash: '#/traces/03f9c770db5ee2f1caac0afc36db49ba', + } as Location; + + coreRefs.chrome = { navGroup: { getNavGroupEnabled: jest.fn().mockReturnValue(true) } }; + + convertTraceAnalyticsNewNavUrl(locationMock); + + expect(window.location.assign).toHaveBeenCalledWith( + `/app/${observabilityTracesNewNavID}#/traces?datasourceId=&traceId=03f9c770db5ee2f1caac0afc36db49ba` + ); + }); + + it('should redirect to the old navigation traces URL if trace ID is present and new nav is disabled', () => { + const locationMock = { + pathname: `/app/${observabilityTracesID}`, + hash: '#/traces/03f9c770db5ee2f1caac0afc36db49ba', + } as Location; + + coreRefs.chrome = { navGroup: { getNavGroupEnabled: jest.fn().mockReturnValue(false) } }; + + convertTraceAnalyticsNewNavUrl(locationMock); + + expect(window.location.assign).toHaveBeenCalledWith( + `/app/${observabilityTracesID}#/traces?datasourceId=&traceId=03f9c770db5ee2f1caac0afc36db49ba` + ); + }); + + it('should redirect to the new navigation services URL if service ID is present and new nav is enabled', () => { + const locationMock = { + pathname: `/app/${observabilityTracesID}`, + hash: '#/services/analytics-service', + } as Location; + + coreRefs.chrome = { navGroup: { getNavGroupEnabled: jest.fn().mockReturnValue(true) } }; + + convertTraceAnalyticsNewNavUrl(locationMock); + + expect(window.location.assign).toHaveBeenCalledWith( + `/app/${observabilityServicesNewNavID}#/services?datasourceId=&serviceId=analytics-service` + ); + }); + + it('should redirect to the old navigation services URL if service ID is present and new nav is disabled', () => { + const locationMock = { + pathname: `/app/${observabilityTracesID}`, + hash: '#/services/analytics-service', + } as Location; + + coreRefs.chrome = { navGroup: { getNavGroupEnabled: jest.fn().mockReturnValue(false) } }; + + convertTraceAnalyticsNewNavUrl(locationMock); + + expect(window.location.assign).toHaveBeenCalledWith( + `/app/${observabilityTracesID}#/services?datasourceId=&serviceId=analytics-service` + ); + }); + + it('should redirect to new navigation traces page if on root traces page and new nav is enabled', () => { + const locationMock = { + pathname: `/app/${observabilityTracesID}`, + hash: '#/traces', + } as Location; + + coreRefs.chrome = { navGroup: { getNavGroupEnabled: jest.fn().mockReturnValue(true) } }; + + convertTraceAnalyticsNewNavUrl(locationMock); + + expect(window.location.assign).toHaveBeenCalledWith( + `/app/${observabilityTracesNewNavID}#/traces` + ); + }); + + it('should redirect to new navigation services page if on root services page and new nav is enabled', () => { + const locationMock = { + pathname: `/app/${observabilityTracesID}`, + hash: '#/services', + } as Location; + + coreRefs.chrome = { navGroup: { getNavGroupEnabled: jest.fn().mockReturnValue(true) } }; + + convertTraceAnalyticsNewNavUrl(locationMock); + + expect(window.location.assign).toHaveBeenCalledWith( + `/app/${observabilityServicesNewNavID}#/services` + ); + }); + + it('should not redirect if new nav is disabled and on root traces/services page', () => { + const locationMock = { + pathname: `/app/${observabilityTracesID}`, + hash: '#/services', + } as Location; + + coreRefs.chrome = { navGroup: { getNavGroupEnabled: jest.fn().mockReturnValue(false) } }; + + convertTraceAnalyticsNewNavUrl(locationMock); + + expect(window.location.assign).not.toHaveBeenCalled(); + }); +}); diff --git a/public/components/trace_analytics/components/common/legacy_route_helpers.ts b/public/components/trace_analytics/components/common/legacy_route_helpers.ts index 3be7bfbf0..65943382f 100644 --- a/public/components/trace_analytics/components/common/legacy_route_helpers.ts +++ b/public/components/trace_analytics/components/common/legacy_route_helpers.ts @@ -3,7 +3,12 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { observabilityTracesID } from '../../../../../common/constants/shared'; +import { + observabilityTracesID, + observabilityTracesNewNavID, + observabilityServicesNewNavID, +} from '../../../../../common/constants/shared'; +import { coreRefs } from '../../../../framework/core_refs'; export const convertLegacyTraceAnalyticsUrl = (location: Location) => { const pathname = location.pathname.replace('trace-analytics-dashboards', observabilityTracesID); @@ -12,3 +17,72 @@ export const convertLegacyTraceAnalyticsUrl = (location: Location) => { }`; return pathname + hash; }; + +export const convertTraceAnalyticsNewNavUrl = (location: Location) => { + const pathname = location.pathname; + const hash = location.hash; + + const isNewNavEnabled = coreRefs?.chrome?.navGroup?.getNavGroupEnabled(); + + // Handle service URLs with IDs + if (hash.includes('#/services/')) { + const serviceId = location.hash.split('/services/')[1]?.split('?')[0] || ''; + if (serviceId) { + if (isNewNavEnabled) { + window.location.assign( + `/app/${observabilityServicesNewNavID}#/services?datasourceId=&serviceId=${encodeURIComponent( + serviceId + )}` + ); + } else { + window.location.assign( + `/app/${observabilityTracesID}#/services?datasourceId=&serviceId=${encodeURIComponent( + serviceId + )}` + ); + } + return; + } + } + + // Handle trace URLs with IDs + if (hash.includes('#/traces/')) { + const traceId = location.hash.split('/traces/')[1]?.split('?')[0] || ''; + if (traceId) { + if (isNewNavEnabled) { + window.location.assign( + `/app/${observabilityTracesNewNavID}#/traces?datasourceId=&traceId=${encodeURIComponent( + traceId + )}` + ); + } else { + window.location.assign( + `/app/${observabilityTracesID}#/traces?datasourceId=&traceId=${encodeURIComponent( + traceId + )}` + ); + } + return; + } + } + + if (hash === '#/traces') { + if (isNewNavEnabled) { + window.location.assign(`/app/${observabilityTracesNewNavID}#/traces`); + } + return; + } + + if (hash === '#/services') { + if (isNewNavEnabled) { + window.location.assign(`/app/${observabilityServicesNewNavID}#/services`); + } + return; + } + + if (pathname === `/app/${observabilityTracesID}`) { + if (isNewNavEnabled) { + window.location.assign(`/app/${observabilityTracesNewNavID}#/traces`); + } + } +}; diff --git a/public/components/trace_analytics/components/services/service_view.tsx b/public/components/trace_analytics/components/services/service_view.tsx index 37850327a..17a07068a 100644 --- a/public/components/trace_analytics/components/services/service_view.tsx +++ b/public/components/trace_analytics/components/services/service_view.tsx @@ -114,7 +114,16 @@ export function ServiceView(props: ServiceViewProps) { }, { text: props.serviceName, - href: `#/services/${encodeURIComponent(props.serviceName)}`, + href: (() => { + const dataSourceId = props.dataSourceMDSId[0].id; + if (dataSourceId && dataSourceId !== '') { + return `#/services?datasourceId=${encodeURIComponent( + dataSourceId + )}&serviceId=${encodeURIComponent(props.serviceName)}`; + } else { + return `#/services?serviceId=${encodeURIComponent(props.serviceName)}`; + } + })(), }, ] ); @@ -122,7 +131,14 @@ export function ServiceView(props: ServiceViewProps) { }, [props.serviceName, props.setDataSourceMenuSelectable]); const redirectToServicePage = (service: string) => { - window.location.href = `#/services/${service}`; + const dataSourceId = props.dataSourceMDSId[0].id; + if (dataSourceId && dataSourceId !== '') { + window.location.href = `#/services?datasourceId=${encodeURIComponent( + dataSourceId + )}&serviceId=${encodeURIComponent(service)}`; + } else { + window.location.href = `#/services?datasourceId=&serviceId=${encodeURIComponent(service)}`; + } }; const onClickConnectedService = (service: string) => { diff --git a/public/components/trace_analytics/home.tsx b/public/components/trace_analytics/home.tsx index 2b60876e0..ebe3e4978 100644 --- a/public/components/trace_analytics/home.tsx +++ b/public/components/trace_analytics/home.tsx @@ -22,7 +22,6 @@ import { } from '../../../../../src/plugins/data_source_management/public'; import { TRACE_TABLE_TYPE_KEY } from '../../../common/constants/trace_analytics'; import { TraceAnalyticsMode, TraceQueryMode } from '../../../common/types/trace_analytics'; -import { dataSourceFilterFn } from '../../../common/utils/shared'; import { coreRefs } from '../../framework/core_refs'; import { FilterType } from './components/common/filters/filters'; import { getAttributes, getSpanIndices } from './components/common/helper_functions'; @@ -119,7 +118,13 @@ export const Home = (props: HomeProps) => { (sessionStorage.getItem(TRACE_TABLE_TYPE_KEY) as TraceQueryMode) || 'all_spans' ); - const [dataSourceMDSId, setDataSourceMDSId] = useState([{ id: '', label: '' }]); + // Get existing query params + const queryParamsOnLoad = new URLSearchParams(window.location.href.split('?')[1]); + const dsFromURL = queryParamsOnLoad.get('datasourceId'); + + const [dataSourceMDSId, setDataSourceMDSId] = useState([ + { id: dsFromURL ?? undefined, label: undefined }, + ]); const [currentSelectedService, setCurrentSelectedService] = useState(''); const [dataSourceMenuSelectable, setDataSourceMenuSelectable] = useState(true); @@ -146,16 +151,26 @@ export const Home = (props: HomeProps) => { const dataConnectionId = e[0] ? e[0].id : undefined; const dataConnectionLabel = e[0] ? e[0].label : undefined; - setDataSourceMDSId([{ id: dataConnectionId, label: dataConnectionLabel }]); + if (dataConnectionId !== dataSourceMDSId[0].id) { + setDataSourceMDSId([{ id: dataConnectionId, label: dataConnectionLabel }]); + + const currentUrl = window.location.href.split('?')[0]; + const queryParams = new URLSearchParams(window.location.search); + + queryParams.set('datasourceId', dataConnectionId); + + window.history.replaceState(null, '', `${currentUrl}?${queryParams.toString()}`); + } }; const dataSourceMenuComponent = useMemo(() => { const sharedProps = { setMenuMountPoint: props.setActionMenu, componentConfig: { - activeOption: dataSourceMDSId, + activeOption: dataSourceMDSId[0].id === undefined ? undefined : dataSourceMDSId, + savedObjects: props.savedObjectsMDSClient.client, + notifications: props.notifications, fullWidth: true, - dataSourceFilter: dataSourceFilterFn, }, }; @@ -165,8 +180,6 @@ export const Home = (props: HomeProps) => { componentType={'DataSourceSelectable'} componentConfig={{ ...sharedProps.componentConfig, - savedObjects: props.savedObjectsMDSClient.client, - notifications: props.notifications, onSelectedDataSources: onSelectedDataSource, }} /> @@ -174,6 +187,7 @@ export const Home = (props: HomeProps) => { ); }, [ + dataSourceMDSId, dataSourceMenuSelectable, props.setActionMenu, props.savedObjectsMDSClient.client, @@ -259,7 +273,18 @@ export const Home = (props: HomeProps) => { sessionStorage.setItem(TRACE_TABLE_TYPE_KEY, 'traces'); }; - const getTraceViewUri = (traceId: string) => `#/traces/${encodeURIComponent(traceId)}`; + const getTraceViewUri = (traceId: string) => { + const dataSourceId = dataSourceMDSId[0].id; + if (dataSourceId && dataSourceId !== '') { + // If a datasourceId is selected, include it in the URL + return `#/traces?datasourceId=${encodeURIComponent( + dataSourceId + )}&traceId=${encodeURIComponent(traceId)}`; + } else { + // If no datasourceId is selected leave it as empty + return `#/traces?datasourceId=&traceId=${encodeURIComponent(traceId)}`; + } + }; const [spanFlyoutComponent, setSpanFlyoutComponent] = useState(<>); @@ -346,112 +371,92 @@ export const Home = (props: HomeProps) => { {props.dataSourceEnabled && dataSourceMenuComponent} - !isNavGroupEnabled ? ( - - - - ) : ( - <> - { + const queryParams = new URLSearchParams(window.location.href.split('?')[1]); + const traceId = queryParams.get('traceId'); + + const SideBarComponent = !isNavGroupEnabled ? TraceSideBar : React.Fragment; + if (!traceId) { + return ( + + + + ); + } else { + return ( + - - ) - } + ); + } + }} /> ( - - )} - /> - - !isNavGroupEnabled ? ( - - { + const queryParams = new URLSearchParams(window.location.href.split('?')[1]); + const serviceId = queryParams.get('serviceId'); + + const SideBarComponent = !isNavGroupEnabled ? TraceSideBar : React.Fragment; + if (!serviceId) { + return ( + + + + ); + } else { + return ( + - - ) : ( - <> - { + for (const addedFilter of filters) { + if ( + addedFilter.field === filter.field && + addedFilter.operator === filter.operator && + addedFilter.value === filter.value + ) { + return; + } + } + const newFilters = [...filters, filter]; + setFiltersWithStorage(newFilters); + }} dataSourceMDSId={dataSourceMDSId} - {...commonProps} /> - - ) - } - /> - ( - { - for (const addedFilter of filters) { - if ( - addedFilter.field === filter.field && - addedFilter.operator === filter.operator && - addedFilter.value === filter.value - ) { - return; - } - } - const newFilters = [...filters, filter]; - setFiltersWithStorage(newFilters); - }} - dataSourceMDSId={dataSourceMDSId} - /> - )} + ); + } + }} /> } /> diff --git a/public/plugin.tsx b/public/plugin.tsx index cbcdd3d6f..e7ec341f3 100644 --- a/public/plugin.tsx +++ b/public/plugin.tsx @@ -81,7 +81,10 @@ import { AccelerationDetailsFlyout } from './components/datasources/components/m import { CreateAcceleration } from './components/datasources/components/manage/accelerations/create_accelerations_flyout'; import { AssociatedObjectsDetailsFlyout } from './components/datasources/components/manage/associated_objects/associated_objects_details_flyout'; import { convertLegacyNotebooksUrl } from './components/notebooks/components/helpers/legacy_route_helpers'; -import { convertLegacyTraceAnalyticsUrl } from './components/trace_analytics/components/common/legacy_route_helpers'; +import { + convertLegacyTraceAnalyticsUrl, + convertTraceAnalyticsNewNavUrl, +} from './components/trace_analytics/components/common/legacy_route_helpers'; import { registerAsssitantDependencies } from './dependencies/register_assistant'; import { OBSERVABILITY_EMBEDDABLE, @@ -452,6 +455,21 @@ export class ObservabilityPlugin coreRefs.navigation = startDeps.navigation; coreRefs.contentManagement = startDeps.contentManagement; + // redirect trace URL to current URL under observability + // if (window.location.hash.includes('#/traces/')) { + // window.location.assign(convertTraceUrl(window.location)); + // } + + // // redirect service analytics URL to current URL under observability + // if (window.location.hash.includes('#/services/')) { + // window.location.assign(convertServiceUrl(window.location)); + // } + + // redirect legacy trace analytics URL to current URL under observability + if (window.location.pathname.includes(observabilityTracesID)) { + convertTraceAnalyticsNewNavUrl(window.location); + } + const { dataSourceService, dataSourceFactory } = startDeps.data.dataSources; dataSourceFactory.registerDataSourceType(S3_DATA_SOURCE_TYPE, S3DataSource); From 3e064a23f40453613929d6b362be1ca1ea0daaf8 Mon Sep 17 00:00:00 2001 From: Adam Tackett Date: Thu, 3 Oct 2024 12:02:40 -0700 Subject: [PATCH 09/10] remove comment Signed-off-by: Adam Tackett --- public/plugin.tsx | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/public/plugin.tsx b/public/plugin.tsx index e7ec341f3..c3f9e757d 100644 --- a/public/plugin.tsx +++ b/public/plugin.tsx @@ -455,17 +455,7 @@ export class ObservabilityPlugin coreRefs.navigation = startDeps.navigation; coreRefs.contentManagement = startDeps.contentManagement; - // redirect trace URL to current URL under observability - // if (window.location.hash.includes('#/traces/')) { - // window.location.assign(convertTraceUrl(window.location)); - // } - - // // redirect service analytics URL to current URL under observability - // if (window.location.hash.includes('#/services/')) { - // window.location.assign(convertServiceUrl(window.location)); - // } - - // redirect legacy trace analytics URL to current URL under observability + // redirect trace URL based on new navigation if (window.location.pathname.includes(observabilityTracesID)) { convertTraceAnalyticsNewNavUrl(window.location); } From b285346de6a84eaa06d37d6644e74b600ac16a7e Mon Sep 17 00:00:00 2001 From: Adam Tackett Date: Thu, 3 Oct 2024 17:15:59 -0700 Subject: [PATCH 10/10] address comments Signed-off-by: Adam Tackett --- .../overview/components/card_configs.tsx | 8 +- .../components/dashboard_controls.tsx | 5 +- .../__tests__/legacy_route_helpers.test.tsx | 90 +++++++++++++++++++ .../components/common/helper_functions.tsx | 10 +++ .../components/services/service_view.tsx | 27 ++---- 5 files changed, 116 insertions(+), 24 deletions(-) diff --git a/public/components/overview/components/card_configs.tsx b/public/components/overview/components/card_configs.tsx index 9ddcfcf5f..2ebcbbb73 100644 --- a/public/components/overview/components/card_configs.tsx +++ b/public/components/overview/components/card_configs.tsx @@ -7,8 +7,8 @@ import { i18n } from '@osd/i18n'; import { observabilityGettingStartedID, observabilityMetricsID, - observabilityTracesNewNavURL, - observabilityServicesNewNavURL, + observabilityTracesNewNavID, + observabilityServicesNewNavID, alertingPluginID, anomalyDetectionPluginID, tutorialSampleDataPluginId, @@ -82,7 +82,7 @@ const TRACES_CONFIG: GettingStartedConfig = { }), description: 'Analyze performance bottlenecks using event flow visualizations.', footer: 'Traces', - url: observabilityTracesNewNavURL, + url: observabilityTracesNewNavID, path: '#/', }; @@ -94,7 +94,7 @@ const SERVICES_CONFIG: GettingStartedConfig = { }), description: 'Identify service performance issues with comprehensive monitoring and analysis.', footer: 'Services', - url: observabilityServicesNewNavURL, + url: observabilityServicesNewNavID, path: '#/', }; diff --git a/public/components/overview/components/dashboard_controls.tsx b/public/components/overview/components/dashboard_controls.tsx index 077e8712b..893170b39 100644 --- a/public/components/overview/components/dashboard_controls.tsx +++ b/public/components/overview/components/dashboard_controls.tsx @@ -61,7 +61,10 @@ export function DashboardControls() { + } > { + let originalLocation: Location; + + beforeEach(() => { + originalLocation = window.location; + + Object.defineProperty(window, 'location', { + value: { + ...originalLocation, + assign: jest.fn(), + }, + writable: true, + }); + }); + + afterEach(() => { + window.location = originalLocation; + }); + it('should convert legacy URL correctly', () => { const location = { pathname: '/app/trace-analytics-dashboards', @@ -36,6 +54,78 @@ describe('ConvertLegacyTraceAnalyticsUrl', () => { const result = convertLegacyTraceAnalyticsUrl(location); expect(result).toBe(`/app/${observabilityTracesID}#/traces?existing=param¶m1=value1`); }); + + it('should convert legacy trace URL with ID and redirect to the new nav traces URL', () => { + const location = { + pathname: '/app/trace-analytics-dashboards', + hash: '#/traces/02feb3a4f611abd81f2a53244d1278ae', + search: '', + } as Location; + + coreRefs.chrome = { navGroup: { getNavGroupEnabled: jest.fn().mockReturnValue(true) } }; + + const result = convertLegacyTraceAnalyticsUrl(location); + expect(result).toBe(`/app/${observabilityTracesID}#/traces/02feb3a4f611abd81f2a53244d1278ae`); + + convertTraceAnalyticsNewNavUrl(location); + expect(window.location.assign).toHaveBeenCalledWith( + `/app/${observabilityTracesNewNavID}#/traces?datasourceId=&traceId=02feb3a4f611abd81f2a53244d1278ae` + ); + }); + + it('should convert legacy service URL with ID and redirect to the new nav services URL', () => { + const location = { + pathname: '/app/trace-analytics-dashboards', + hash: '#/services/analytics-service', + search: '', + } as Location; + + coreRefs.chrome = { navGroup: { getNavGroupEnabled: jest.fn().mockReturnValue(true) } }; + + const result = convertLegacyTraceAnalyticsUrl(location); + expect(result).toBe(`/app/${observabilityTracesID}#/services/analytics-service`); + + convertTraceAnalyticsNewNavUrl(location); + expect(window.location.assign).toHaveBeenCalledWith( + `/app/${observabilityServicesNewNavID}#/services?datasourceId=&serviceId=analytics-service` + ); + }); + + it('should convert legacy trace URL with ID and redirect to the old nav traces URL', () => { + const location = { + pathname: '/app/trace-analytics-dashboards', + hash: '#/traces/02feb3a4f611abd81f2a53244d1278ae', + search: '', + } as Location; + + coreRefs.chrome = { navGroup: { getNavGroupEnabled: jest.fn().mockReturnValue(false) } }; + + const result = convertLegacyTraceAnalyticsUrl(location); + expect(result).toBe(`/app/${observabilityTracesID}#/traces/02feb3a4f611abd81f2a53244d1278ae`); + + convertTraceAnalyticsNewNavUrl(location); + expect(window.location.assign).toHaveBeenCalledWith( + `/app/${observabilityTracesID}#/traces?datasourceId=&traceId=02feb3a4f611abd81f2a53244d1278ae` + ); + }); + + it('should convert legacy service URL with ID and redirect to the old nav services URL', () => { + const location = { + pathname: '/app/trace-analytics-dashboards', + hash: '#/services/analytics-service', + search: '', + } as Location; + + coreRefs.chrome = { navGroup: { getNavGroupEnabled: jest.fn().mockReturnValue(false) } }; + + const result = convertLegacyTraceAnalyticsUrl(location); + expect(result).toBe(`/app/${observabilityTracesID}#/services/analytics-service`); + + convertTraceAnalyticsNewNavUrl(location); + expect(window.location.assign).toHaveBeenCalledWith( + `/app/${observabilityTracesID}#/services?datasourceId=&serviceId=analytics-service` + ); + }); }); describe('ConvertTraceAnalyticsNewNavUrl', () => { diff --git a/public/components/trace_analytics/components/common/helper_functions.tsx b/public/components/trace_analytics/components/common/helper_functions.tsx index e90fab06d..6bec57e73 100644 --- a/public/components/trace_analytics/components/common/helper_functions.tsx +++ b/public/components/trace_analytics/components/common/helper_functions.tsx @@ -612,3 +612,13 @@ export const getServiceIndices = (mode: TraceAnalyticsMode) => { return JAEGER_SERVICE_INDEX_NAME; } }; + +export const generateServiceUrl = (service: string, dataSourceId: string) => { + const url = `#/services?serviceId=${encodeURIComponent(service)}`; + + if (dataSourceId && dataSourceId !== '') { + return `${url}&datasourceId=${encodeURIComponent(dataSourceId)}`; + } + + return `${url}&datasourceId=`; +}; diff --git a/public/components/trace_analytics/components/services/service_view.tsx b/public/components/trace_analytics/components/services/service_view.tsx index 17a07068a..01e565215 100644 --- a/public/components/trace_analytics/components/services/service_view.tsx +++ b/public/components/trace_analytics/components/services/service_view.tsx @@ -42,7 +42,12 @@ import { handleServiceViewRequest, } from '../../requests/services_request_handler'; import { FilterType } from '../common/filters/filters'; -import { PanelTitle, filtersToDsl, processTimeStamp } from '../common/helper_functions'; +import { + PanelTitle, + filtersToDsl, + generateServiceUrl, + processTimeStamp, +} from '../common/helper_functions'; import { ServiceMap, ServiceObject } from '../common/plots/service_map'; import { SearchBarProps, renderDatePicker } from '../common/search_bar'; import { SpanDetailFlyout } from '../traces/span_detail_flyout'; @@ -114,16 +119,7 @@ export function ServiceView(props: ServiceViewProps) { }, { text: props.serviceName, - href: (() => { - const dataSourceId = props.dataSourceMDSId[0].id; - if (dataSourceId && dataSourceId !== '') { - return `#/services?datasourceId=${encodeURIComponent( - dataSourceId - )}&serviceId=${encodeURIComponent(props.serviceName)}`; - } else { - return `#/services?serviceId=${encodeURIComponent(props.serviceName)}`; - } - })(), + href: generateServiceUrl(props.serviceName, props.dataSourceMDSId[0].id), }, ] ); @@ -131,14 +127,7 @@ export function ServiceView(props: ServiceViewProps) { }, [props.serviceName, props.setDataSourceMenuSelectable]); const redirectToServicePage = (service: string) => { - const dataSourceId = props.dataSourceMDSId[0].id; - if (dataSourceId && dataSourceId !== '') { - window.location.href = `#/services?datasourceId=${encodeURIComponent( - dataSourceId - )}&serviceId=${encodeURIComponent(service)}`; - } else { - window.location.href = `#/services?datasourceId=&serviceId=${encodeURIComponent(service)}`; - } + window.location.href = generateServiceUrl(service, props.dataSourceMDSId[0].id); }; const onClickConnectedService = (service: string) => {