From be246574236aed227417d98f578af09af68080f8 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sat, 5 Oct 2024 00:26:01 +0000 Subject: [PATCH] [Bug] Services Data Picker, UI Fixes (#2177) * bug fix services data picker, ui fixes Signed-off-by: Adam Tackett * add tooltip to the re-direct Signed-off-by: Adam Tackett * fix services view page revert Signed-off-by: Adam Tackett * fix services view page revert Signed-off-by: Adam Tackett * fix services view Signed-off-by: Adam Tackett * applied comments Signed-off-by: Adam Tackett * fix traces bug Signed-off-by: Adam Tackett * Fix bugs and add url redirection and testing Signed-off-by: Adam Tackett * remove comment Signed-off-by: Adam Tackett * address comments Signed-off-by: Adam Tackett --------- Signed-off-by: Adam Tackett Signed-off-by: Shenoy Pratik Co-authored-by: Adam Tackett Co-authored-by: Shenoy Pratik (cherry picked from commit cf01e521e79c71e9b250639f4f21c2f2cb111332) Signed-off-by: github-actions[bot] --- common/constants/shared.ts | 4 +- .../__snapshots__/top_menu.test.tsx.snap | 210 +++++---------- .../components/metrics/top_menu/top_menu.tsx | 15 +- .../overview/components/card_configs.tsx | 8 +- .../components/dashboard_controls.tsx | 37 ++- .../__snapshots__/search_bar.test.tsx.snap | 10 +- .../__tests__/legacy_route_helpers.test.tsx | 254 ++++++++++++++++++ .../components/common/helper_functions.tsx | 10 + .../components/common/legacy_route_helpers.ts | 76 +++++- .../components/common/search_bar.tsx | 1 + .../__snapshots__/service_view.test.tsx.snap | 2 +- .../components/services/service_view.tsx | 33 +-- .../components/services/services_content.tsx | 3 +- .../__snapshots__/trace_view.test.tsx.snap | 2 +- .../components/traces/trace_view.tsx | 25 +- .../components/traces/traces_content.tsx | 4 +- public/components/trace_analytics/home.tsx | 254 ++++++++++-------- public/plugin.tsx | 10 +- 18 files changed, 630 insertions(+), 328 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 607b9894c..516fbce5d 100644 --- a/common/constants/shared.ts +++ b/common/constants/shared.ts @@ -61,13 +61,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/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/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 6847b1fcb..893170b39 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, @@ -15,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'; @@ -48,15 +50,32 @@ 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/__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..634717a36 --- /dev/null +++ b/public/components/trace_analytics/components/common/__tests__/legacy_route_helpers.test.tsx @@ -0,0 +1,254 @@ +/* + * 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', () => { + 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', + 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`); + }); + + 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', () => { + 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/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/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/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 ( (); + props.setDataSourceMenuSelectable?.(false); + }, [props.serviceName, props.setDataSourceMenuSelectable]); const redirectToServicePage = (service: string) => { - window.location.href = `#/services/${service}`; + window.location.href = generateServiceUrl(service, props.dataSourceMDSId[0].id); }; const onClickConnectedService = (service: string) => { @@ -261,17 +261,6 @@ export function ServiceView(props: ServiceViewProps) { const renderOverview = () => { return ( <> - {props.dataSourceEnabled && ( - - )} 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`] = `
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,27 +252,18 @@ export function TraceView(props: TraceViewProps) { }, ] ); + props.setDataSourceMenuSelectable?.(false); refresh(); - }, [props.mode]); + }, [props.mode, props.setDataSourceMenuSelectable]); + return ( <> - {props.dataSourceEnabled && ( - - )} {renderTitle(props.traceId)} - + {renderOverview(fields)} 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 268881c04..ebe3e4978 100644 --- a/public/components/trace_analytics/home.tsx +++ b/public/components/trace_analytics/home.tsx @@ -18,10 +18,10 @@ import { import { DataSourceManagementPluginSetup, DataSourceSelectableConfig, + DataSourceViewConfig, } 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'; @@ -73,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,8 +117,16 @@ export const Home = (props: HomeProps) => { const [tracesTableMode, setTracesTableMode] = useState( (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); // Navigate a valid routes when suffixed with '/traces' and '/services' // Route defaults to traces page @@ -133,28 +143,56 @@ 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; - 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(() => { - return ( + const sharedProps = { + setMenuMountPoint: props.setActionMenu, + componentConfig: { + activeOption: dataSourceMDSId[0].id === undefined ? undefined : dataSourceMDSId, + savedObjects: props.savedObjectsMDSClient.client, + notifications: props.notifications, + fullWidth: true, + }, + }; + + return dataSourceMenuSelectable ? ( + ) : ( + ); - }, [props.setActionMenu, props.savedObjectsMDSClient.client, props.notifications]); + }, [ + dataSourceMDSId, + dataSourceMenuSelectable, + props.setActionMenu, + props.savedObjectsMDSClient.client, + props.notifications, + ]); useEffect(() => { handleDataPrepperIndicesExistRequest( @@ -235,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(<>); @@ -293,6 +342,8 @@ export const Home = (props: HomeProps) => { savedObjectsMDSClient: props.savedObjectsMDSClient, attributesFilterFields, setSpanFlyout, + setDataSourceMenuSelectable, + currentSelectedService, }; let flyout; @@ -317,118 +368,95 @@ export const Home = (props: HomeProps) => { }} toastLifeTimeMs={6000} /> + {props.dataSourceEnabled && dataSourceMenuComponent} - !isNavGroupEnabled ? ( - - {props.dataSourceEnabled && dataSourceMenuComponent} - - - ) : ( - <> - {props.dataSourceEnabled && dataSourceMenuComponent} - - { + 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 ? ( - - {props.dataSourceEnabled && dataSourceMenuComponent} - { + 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 ( + - - ) : ( - <> - {props.dataSourceEnabled && dataSourceMenuComponent} - { + 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 4dabd09b6..24c8d36d2 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,11 @@ export class ObservabilityPlugin coreRefs.navigation = startDeps.navigation; coreRefs.contentManagement = startDeps.contentManagement; + // redirect trace URL based on new navigation + if (window.location.pathname.includes(observabilityTracesID)) { + convertTraceAnalyticsNewNavUrl(window.location); + } + const { dataSourceService, dataSourceFactory } = startDeps.data.dataSources; dataSourceFactory.registerDataSourceType(S3_DATA_SOURCE_TYPE, S3DataSource);