diff --git a/frontend/src/container/TraceDetail/SelectedSpanDetails/Tags/index.tsx b/frontend/src/container/TraceDetail/SelectedSpanDetails/Tags/index.tsx index 7bd2449cc1..4c9e5227ca 100644 --- a/frontend/src/container/TraceDetail/SelectedSpanDetails/Tags/index.tsx +++ b/frontend/src/container/TraceDetail/SelectedSpanDetails/Tags/index.tsx @@ -1,4 +1,6 @@ -import { Input, Typography } from 'antd'; +import { Input, List, Typography } from 'antd'; +import ROUTES from 'constants/routes'; +import { formUrlParams } from 'container/TraceDetail/utils'; import React, { useCallback, useEffect, useMemo, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { ITraceTag } from 'types/api/trace/getTraceItem'; @@ -7,7 +9,12 @@ import { ModalText } from '..'; import { Container } from './styles'; import Tag from './Tag'; -function Tags({ tags, onToggleHandler, setText }: TagsProps): JSX.Element { +function Tags({ + tags, + linkedSpans, + onToggleHandler, + setText, +}: TagsProps): JSX.Element { const { t } = useTranslation(['traceDetails']); const [allRenderedTags, setAllRenderedTags] = useState(tags); const isSearchVisible = useMemo(() => tags.length > 5, [tags]); @@ -16,6 +23,16 @@ function Tags({ tags, onToggleHandler, setText }: TagsProps): JSX.Element { setAllRenderedTags(tags); }, [tags]); + const getLink = useCallback( + (item: Record) => + `${ROUTES.TRACE}/${item.TraceId}${formUrlParams({ + spanId: item.SpanId, + levelUp: 0, + levelDown: 0, + })}`, + [], + ); + const onChangeHandler = useCallback( (e: React.ChangeEvent): void => { const { value } = e.target; @@ -38,7 +55,6 @@ function Tags({ tags, onToggleHandler, setText }: TagsProps): JSX.Element { onChange={onChangeHandler} /> )} - {allRenderedTags.map((tag) => ( ))} + {linkedSpans && linkedSpans.length > 0 && ( + Linked Spans} + dataSource={linkedSpans} + renderItem={(item): JSX.Element => ( + + {item.SpanId} + + )} + /> + )} ); } interface TagsProps extends CommonTagsProps { tags: ITraceTag[]; + linkedSpans?: Record[]; } export interface CommonTagsProps { @@ -62,4 +90,8 @@ export interface CommonTagsProps { setText: React.Dispatch>; } +Tags.defaultProps = { + linkedSpans: [], +}; + export default Tags; diff --git a/frontend/src/container/TraceDetail/SelectedSpanDetails/index.tsx b/frontend/src/container/TraceDetail/SelectedSpanDetails/index.tsx index d6c37783a1..a9bf00cd0f 100644 --- a/frontend/src/container/TraceDetail/SelectedSpanDetails/index.tsx +++ b/frontend/src/container/TraceDetail/SelectedSpanDetails/index.tsx @@ -42,7 +42,7 @@ function SelectedSpanDetails(props: SelectedSpanDetailsProps): JSX.Element { return
; } - const { tags } = tree; + const { tags, nonChildReferences } = tree; return ( @@ -83,7 +83,12 @@ function SelectedSpanDetails(props: SelectedSpanDetailsProps): JSX.Element { - + []; + nonChildReferences?: Record[]; // For internal use isProcessed?: boolean; - references?: Record[]; } export interface ITraceTag { diff --git a/frontend/src/utils/__tests__/__snapshots__/spanToTree.test.ts.snap b/frontend/src/utils/__tests__/__snapshots__/spanToTree.test.ts.snap index 2c2ab402e2..c3149cf21a 100644 --- a/frontend/src/utils/__tests__/__snapshots__/spanToTree.test.ts.snap +++ b/frontend/src/utils/__tests__/__snapshots__/spanToTree.test.ts.snap @@ -5,10 +5,31 @@ Object { "missingSpanTree": Array [], "spanTree": Array [ Object { + "childReferences": Array [ + Object { + "RefType": "CHILD_OF", + "SpanId": "", + "TraceId": "0000000000000000span_1", + }, + ], "children": Array [ Object { + "childReferences": Array [ + Object { + "RefType": "CHILD_OF", + "SpanId": "span_1", + "TraceId": "0000000000000000span_1", + }, + ], "children": Array [ Object { + "childReferences": Array [ + Object { + "RefType": "CHILD_OF", + "SpanId": "span_2", + "TraceId": "0000000000000000span_1", + }, + ], "children": Array [], "event": Array [ Object { @@ -25,13 +46,7 @@ Object { "id": "span_3", "isProcessed": true, "name": "HTTP GET SPAN 3", - "references": Array [ - Object { - "RefType": "CHILD_OF", - "SpanId": "span_2", - "TraceId": "0000000000000000span_1", - }, - ], + "nonChildReferences": Array [], "serviceColour": "", "serviceName": "frontend", "startTime": 1657275433246, @@ -60,13 +75,7 @@ Object { "id": "span_2", "isProcessed": true, "name": "HTTP GET SPAN 2", - "references": Array [ - Object { - "RefType": "CHILD_OF", - "SpanId": "span_1", - "TraceId": "0000000000000000span_1", - }, - ], + "nonChildReferences": Array [], "serviceColour": "", "serviceName": "frontend", "startTime": 1657275433246, @@ -94,13 +103,7 @@ Object { "hasError": false, "id": "span_1", "name": "HTTP GET SPAN 1", - "references": Array [ - Object { - "RefType": "CHILD_OF", - "SpanId": "", - "TraceId": "0000000000000000span_1", - }, - ], + "nonChildReferences": Array [], "serviceColour": "", "serviceName": "frontend", "startTime": 1657275433246, @@ -123,6 +126,13 @@ Object { Object { "children": Array [ Object { + "childReferences": Array [ + Object { + "RefType": "CHILD_OF", + "SpanId": "span_2", + "TraceId": "0000000000000000span_1", + }, + ], "children": Array [], "event": Array [ Object { @@ -139,13 +149,7 @@ Object { "id": "span_3", "isProcessed": true, "name": "HTTP GET SPAN 3", - "references": Array [ - Object { - "RefType": "CHILD_OF", - "SpanId": "span_2", - "TraceId": "0000000000000000span_1", - }, - ], + "nonChildReferences": Array [], "serviceColour": "", "serviceName": "frontend", "startTime": 1657275433246, @@ -172,6 +176,13 @@ Object { ], "spanTree": Array [ Object { + "childReferences": Array [ + Object { + "RefType": "CHILD_OF", + "SpanId": "", + "TraceId": "0000000000000000span_1", + }, + ], "children": Array [], "event": Array [ Object { @@ -187,13 +198,7 @@ Object { "hasError": false, "id": "span_1", "name": "HTTP GET SPAN 1", - "references": Array [ - Object { - "RefType": "CHILD_OF", - "SpanId": "", - "TraceId": "0000000000000000span_1", - }, - ], + "nonChildReferences": Array [], "serviceColour": "", "serviceName": "frontend", "startTime": 1657275433246, diff --git a/frontend/src/utils/spanToTree.ts b/frontend/src/utils/spanToTree.ts index 4a1933c2d4..35d17f0681 100644 --- a/frontend/src/utils/spanToTree.ts +++ b/frontend/src/utils/spanToTree.ts @@ -4,8 +4,20 @@ import { ITraceForest, ITraceTree, Span } from 'types/api/trace/getTraceItem'; const getSpanReferences = ( rawReferences: string[] = [], -): Record[] => - rawReferences.map((rawRef) => { + isChildReference: boolean, +): Record[] => { + let filteredReferences = []; + if (isChildReference) { + filteredReferences = rawReferences.filter((value) => + value.includes('CHILD_OF'), + ); + } else { + filteredReferences = rawReferences.filter( + (value) => !value.includes('CHILD_OF'), + ); + } + + return filteredReferences.map((rawRef) => { const refObject: Record = {}; rawRef .replaceAll('{', '') @@ -19,6 +31,7 @@ const getSpanReferences = ( return refObject; }); +}; // This getSpanTags is migrated from the previous implementation. const getSpanTags = (spanData: Span): { key: string; value: string }[] => { @@ -41,7 +54,7 @@ export const spanToTreeUtil = (inputSpanList: Span[]): ITraceForest => { const traceIdSet: Set = new Set(); const spanMap: Record = {}; - const createTarceRootSpan = ( + const createTraceRootSpan = ( spanReferences: Record[], ): void => { spanReferences.forEach(({ SpanId, TraceId }) => { @@ -64,7 +77,8 @@ export const spanToTreeUtil = (inputSpanList: Span[]): ITraceForest => { }; spanList.forEach((span) => { - const spanReferences = getSpanReferences(span[9] as string[]); + const childReferences = getSpanReferences(span[9] as string[], true); + const nonChildReferences = getSpanReferences(span[9] as string[], false); const spanObject = { id: span[1], name: span[4], @@ -76,16 +90,17 @@ export const spanToTreeUtil = (inputSpanList: Span[]): ITraceForest => { serviceName: span[3], hasError: !!span[11], serviceColour: '', - event: span[10].map((e) => JSON.parse(e || '{}') || {}), - references: spanReferences, + event: span[10]?.map((e) => JSON.parse(e || '{}') || {}), + childReferences, + nonChildReferences, }; spanMap[span[1]] = spanObject; }); for (const [, spanData] of Object.entries(spanMap)) { - if (spanData.references) { - createTarceRootSpan(spanData.references); - spanData.references.forEach(({ SpanId: parentSpanId }) => { + if (spanData.childReferences) { + createTraceRootSpan(spanData.childReferences); + spanData.childReferences.forEach(({ SpanId: parentSpanId }) => { if (spanMap[parentSpanId]) { spanData.isProcessed = true; spanMap[parentSpanId].children.push(spanData); @@ -103,7 +118,9 @@ export const spanToTreeUtil = (inputSpanList: Span[]): ITraceForest => { const missingSpanTree: ITraceTree[] = []; const referencedTraceIds: string[] = Array.from(traceIdSet); Object.keys(spanMap).forEach((spanId) => { - const isRoot = spanMap[spanId].references?.some((refs) => refs.SpanId === ''); + const isRoot = spanMap[spanId].childReferences?.some( + (refs) => refs.SpanId === '', + ); if (isRoot) { spanTree.push(spanMap[spanId]); return;