diff --git a/public/components/trace_analytics/components/dashboard/dashboard_content.tsx b/public/components/trace_analytics/components/dashboard/dashboard_content.tsx index a67f0b12c..9cf1d8cd9 100644 --- a/public/components/trace_analytics/components/dashboard/dashboard_content.tsx +++ b/public/components/trace_analytics/components/dashboard/dashboard_content.tsx @@ -44,7 +44,7 @@ export function DashboardContent(props: DashboardProps) { startTime, endTime, childBreadcrumbs, - parentBreadcrumbs, + parentBreadcrumb, filters, setStartTime, setEndTime, @@ -83,7 +83,7 @@ export function DashboardContent(props: DashboardProps) { }, [showTimeoutToast]); useEffect(() => { - // chrome.setBreadcrumbs([...parentBreadcrumbs, ...childBreadcrumbs]); + chrome.setBreadcrumbs([parentBreadcrumb, ...childBreadcrumbs]); const validFilters = getValidFilterFields(mode, page); setFilters([ ...filters.map((filter) => ({ diff --git a/public/components/trace_analytics/components/services/service_view.tsx b/public/components/trace_analytics/components/services/service_view.tsx index 0121af258..5101760a0 100644 --- a/public/components/trace_analytics/components/services/service_view.tsx +++ b/public/components/trace_analytics/components/services/service_view.tsx @@ -62,7 +62,7 @@ export function ServiceView(props: ServiceViewProps) { useEffect(() => { props.chrome.setBreadcrumbs([ - ...props.parentBreadcrumbs, + props.parentBreadcrumb, { text: 'Trace analytics', href: '#/trace_analytics/home', diff --git a/public/components/trace_analytics/components/services/services_content.tsx b/public/components/trace_analytics/components/services/services_content.tsx index e25bf8726..417c9420e 100644 --- a/public/components/trace_analytics/components/services/services_content.tsx +++ b/public/components/trace_analytics/components/services/services_content.tsx @@ -30,7 +30,7 @@ export function ServicesContent(props: ServicesProps) { endTime, appConfigs = [], childBreadcrumbs, - parentBreadcrumbs, + parentBreadcrumb, nameColumnAction, traceColumnAction, setFilters, @@ -51,7 +51,7 @@ export function ServicesContent(props: ServicesProps) { const [filteredService, setFilteredService] = useState(''); useEffect(() => { - chrome.setBreadcrumbs([...parentBreadcrumbs, ...childBreadcrumbs]); + chrome.setBreadcrumbs([parentBreadcrumb, ...childBreadcrumbs]); const validFilters = getValidFilterFields(mode, 'services'); setFilters([ ...filters.map((filter) => ({ @@ -71,12 +71,25 @@ export function ServicesContent(props: ServicesProps) { } } setFilteredService(newFilteredService); - if (!redirect && ((mode === 'data_prepper' && dataPrepperIndicesExist) || (mode === 'jaeger' && jaegerIndicesExist))) refresh(newFilteredService); + if ( + !redirect && + ((mode === 'data_prepper' && dataPrepperIndicesExist) || + (mode === 'jaeger' && jaegerIndicesExist)) + ) + refresh(newFilteredService); }, [filters, appConfigs, redirect, mode, jaegerIndicesExist, dataPrepperIndicesExist]); const refresh = async (currService?: string) => { setLoading(true); - const DSL = filtersToDsl(mode, filters, query,processTimeStamp(startTime, mode), processTimeStamp(endTime, mode), page, appConfigs); + const DSL = filtersToDsl( + mode, + filters, + query, + processTimeStamp(startTime, mode), + processTimeStamp(endTime, mode), + page, + appConfigs + ); // service map should not be filtered by service name const serviceMapDSL = _.cloneDeep(DSL); serviceMapDSL.query.bool.must = serviceMapDSL.query.bool.must.filter( @@ -84,7 +97,13 @@ export function ServicesContent(props: ServicesProps) { ); await Promise.all([ handleServicesRequest(http, DSL, setTableItems, mode), - handleServiceMapRequest(http, serviceMapDSL, mode, setServiceMap, currService || filteredService), + handleServiceMapRequest( + http, + serviceMapDSL, + mode, + setServiceMap, + currService || filteredService + ), ]); setLoading(false); }; @@ -133,7 +152,7 @@ export function ServicesContent(props: ServicesProps) { dataPrepperIndicesExist={dataPrepperIndicesExist} /> - { (mode === 'data_prepper' && dataPrepperIndicesExist) ? + {mode === 'data_prepper' && dataPrepperIndicesExist ? ( : (
) - } + /> + ) : ( +
+ )} ); } diff --git a/public/components/trace_analytics/components/traces/trace_view.tsx b/public/components/trace_analytics/components/traces/trace_view.tsx index 46fd00325..3f460e405 100644 --- a/public/components/trace_analytics/components/traces/trace_view.tsx +++ b/public/components/trace_analytics/components/traces/trace_view.tsx @@ -206,7 +206,7 @@ export function TraceView(props: TraceViewProps) { useEffect(() => { props.chrome.setBreadcrumbs([ - ...props.parentBreadcrumbs, + props.parentBreadcrumb, { text: 'Trace analytics', href: '#/trace_analytics/home', diff --git a/public/components/trace_analytics/components/traces/traces_content.tsx b/public/components/trace_analytics/components/traces/traces_content.tsx index 66764f988..2efc70ec7 100644 --- a/public/components/trace_analytics/components/traces/traces_content.tsx +++ b/public/components/trace_analytics/components/traces/traces_content.tsx @@ -23,7 +23,7 @@ export function TracesContent(props: TracesProps) { appConfigs, startTime, endTime, - parentBreadcrumbs, + parentBreadcrumb, childBreadcrumbs, traceIdColumnAction, setQuery, @@ -39,7 +39,7 @@ export function TracesContent(props: TracesProps) { const [loading, setLoading] = useState(false); useEffect(() => { - chrome.setBreadcrumbs([...parentBreadcrumbs, ...childBreadcrumbs]); + chrome.setBreadcrumbs([parentBreadcrumb, ...childBreadcrumbs]); const validFilters = getValidFilterFields(mode, 'traces'); setFilters([ ...filters.map((filter) => ({ @@ -51,13 +51,33 @@ export function TracesContent(props: TracesProps) { }, []); useEffect(() => { - if (!redirect && ((mode === 'data_prepper' && dataPrepperIndicesExist) || (mode === 'jaeger' && jaegerIndicesExist))) refresh(); + if ( + !redirect && + ((mode === 'data_prepper' && dataPrepperIndicesExist) || + (mode === 'jaeger' && jaegerIndicesExist)) + ) + refresh(); }, [filters, appConfigs, redirect, mode, dataPrepperIndicesExist, jaegerIndicesExist]); const refresh = async (sort?: PropertySort) => { setLoading(true); - const DSL = filtersToDsl(mode, filters, query, processTimeStamp(startTime, mode), processTimeStamp(endTime, mode), page, appConfigs); - const timeFilterDSL = filtersToDsl(mode, [], '', processTimeStamp(startTime, mode), processTimeStamp(endTime, mode), page); + const DSL = filtersToDsl( + mode, + filters, + query, + processTimeStamp(startTime, mode), + processTimeStamp(endTime, mode), + page, + appConfigs + ); + const timeFilterDSL = filtersToDsl( + mode, + [], + '', + processTimeStamp(startTime, mode), + processTimeStamp(endTime, mode), + page + ); await handleTracesRequest(http, DSL, timeFilterDSL, tableItems, setTableItems, mode, sort); setLoading(false); }; diff --git a/public/components/trace_analytics/home.tsx b/public/components/trace_analytics/home.tsx index d9c443ff1..e0ad209a6 100644 --- a/public/components/trace_analytics/home.tsx +++ b/public/components/trace_analytics/home.tsx @@ -6,36 +6,35 @@ import { EuiGlobalToastList } from '@elastic/eui'; import { Toast } from '@elastic/eui/src/components/toast/global_toast_list'; import React, { ReactChild, useEffect, useState } from 'react'; -import { Route, RouteComponentProps } from 'react-router-dom'; -import { - ChromeBreadcrumb, - ChromeStart, - HttpStart, -} from '../../../../../src/core/public'; -import { ObservabilitySideBar } from '../common/side_nav'; +import { HashRouter, Route, RouteComponentProps } from 'react-router-dom'; +import { ChromeBreadcrumb, ChromeStart, HttpStart } from '../../../../../src/core/public'; import { FilterType } from './components/common/filters/filters'; import { SearchBarProps } from './components/common/search_bar'; import { Dashboard } from './components/dashboard'; import { Services, ServiceView } from './components/services'; import { Traces, TraceView } from './components/traces'; -import { handleDataPrepperIndicesExistRequest, handleJaegerIndicesExistRequest } from './requests/request_handler'; +import { + handleDataPrepperIndicesExistRequest, + handleJaegerIndicesExistRequest, +} from './requests/request_handler'; +import { TraceSideBar } from './trace_side_nav'; export interface TraceAnalyticsCoreDeps { - parentBreadcrumbs: ChromeBreadcrumb[]; + parentBreadcrumb: ChromeBreadcrumb; http: HttpStart; chrome: ChromeStart; } interface HomeProps extends RouteComponentProps, TraceAnalyticsCoreDeps {} -export type TraceAnalyticsMode = 'jaeger' | 'data_prepper' +export type TraceAnalyticsMode = 'jaeger' | 'data_prepper'; export interface TraceAnalyticsComponentDeps extends TraceAnalyticsCoreDeps, SearchBarProps { mode: TraceAnalyticsMode; - modes: { + modes: Array<{ id: string; title: string; - }[]; + }>; setMode: (mode: TraceAnalyticsMode) => void; jaegerIndicesExist: boolean; dataPrepperIndicesExist: boolean; @@ -44,7 +43,9 @@ export interface TraceAnalyticsComponentDeps extends TraceAnalyticsCoreDeps, Sea export const Home = (props: HomeProps) => { const [dataPrepperIndicesExist, setDataPrepperIndicesExist] = useState(false); const [jaegerIndicesExist, setJaegerIndicesExist] = useState(false); - const [mode, setMode] = useState(sessionStorage.getItem('TraceAnalyticsMode') as TraceAnalyticsMode || 'jaeger') + const [mode, setMode] = useState( + (sessionStorage.getItem('TraceAnalyticsMode') as TraceAnalyticsMode) || 'jaeger' + ); const storedFilters = sessionStorage.getItem('TraceAnalyticsFilters'); const [query, setQuery] = useState(sessionStorage.getItem('TraceAnalyticsQuery') || ''); const [filters, setFilters] = useState( @@ -81,18 +82,17 @@ export const Home = (props: HomeProps) => { }; useEffect(() => { - handleDataPrepperIndicesExistRequest(props.http, setDataPrepperIndicesExist) + handleDataPrepperIndicesExistRequest(props.http, setDataPrepperIndicesExist); handleJaegerIndicesExistRequest(props.http, setJaegerIndicesExist); }, []); - const modes = [ { id: 'jaeger', title: 'Jaeger', 'data-test-subj': 'jaeger-mode' }, { id: 'data_prepper', title: 'Data Prepper', 'data-test-subj': 'data-prepper-mode' }, ]; useEffect(() => { - if (!sessionStorage.getItem('TraceAnalyticsMode')){ + if (!sessionStorage.getItem('TraceAnalyticsMode')) { if (dataPrepperIndicesExist) { setMode('data_prepper'); } else if (jaegerIndicesExist) { @@ -104,33 +104,33 @@ export const Home = (props: HomeProps) => { const dashboardBreadcrumbs = [ { text: 'Trace analytics', - href: '#/trace_analytics/home', + href: '#/', }, { text: 'Dashboard', - href: '#/trace_analytics/home', + href: '#/', }, ]; const serviceBreadcrumbs = [ { text: 'Trace analytics', - href: '#/trace_analytics/home', + href: '#/', }, { text: 'Services', - href: '#/trace_analytics/services', + href: '#/services', }, ]; const traceBreadcrumbs = [ { text: 'Trace analytics', - href: '#/trace_analytics/home', + href: '#/', }, { text: 'Traces', - href: '#/trace_analytics/traces', + href: '#/traces', }, ]; @@ -145,13 +145,13 @@ export const Home = (props: HomeProps) => { const [appConfigs, _] = useState([]); const commonProps: TraceAnalyticsComponentDeps = { - parentBreadcrumbs: props.parentBreadcrumbs, + parentBreadcrumb: props.parentBreadcrumb, http: props.http, chrome: props.chrome, query, setQuery: setQueryWithStorage, filters, - appConfigs: appConfigs, + appConfigs, setFilters: setFiltersWithStorage, startTime, setStartTime: setStartTimeWithStorage, @@ -159,7 +159,9 @@ export const Home = (props: HomeProps) => { setEndTime: setEndTimeWithStorage, mode, modes, - setMode: (mode: TraceAnalyticsMode) => {setMode(mode)}, + setMode: (traceMode: TraceAnalyticsMode) => { + setMode(traceMode); + }, jaegerIndicesExist, dataPrepperIndicesExist, }; @@ -167,84 +169,92 @@ export const Home = (props: HomeProps) => { return ( <> { - setToasts(toasts.filter((toast) => toast.id !== removedToast.id)); - }} - toastLifeTimeMs={6000} - /> - ( - - - - )} + toasts={toasts} + dismissToast={(removedToast) => { + setToasts(toasts.filter((toast) => toast.id !== removedToast.id)); + }} + toastLifeTimeMs={6000} /> - ( - - + ( + + + + )} + /> + ( + + + + )} + /> + ( + - - )} - /> - ( - - )} - /> - ( - - + ( + + + + )} + /> + ( + - - )} - /> - ( - { - for (const addedFilter of filters) { - if ( - addedFilter.field === filter.field && - addedFilter.operator === filter.operator && - addedFilter.value === filter.value - ) { - return; + addFilter={(filter: FilterType) => { + 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); - }} - /> - )} - /> + const newFilters = [...filters, filter]; + setFiltersWithStorage(newFilters); + }} + /> + )} + /> + ); }; diff --git a/public/components/trace_analytics/trace_side_nav.tsx b/public/components/trace_analytics/trace_side_nav.tsx new file mode 100644 index 000000000..77cb44596 --- /dev/null +++ b/public/components/trace_analytics/trace_side_nav.tsx @@ -0,0 +1,74 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { + EuiButton, + EuiFlexGroup, + EuiFlexItem, + EuiPage, + EuiPageBody, + EuiPageSideBar, + EuiSideNav, + EuiSideNavItemType, + EuiSwitch, +} from '@elastic/eui'; +import React from 'react'; + +export function TraceSideBar(props: { children: React.ReactNode }) { + function setIsSelected(items: Array>, hash: string): boolean { + if (hash === '#/') { + items[0].isSelected = true; + return true; + } + if (hash === '#/traces') { + items[0].items[0].isSelected = true; + return true; + } + if (hash === '#/services') { + items[0].items[1].isSelected = true; + return true; + } + } + + const items = [ + { + name: 'Trace analytics', + id: 1, + href: '#/', + items: [ + { + name: 'Traces', + id: 1.1, + href: '#/traces', + }, + { + name: 'Services', + id: 1.2, + href: '#/services', + }, + ], + }, + ]; + + setIsSelected(items, location.hash); + + return ( + + + + + + + + + {props.children} + + ); +}