From be7b0dae61bd65b1cb47c00321c631376c4224c7 Mon Sep 17 00:00:00 2001 From: Ruben Vargas Date: Wed, 13 Nov 2019 15:40:59 -0600 Subject: [PATCH 01/22] Add button icon to spans with multiple references Signed-off-by: Ruben Vargas --- .../TraceTimelineViewer/ReferencesButton.css | 19 +++ .../TraceTimelineViewer/ReferencesButton.tsx | 110 ++++++++++++++++++ .../TraceTimelineViewer/SpanBarRow.tsx | 5 +- 3 files changed, 133 insertions(+), 1 deletion(-) create mode 100644 packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.css create mode 100644 packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.tsx diff --git a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.css b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.css new file mode 100644 index 0000000000..f3980a1cc1 --- /dev/null +++ b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.css @@ -0,0 +1,19 @@ +/* +Copyright (c) 2019 Uber Technologies, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +.multi-parent-button { + padding: 0 5px; +} diff --git a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.tsx b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.tsx new file mode 100644 index 0000000000..e29b6fca71 --- /dev/null +++ b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.tsx @@ -0,0 +1,110 @@ +// Copyright (c) 2019 Uber Technologies, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import React from 'react'; +import { Dropdown, Menu, Tooltip } from 'antd'; +import IoNetwork from 'react-icons/lib/io/network'; +import { bindActionCreators } from 'redux'; +import { connect, Dispatch } from 'react-redux'; +import { withRouter } from 'react-router-dom'; +import { History as RouterHistory, Location } from 'history'; + +import './ReferencesButton.css'; + +import { FetchedTrace, ReduxState, TNil } from '../../../types'; +import { actions as timelineActions } from './duck'; +import { extractUiFindFromState } from '../../common/UiFindInput'; +import { SpanReference, Trace } from '../../../types/trace'; +import updateUiFind from '../../../utils/update-ui-find'; + +type TDispatchProps = { + focusUiFindMatches: (trace: Trace, uiFind: string | TNil) => void; +}; + +type TReduxProps = { + uiFind: string | TNil; + trace: FetchedTrace | TNil; +}; + +type TOwnProps = { + references: SpanReference[]; + traceID: string; + history: RouterHistory; + location: Location; + match: any; +}; + +type TReferencesButtonProps = TDispatchProps & TReduxProps & TOwnProps; + +class ReferencesButtonImpl extends React.PureComponent { + focusUiFindMatches = (uiFind: string) => { + const { trace, focusUiFindMatches, location, history } = this.props; + if (trace && trace.data) { + updateUiFind({ + location, + history, + uiFind, + }); + focusUiFindMatches(trace.data, uiFind); + } + }; + + referencesList = (references: SpanReference[]) => ( + + {references.map(({ span, spanID }) => ( + + this.focusUiFindMatches(spanID)}> + {span ? `${span.operationName} - ${spanID}` : spanID} + + + ))} + + ); + + render() { + const { references } = this.props; + + return ( + + + + + + + + ); + } +} + +export function mapDispatchToProps(dispatch: Dispatch): TDispatchProps { + const { focusUiFindMatches } = bindActionCreators(timelineActions, dispatch); + return { focusUiFindMatches }; +} + +// export for tests +export function mapStateToProps(state: ReduxState, ownProps: TOwnProps): TReduxProps { + const { traces } = state.trace; + const trace = ownProps.traceID ? traces[ownProps.traceID] : null; + return { + trace, + ...extractUiFindFromState(state), + }; +} + +export default withRouter( + connect( + mapStateToProps, + mapDispatchToProps + )(ReferencesButtonImpl) +); diff --git a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanBarRow.tsx b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanBarRow.tsx index f69c0f4eb8..920ae60aed 100644 --- a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanBarRow.tsx +++ b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanBarRow.tsx @@ -15,7 +15,7 @@ import * as React from 'react'; import IoAlert from 'react-icons/lib/io/alert'; import IoArrowRightA from 'react-icons/lib/io/arrow-right-a'; - +import ReferencesButton from './ReferencesButton'; import TimelineRow from './TimelineRow'; import { formatDuration, ViewedBoundsFunctionType } from './utils'; import SpanTreeOffset from './SpanTreeOffset'; @@ -150,6 +150,9 @@ export default class SpanBarRow extends React.PureComponent { {rpc ? rpc.operationName : operationName} + {span.references.length > 1 && ( + + )} Date: Wed, 13 Nov 2019 17:49:01 -0600 Subject: [PATCH 02/22] Focus without hide other childs Signed-off-by: Ruben Vargas --- .../TraceTimelineViewer/ReferencesButton.tsx | 8 +++---- .../TracePage/TraceTimelineViewer/duck.tsx | 21 +++++++++++++------ 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.tsx b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.tsx index e29b6fca71..466f90c72c 100644 --- a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.tsx +++ b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.tsx @@ -29,7 +29,7 @@ import { SpanReference, Trace } from '../../../types/trace'; import updateUiFind from '../../../utils/update-ui-find'; type TDispatchProps = { - focusUiFindMatches: (trace: Trace, uiFind: string | TNil) => void; + focusUiFindMatches: (trace: Trace, uiFind: string | TNil, preserveHiddenStatus?: boolean) => void; }; type TReduxProps = { @@ -48,7 +48,7 @@ type TOwnProps = { type TReferencesButtonProps = TDispatchProps & TReduxProps & TOwnProps; class ReferencesButtonImpl extends React.PureComponent { - focusUiFindMatches = (uiFind: string) => { + focusSpan = (uiFind: string) => { const { trace, focusUiFindMatches, location, history } = this.props; if (trace && trace.data) { updateUiFind({ @@ -56,7 +56,7 @@ class ReferencesButtonImpl extends React.PureComponent { history, uiFind, }); - focusUiFindMatches(trace.data, uiFind); + focusUiFindMatches(trace.data, uiFind, true); } }; @@ -64,7 +64,7 @@ class ReferencesButtonImpl extends React.PureComponent { {references.map(({ span, spanID }) => ( - this.focusUiFindMatches(spanID)}> + this.focusSpan(spanID)}> {span ? `${span.operationName} - ${spanID}` : spanID} diff --git a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/duck.tsx b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/duck.tsx index 528c2a282f..bed897f57a 100644 --- a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/duck.tsx +++ b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/duck.tsx @@ -27,7 +27,7 @@ import spanAncestorIds from '../../../utils/span-ancestor-ids'; export type TSpanIdLogValue = { logItem: Log; spanID: string }; export type TSpanIdValue = { spanID: string }; type TSpansValue = { spans: Span[] }; -type TTraceUiFindValue = { trace: Trace; uiFind: string | TNil }; +type TTraceUiFindValue = { trace: Trace; uiFind: string | TNil; preserveHiddenStatus?: boolean }; export type TWidthValue = { width: number }; export type TActionTypes = | TSpanIdLogValue @@ -91,7 +91,11 @@ const fullActions = createActions({ [actionTypes.DETAIL_WARNINGS_TOGGLE]: (spanID: string) => ({ spanID }), [actionTypes.DETAIL_TAGS_TOGGLE]: (spanID: string) => ({ spanID }), [actionTypes.DETAIL_TOGGLE]: (spanID: string) => ({ spanID }), - [actionTypes.FOCUS_UI_FIND_MATCHES]: (trace: Trace, uiFind: string | TNil) => ({ trace, uiFind }), + [actionTypes.FOCUS_UI_FIND_MATCHES]: ( + trace: Trace, + uiFind: string | TNil, + preserveHiddenStatus?: boolean + ) => ({ trace, uiFind, preserveHiddenStatus }), [actionTypes.REMOVE_HOVER_INDENT_GUIDE_ID]: (spanID: string) => ({ spanID }), [actionTypes.SET_SPAN_NAME_COLUMN_WIDTH]: (width: number) => ({ width }), [actionTypes.SET_TRACE]: (trace: Trace, uiFind: string | TNil) => ({ trace, uiFind }), @@ -99,7 +103,7 @@ const fullActions = createActions({ export const actions = (fullActions as any).jaegerUi.traceTimelineViewer as TTimelineViewerActions; -function calculateFocusedFindRowStates(uiFind: string, spans: Span[]) { +function calculateFocusedFindRowStates(uiFind: string, spans: Span[], preserveHiddenStatus: boolean = false) { const spansMap = new Map(); const childrenHiddenIDs: Set = new Set(); const detailStates: Map = new Map(); @@ -107,7 +111,9 @@ function calculateFocusedFindRowStates(uiFind: string, spans: Span[]) { spans.forEach(span => { spansMap.set(span.spanID, span); - childrenHiddenIDs.add(span.spanID); + if (!preserveHiddenStatus) { + childrenHiddenIDs.add(span.spanID); + } }); const matchedSpanIds = filterSpans(uiFind, spans); if (matchedSpanIds && matchedSpanIds.size) { @@ -125,11 +131,14 @@ function calculateFocusedFindRowStates(uiFind: string, spans: Span[]) { }; } -function focusUiFindMatches(state: TTraceTimeline, { uiFind, trace }: TTraceUiFindValue) { +function focusUiFindMatches( + state: TTraceTimeline, + { uiFind, trace, preserveHiddenStatus }: TTraceUiFindValue +) { if (!uiFind) return state; return { ...state, - ...calculateFocusedFindRowStates(uiFind, trace.spans), + ...calculateFocusedFindRowStates(uiFind, trace.spans, preserveHiddenStatus), }; } From 1f7bba1d357f7e82ee6d78a8dc89d9cced938795 Mon Sep 17 00:00:00 2001 From: Ruben Vargas Date: Wed, 13 Nov 2019 22:11:48 -0600 Subject: [PATCH 03/22] Improve ReferencesButton component Signed-off-by: Ruben Vargas --- .../TraceTimelineViewer/ReferencesButton.css | 1 + .../TraceTimelineViewer/ReferencesButton.tsx | 11 +++++------ .../TracePage/TraceTimelineViewer/SpanBarRow.tsx | 10 +++++++++- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.css b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.css index f3980a1cc1..b4aa84fdbb 100644 --- a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.css +++ b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.css @@ -16,4 +16,5 @@ limitations under the License. .multi-parent-button { padding: 0 5px; + color: #000; } diff --git a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.tsx b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.tsx index 466f90c72c..b8a55185e9 100644 --- a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.tsx +++ b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.tsx @@ -14,7 +14,6 @@ import React from 'react'; import { Dropdown, Menu, Tooltip } from 'antd'; -import IoNetwork from 'react-icons/lib/io/network'; import { bindActionCreators } from 'redux'; import { connect, Dispatch } from 'react-redux'; import { withRouter } from 'react-router-dom'; @@ -43,6 +42,8 @@ type TOwnProps = { history: RouterHistory; location: Location; match: any; + children?: React.ReactNode; + tooltipText: string; }; type TReferencesButtonProps = TDispatchProps & TReduxProps & TOwnProps; @@ -73,14 +74,12 @@ class ReferencesButtonImpl extends React.PureComponent { ); render() { - const { references } = this.props; + const { references, children, tooltipText } = this.props; return ( - + - - - + {children} ); diff --git a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanBarRow.tsx b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanBarRow.tsx index 920ae60aed..05cd456bbe 100644 --- a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanBarRow.tsx +++ b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanBarRow.tsx @@ -15,6 +15,8 @@ import * as React from 'react'; import IoAlert from 'react-icons/lib/io/alert'; import IoArrowRightA from 'react-icons/lib/io/arrow-right-a'; +import IoNetwork from 'react-icons/lib/io/network'; + import ReferencesButton from './ReferencesButton'; import TimelineRow from './TimelineRow'; import { formatDuration, ViewedBoundsFunctionType } from './utils'; @@ -151,7 +153,13 @@ export default class SpanBarRow extends React.PureComponent { {rpc ? rpc.operationName : operationName} {span.references.length > 1 && ( - + + + )} From 5bd6ddb8906acc100e809819b1b2388efae1edab Mon Sep 17 00:00:00 2001 From: Ruben Vargas Date: Wed, 13 Nov 2019 22:55:17 -0600 Subject: [PATCH 04/22] Add icon for spans refered by a multiparent span Signed-off-by: Ruben Vargas --- .../TraceTimelineViewer/ReferencesButton.tsx | 17 +++++++++++++---- .../TraceTimelineViewer/SpanBarRow.tsx | 11 ++++++++++- .../src/model/transform-trace-data.tsx | 12 +++++++++++- packages/jaeger-ui/src/types/trace.tsx | 1 + 4 files changed, 35 insertions(+), 6 deletions(-) diff --git a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.tsx b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.tsx index b8a55185e9..0190073713 100644 --- a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.tsx +++ b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.tsx @@ -75,12 +75,21 @@ class ReferencesButtonImpl extends React.PureComponent { render() { const { references, children, tooltipText } = this.props; - + if (references.length > 1) { + return ( + + + {children} + + + ); + } + const ref = references[0]; return ( - - {children} - + this.focusSpan(ref.spanID)}> + {children} + ); } diff --git a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanBarRow.tsx b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanBarRow.tsx index 05cd456bbe..938e3bb58f 100644 --- a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanBarRow.tsx +++ b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanBarRow.tsx @@ -16,7 +16,7 @@ import * as React from 'react'; import IoAlert from 'react-icons/lib/io/alert'; import IoArrowRightA from 'react-icons/lib/io/arrow-right-a'; import IoNetwork from 'react-icons/lib/io/network'; - +import IoIosArrowUp from 'react-icons/lib/io/ios-arrow-up'; import ReferencesButton from './ReferencesButton'; import TimelineRow from './TimelineRow'; import { formatDuration, ViewedBoundsFunctionType } from './utils'; @@ -161,6 +161,15 @@ export default class SpanBarRow extends React.PureComponent { )} + {span.referrals && span.referrals.length > 0 && ( + + + + )} { + const multiRef = span.references.length > 1; + span.references.forEach((ref, index) => { const refSpan = spanMap.get(ref.spanID) as Span; if (refSpan) { // eslint-disable-next-line no-param-reassign ref.span = refSpan; + if (multiRef && index > 0) { + refSpan.referrals = refSpan.referrals || []; + refSpan.referrals.push({ + spanID, + traceID, + span, + refType: ref.refType, + }); + } } }); spans.push(span); diff --git a/packages/jaeger-ui/src/types/trace.tsx b/packages/jaeger-ui/src/types/trace.tsx index c06b1f4933..4a299767f5 100644 --- a/packages/jaeger-ui/src/types/trace.tsx +++ b/packages/jaeger-ui/src/types/trace.tsx @@ -66,6 +66,7 @@ export type Span = SpanData & { tags: NonNullable; references: NonNullable; warnings: NonNullable; + referrals: Array; }; export type TraceData = { From 70442f689ce4776a3efda53c520c2a77abb21c52 Mon Sep 17 00:00:00 2001 From: Ruben Vargas Date: Thu, 14 Nov 2019 14:33:40 -0600 Subject: [PATCH 05/22] Fix tests Signed-off-by: Ruben Vargas --- .../src/components/TracePage/TraceTimelineViewer/SpanBarRow.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanBarRow.tsx b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanBarRow.tsx index 938e3bb58f..cc28c510b5 100644 --- a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanBarRow.tsx +++ b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanBarRow.tsx @@ -152,7 +152,7 @@ export default class SpanBarRow extends React.PureComponent { {rpc ? rpc.operationName : operationName} - {span.references.length > 1 && ( + {span.references && span.references.length > 1 && ( Date: Sat, 16 Nov 2019 12:58:45 -0600 Subject: [PATCH 06/22] Test ReferencesButton component Signed-off-by: Ruben Vargas --- .../ReferencesButton.test.js | 140 ++++++++++++++++++ .../TraceTimelineViewer/ReferencesButton.tsx | 8 +- .../ReferencesButton.test.js.snap | 19 +++ .../src/model/transform-trace-data.tsx | 4 +- 4 files changed, 166 insertions(+), 5 deletions(-) create mode 100644 packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.test.js create mode 100644 packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/__snapshots__/ReferencesButton.test.js.snap diff --git a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.test.js b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.test.js new file mode 100644 index 0000000000..ffecef253f --- /dev/null +++ b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.test.js @@ -0,0 +1,140 @@ +// Copyright (c) 2019 Uber Technologies, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import React from 'react'; +import { shallow, mount } from 'enzyme'; +import { Menu, Dropdown } from 'antd'; +import queryString from 'query-string'; + +import { UnconnectedReferencesButton, mapDispatchToProps, mapStateToProps } from './ReferencesButton'; +import updateUiFindSpy from '../../../utils/update-ui-find'; +import transformTraceData from '../../../model/transform-trace-data'; +import traceGenerator from '../../../demo/trace-generators'; + +jest.mock('../../../utils/update-ui-find'); + +describe('ReferencesButton', () => { + const trace = transformTraceData(traceGenerator.trace({ numberOfSpans: 10 })); + const focusMock = jest.fn(); + const oneReference = trace.spans[1].references; + const moreReferences = oneReference.slice(); + moreReferences.push({ + refType: 'CHILD_OF', + traceID: trace.traceID, + spanID: trace.spans[2].spanID, + }); + const baseProps = { + uiFind: null, + history: { + replace: () => {}, + }, + location: { + search: null, + }, + traceID: 'trace1', + trace: { + data: trace, + }, + focusUiFindMatches: focusMock, + }; + describe('rendering', () => { + it('rendering as expected', () => { + const props = { ...baseProps, references: oneReference }; + const wrapper = shallow(); + expect(wrapper).toMatchSnapshot(); + }); + + it('render with dropdown', () => { + const props = { ...baseProps, references: moreReferences }; + const wrapper = shallow(); + const dropdown = wrapper.find(Dropdown); + expect(dropdown.length).toBe(1); + const menuInstance = shallow(dropdown.first().props().overlay); + const submenuItems = menuInstance.find(Menu.Item); + expect(submenuItems.length).toBe(2); + }); + }); + + describe('navigate to reference', () => { + beforeEach(() => { + focusMock.mockReset(); + }); + + it('calls updateUiFind and focusUiFindMatches with correct kwargs', () => { + const props = { ...baseProps, references: oneReference }; + const wrapper = shallow(); + wrapper.find('a').simulate('click'); + expect(updateUiFindSpy).toHaveBeenLastCalledWith({ + history: props.history, + location: props.location, + uiFind: trace.spans[1].references[0].spanID, + }); + expect(focusMock).toHaveBeenLastCalledWith(trace, trace.spans[1].references[0].spanID, true); + }); + + it('calls updateUiFind and focusUiFindMatches with correct kwargs on dropdown', () => { + const props = { ...baseProps, references: moreReferences }; + const wrapper = mount(); + const dropdown = wrapper.find(Dropdown); + dropdown.find('.multi-parent-button').simulate('click'); + const menuInstance = shallow(dropdown.first().props().overlay); + const submenuItems = menuInstance.find(Menu.Item); + submenuItems + .at(0) + .find('a') + .simulate('click'); + expect(focusMock).toHaveBeenLastCalledWith(trace, trace.spans[1].references[0].spanID, true); + }); + }); + + describe('mapDispatchToProps()', () => { + it('creates the actions correctly', () => { + expect(mapDispatchToProps(() => {})).toEqual({ + focusUiFindMatches: expect.any(Function), + }); + }); + }); + + describe('mapStateToProps()', () => { + const queryStringParseSpy = jest.spyOn(queryString, 'parse'); + const uiFind = 'span1'; + + beforeEach(() => { + queryStringParseSpy.mockReturnValue({ uiFind }); + }); + + it('maps state to props correctly', () => { + const state = { + router: { + location: { + search: uiFind, + }, + }, + trace: { + traces: { + [trace.traceID]: trace, + }, + }, + }; + const mappedProps = mapStateToProps(state, { + traceID: trace.traceID, + }); + + expect(mappedProps).toEqual({ + trace, + uiFind: 'span1', + }); + }); + }); +}); diff --git a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.tsx b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.tsx index 0190073713..be5bcf611a 100644 --- a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.tsx +++ b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.tsx @@ -48,7 +48,8 @@ type TOwnProps = { type TReferencesButtonProps = TDispatchProps & TReduxProps & TOwnProps; -class ReferencesButtonImpl extends React.PureComponent { +// export for tests +export class UnconnectedReferencesButton extends React.PureComponent { focusSpan = (uiFind: string) => { const { trace, focusUiFindMatches, location, history } = this.props; if (trace && trace.data) { @@ -65,7 +66,7 @@ class ReferencesButtonImpl extends React.PureComponent { {references.map(({ span, spanID }) => ( - this.focusSpan(spanID)}> + this.focusSpan(spanID)} className="reference-option"> {span ? `${span.operationName} - ${spanID}` : spanID} @@ -95,6 +96,7 @@ class ReferencesButtonImpl extends React.PureComponent { } } +// export for tests export function mapDispatchToProps(dispatch: Dispatch): TDispatchProps { const { focusUiFindMatches } = bindActionCreators(timelineActions, dispatch); return { focusUiFindMatches }; @@ -114,5 +116,5 @@ export default withRouter( connect( mapStateToProps, mapDispatchToProps - )(ReferencesButtonImpl) + )(UnconnectedReferencesButton) ); diff --git a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/__snapshots__/ReferencesButton.test.js.snap b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/__snapshots__/ReferencesButton.test.js.snap new file mode 100644 index 0000000000..d4f4e611ba --- /dev/null +++ b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/__snapshots__/ReferencesButton.test.js.snap @@ -0,0 +1,19 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`ReferencesButton rendering rendering as expected 1`] = ` + + + +`; diff --git a/packages/jaeger-ui/src/model/transform-trace-data.tsx b/packages/jaeger-ui/src/model/transform-trace-data.tsx index e254ef0356..00a27ea6be 100644 --- a/packages/jaeger-ui/src/model/transform-trace-data.tsx +++ b/packages/jaeger-ui/src/model/transform-trace-data.tsx @@ -111,13 +111,13 @@ export default function transformTraceData(data: TraceData & { spans: SpanData[] const tagsInfo = deduplicateTags(span.tags); span.tags = tagsInfo.tags; span.warnings = span.warnings.concat(tagsInfo.warnings); - const multiRef = span.references.length > 1; span.references.forEach((ref, index) => { const refSpan = spanMap.get(ref.spanID) as Span; if (refSpan) { // eslint-disable-next-line no-param-reassign ref.span = refSpan; - if (multiRef && index > 0) { + if (index > 0) { + // Don't take into account the parent, just other references. refSpan.referrals = refSpan.referrals || []; refSpan.referrals.push({ spanID, From 488b2c3735a2eca32cb69f6caefedaec847d17eb Mon Sep 17 00:00:00 2001 From: Ruben Vargas Date: Sat, 16 Nov 2019 17:49:33 -0600 Subject: [PATCH 07/22] Test span multiple reference transform Signed-off-by: Ruben Vargas --- .../jaeger-ui/src/demo/trace-generators.js | 18 +++++++++------- packages/jaeger-ui/src/reducers/trace.test.js | 21 +++++++++++++++++++ 2 files changed, 31 insertions(+), 8 deletions(-) diff --git a/packages/jaeger-ui/src/demo/trace-generators.js b/packages/jaeger-ui/src/demo/trace-generators.js index c384163be6..5cd1782ca5 100644 --- a/packages/jaeger-ui/src/demo/trace-generators.js +++ b/packages/jaeger-ui/src/demo/trace-generators.js @@ -49,18 +49,18 @@ function getParentSpanId(span, levels) { } /* this simulates the hierarchy created by CHILD_OF tags */ -function attachReferences(spans) { - const depth = chance.integer({ min: 1, max: 10 }); +function attachReferences(spans, depth, spansPerLevel) { let levels = [[getSpanId(spans[0])]]; - const duplicateLevelFilter = currentLevels => spanID => - !currentLevels.find(level => level.indexOf(spanID) >= 0); + const duplicateLevelFilter = currentLevels => span => + !currentLevels.find(level => level.indexOf(span.spanID) >= 0); while (levels.length < depth) { + const remainingSpans = spans.filter(duplicateLevelFilter(levels)); + if (remainingSpans.length <= 0) break; const newLevel = chance - .pickset(spans, chance.integer({ min: 4, max: 8 })) - .map(getSpanId) - .filter(duplicateLevelFilter(levels)); + .pickset(remainingSpans, spansPerLevel || chance.integer({ min: 4, max: 8 })) + .map(getSpanId); levels.push(newLevel); } @@ -95,6 +95,8 @@ export default chance.mixin({ Math.ceil(chance.normal({ mean: 45, dev: 15 })) + 1, ]), numberOfProcesses = chance.integer({ min: 1, max: 10 }), + maxDepth = chance.integer({ min: 1, max: 10 }), + spansPerLevel = null, }) { const traceID = chance.guid(); const duration = chance.integer({ min: 10000, max: 5000000 }); @@ -109,7 +111,7 @@ export default chance.mixin({ traceStartTime: timestamp, traceEndTime: timestamp + duration, }); - spans = attachReferences(spans); + spans = attachReferences(spans, maxDepth, spansPerLevel); if (spans.length > 1) { spans = setupParentSpan(spans, { startTime: timestamp, duration }); } diff --git a/packages/jaeger-ui/src/reducers/trace.test.js b/packages/jaeger-ui/src/reducers/trace.test.js index 8e4135d79c..b481933bc6 100644 --- a/packages/jaeger-ui/src/reducers/trace.test.js +++ b/packages/jaeger-ui/src/reducers/trace.test.js @@ -113,6 +113,27 @@ describe('fetch multiple traces', () => { }; expect(state.traces).toEqual(outcome); }); + + it('process multiple references', () => { + const multiRefTrace = traceGenerator.trace({ numberOfSpans: 6, maxDepth: 3, spansPerLevel: 4 }); + const parentID = multiRefTrace.spans[0].spanID; + const traceID = multiRefTrace.spans[0].traceID; + const noSiblingSpan = multiRefTrace.spans.filter( + span => span.references.length > 0 && span.references[0].spanID !== parentID + ); + const firstLevel = multiRefTrace.spans.filter( + span => span.references.length > 0 && span.references[0].spanID === parentID + ); + noSiblingSpan[0].references.push({ + refType: 'CHILD_OF', + traceID, + spanID: firstLevel[0].spanID, + }); + const tTrace = transformTraceData(multiRefTrace); + const multiRef = tTrace.spans.filter(span => span.referrals && span.referrals.length > 0); + expect(multiRef.length).toEqual(1); + expect(multiRef[0].spanID).toEqual(firstLevel[0].spanID); + }); }); it('handles a failed request', () => { From 25c6bc9fe6ac4a227f03e6bb40ef3547b0435b91 Mon Sep 17 00:00:00 2001 From: Ruben Vargas Date: Sun, 17 Nov 2019 00:14:10 -0600 Subject: [PATCH 08/22] Link to external references in other traces Signed-off-by: Ruben Vargas --- .../ReferencesButton.test.js | 31 +++++++++++- .../TraceTimelineViewer/ReferencesButton.tsx | 50 ++++++++++++++----- .../ReferencesButton.test.js.snap | 19 +++++++ 3 files changed, 87 insertions(+), 13 deletions(-) diff --git a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.test.js b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.test.js index ffecef253f..cf7a92c5c3 100644 --- a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.test.js +++ b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.test.js @@ -21,6 +21,7 @@ import { UnconnectedReferencesButton, mapDispatchToProps, mapStateToProps } from import updateUiFindSpy from '../../../utils/update-ui-find'; import transformTraceData from '../../../model/transform-trace-data'; import traceGenerator from '../../../demo/trace-generators'; +import NewWindowIcon from '../../common/NewWindowIcon'; jest.mock('../../../utils/update-ui-find'); @@ -28,6 +29,7 @@ describe('ReferencesButton', () => { const trace = transformTraceData(traceGenerator.trace({ numberOfSpans: 10 })); const focusMock = jest.fn(); const oneReference = trace.spans[1].references; + const moreReferences = oneReference.slice(); moreReferences.push({ refType: 'CHILD_OF', @@ -42,7 +44,7 @@ describe('ReferencesButton', () => { location: { search: null, }, - traceID: 'trace1', + traceID: trace.traceID, trace: { data: trace, }, @@ -55,6 +57,16 @@ describe('ReferencesButton', () => { expect(wrapper).toMatchSnapshot(); }); + it('rendering as with external reference', () => { + const oneExternal = [{ ...oneReference[0] }]; + oneExternal[0].traceID = 'extTrace'; + oneExternal[0].spanID = 'extSpanID'; + + const props = { ...baseProps, references: oneExternal }; + const wrapper = shallow(); + expect(wrapper).toMatchSnapshot(); + }); + it('render with dropdown', () => { const props = { ...baseProps, references: moreReferences }; const wrapper = shallow(); @@ -64,6 +76,23 @@ describe('ReferencesButton', () => { const submenuItems = menuInstance.find(Menu.Item); expect(submenuItems.length).toBe(2); }); + + it('render with dropdown and mix of external and internal', () => { + const mixRef = oneReference.slice(); + const oneExternal = { ...oneReference[0] }; + oneExternal.traceID = 'extTrace'; + oneExternal.spanID = 'extSpanID'; + mixRef.push(oneExternal); + const props = { ...baseProps, references: mixRef }; + const wrapper = shallow(); + const dropdown = wrapper.find(Dropdown); + expect(dropdown.length).toBe(1); + const menuInstance = shallow(dropdown.first().props().overlay); + const submenuItems = menuInstance.find(Menu.Item); + expect(submenuItems.length).toBe(2); + expect(submenuItems.at(1).find('a[href="/trace/extTrace/uiFind?=extSpanID"]').length).toBe(1); + expect(submenuItems.at(1).find(NewWindowIcon).length).toBe(1); + }); }); describe('navigate to reference', () => { diff --git a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.tsx b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.tsx index be5bcf611a..1a6e56b29e 100644 --- a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.tsx +++ b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.tsx @@ -19,13 +19,16 @@ import { connect, Dispatch } from 'react-redux'; import { withRouter } from 'react-router-dom'; import { History as RouterHistory, Location } from 'history'; -import './ReferencesButton.css'; +import NewWindowIcon from '../../common/NewWindowIcon'; +import updateUiFind from '../../../utils/update-ui-find'; +import { getUrl } from '../url'; import { FetchedTrace, ReduxState, TNil } from '../../../types'; import { actions as timelineActions } from './duck'; import { extractUiFindFromState } from '../../common/UiFindInput'; import { SpanReference, Trace } from '../../../types/trace'; -import updateUiFind from '../../../utils/update-ui-find'; + +import './ReferencesButton.css'; type TDispatchProps = { focusUiFindMatches: (trace: Trace, uiFind: string | TNil, preserveHiddenStatus?: boolean) => void; @@ -48,6 +51,8 @@ type TOwnProps = { type TReferencesButtonProps = TDispatchProps & TReduxProps & TOwnProps; +const linkToExternalSpan = (traceID: string, spanID: string) => `${getUrl(traceID)}/uiFind?=${spanID}`; + // export for tests export class UnconnectedReferencesButton extends React.PureComponent { focusSpan = (uiFind: string) => { @@ -62,15 +67,38 @@ export class UnconnectedReferencesButton extends React.PureComponent { + if (traceID === reference.traceID) { + return ( + this.focusSpan(reference.spanID)} className={className}> + {children} + + ); + } + return ( + + {children} + + ); + }; + referencesList = (references: SpanReference[]) => ( - {references.map(({ span, spanID }) => ( - - this.focusSpan(spanID)} className="reference-option"> - {span ? `${span.operationName} - ${spanID}` : spanID} - - - ))} + {references.map(ref => { + const { span, traceID, spanID } = ref; + const child = ( + + {span ? `${span.operationName} - ${ref.spanID}` : ref.spanID} + {traceID !== this.props.traceID && } + + ); + return {this.spanLink(ref, this.props.traceID, child)}; + })} ); @@ -88,9 +116,7 @@ export class UnconnectedReferencesButton extends React.PureComponent - this.focusSpan(ref.spanID)}> - {children} - + {this.spanLink(ref, this.props.traceID, children, 'multi-parent-button')} ); } diff --git a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/__snapshots__/ReferencesButton.test.js.snap b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/__snapshots__/ReferencesButton.test.js.snap index d4f4e611ba..7ac04b3e32 100644 --- a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/__snapshots__/ReferencesButton.test.js.snap +++ b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/__snapshots__/ReferencesButton.test.js.snap @@ -17,3 +17,22 @@ exports[`ReferencesButton rendering rendering as expected 1`] = ` /> `; + +exports[`ReferencesButton rendering rendering as with external reference 1`] = ` + + + +`; From 4952cc476f92db4c4563aa6865cd838f2962c86b Mon Sep 17 00:00:00 2001 From: Ruben Vargas Date: Tue, 19 Nov 2019 13:11:33 -0600 Subject: [PATCH 09/22] Change reference link text Signed-off-by: Ruben Vargas --- .../TraceTimelineViewer/ReferencesButton.css | 9 +++++++ .../TraceTimelineViewer/ReferencesButton.tsx | 26 ++++++++++++++++--- .../TraceTimelineViewer/SpanBarRow.tsx | 2 +- 3 files changed, 32 insertions(+), 5 deletions(-) diff --git a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.css b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.css index b4aa84fdbb..9118bad5e3 100644 --- a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.css +++ b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.css @@ -18,3 +18,12 @@ limitations under the License. padding: 0 5px; color: #000; } + +.external-trace-ref { + float: right; + margin-left: 5px; +} + +.ref-tooltip { + max-width: none; +} diff --git a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.tsx b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.tsx index 1a6e56b29e..04fe6a73a5 100644 --- a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.tsx +++ b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.tsx @@ -93,8 +93,14 @@ export class UnconnectedReferencesButton extends React.PureComponent - {span ? `${span.operationName} - ${ref.spanID}` : ref.spanID} - {traceID !== this.props.traceID && } + {span + ? `${span.process.serviceName}:${span.operationName} - ${ref.spanID}` + : `(another trace) - ${ref.spanID}`} + {traceID !== this.props.traceID && ( +
+ +
+ )} ); return {this.spanLink(ref, this.props.traceID, child)}; @@ -106,7 +112,13 @@ export class UnconnectedReferencesButton extends React.PureComponent 1) { return ( - +
{children} @@ -115,7 +127,13 @@ export class UnconnectedReferencesButton extends React.PureComponent + {this.spanLink(ref, this.props.traceID, children, 'multi-parent-button')} ); diff --git a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanBarRow.tsx b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanBarRow.tsx index cc28c510b5..23841354c3 100644 --- a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanBarRow.tsx +++ b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanBarRow.tsx @@ -165,7 +165,7 @@ export default class SpanBarRow extends React.PureComponent { From 52cc0e725e5520ee28364d509980dc5cd01a2cfe Mon Sep 17 00:00:00 2001 From: Ruben Vargas Date: Tue, 19 Nov 2019 20:54:38 -0600 Subject: [PATCH 10/22] References accordion in span details Signed-off-by: Ruben Vargas --- .../SpanDetail/AccordianReferences.css | 22 +++ .../SpanDetail/AccordianReferences.tsx | 160 ++++++++++++++++++ .../SpanDetail/DetailState.tsx | 17 +- .../TraceTimelineViewer/SpanDetail/index.tsx | 28 ++- .../TraceTimelineViewer/SpanDetailRow.tsx | 3 + .../VirtualizedTraceView.tsx | 3 + .../TracePage/TraceTimelineViewer/duck.tsx | 8 +- 7 files changed, 236 insertions(+), 5 deletions(-) create mode 100644 packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/AccordianReferences.css create mode 100644 packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/AccordianReferences.tsx diff --git a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/AccordianReferences.css b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/AccordianReferences.css new file mode 100644 index 0000000000..18c29f9135 --- /dev/null +++ b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/AccordianReferences.css @@ -0,0 +1,22 @@ +.ReferencesList--List { + width: 100%; + list-style: none; + padding: 0; + margin: 0; + background: #fff; +} +.ReferencesList { + background: #fff; + border: 1px solid #ddd; + margin-bottom: 0.7em; + max-height: 450px; + overflow: auto; +} + +.ReferencesList--Item { + padding: 0.25rem 0.5rem; +} + +.ReferencesList--Item:nth-child(2n) { + background: #f5f5f5; +} diff --git a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/AccordianReferences.tsx b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/AccordianReferences.tsx new file mode 100644 index 0000000000..5d823fa7f0 --- /dev/null +++ b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/AccordianReferences.tsx @@ -0,0 +1,160 @@ +// Copyright (c) 2019 Uber Technologies, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import * as React from 'react'; +import cx from 'classnames'; +import IoIosArrowDown from 'react-icons/lib/io/ios-arrow-down'; +import IoIosArrowRight from 'react-icons/lib/io/ios-arrow-right'; +import { FetchedTrace, ReduxState, TNil } from '../../../../types'; + +import './AccordianReferences.css'; +import { SpanReference, Trace } from '../../../../types/trace'; +import updateUiFind from '../../../../utils/update-ui-find'; +import { connect, Dispatch } from 'react-redux'; +import { bindActionCreators } from 'redux'; +import { actions as timelineActions } from '../duck'; +import { extractUiFindFromState } from '../../../common/UiFindInput'; +import { RouteComponentProps, withRouter } from 'react-router-dom'; + +type TOwnProps = { + className?: string | TNil; + data: SpanReference[]; + headerClassName?: string | TNil; + highContrast?: boolean; + interactive?: boolean; + isOpen: boolean; + label: React.ReactNode; + onToggle?: null | (() => void); + traceID: string; +}; + +type TDispatchProps = { + focusUiFindMatches: (trace: Trace, uiFind: string | TNil, preserveHiddenStatus?: boolean) => void; +}; + +type TReduxProps = { + uiFind: string | TNil; + trace: FetchedTrace | TNil; +}; + +type AccordianReferencesProps = TOwnProps & TDispatchProps & TReduxProps & RouteComponentProps; + +type ReferenceItemProps = { + data: SpanReference[]; + focusSpan: (spanID: string) => void; +}; + +function References(props: ReferenceItemProps) { + const { data, focusSpan } = props; + return ( +
+ +
+ ); +} + +export class UnconnectedAccordianReferences extends React.PureComponent { + static defaultProps = { + className: null, + highContrast: false, + interactive: true, + onToggle: null, + }; + + focusSpan = (uiFind: string) => { + const { trace, focusUiFindMatches, location, history } = this.props; + if (trace && trace.data) { + updateUiFind({ + location, + history, + uiFind, + }); + focusUiFindMatches(trace.data, uiFind, true); + } + }; + + render() { + const { + className, + data, + headerClassName, + highContrast, + interactive, + isOpen, + label, + onToggle, + } = this.props; + const isEmpty = !Array.isArray(data) || !data.length; + const iconCls = cx('u-align-icon', { 'AccordianKReferences--emptyIcon': isEmpty }); + let arrow: React.ReactNode | null = null; + let headerProps: Object | null = null; + if (interactive) { + arrow = isOpen ? : ; + headerProps = { + 'aria-checked': isOpen, + onClick: isEmpty ? null : onToggle, + role: 'switch', + }; + } + return ( +
+
+ {arrow} + {label} ({data.length}) +
+ {isOpen && } +
+ ); + } +} + +// export for tests +export function mapDispatchToProps(dispatch: Dispatch): TDispatchProps { + const { focusUiFindMatches } = bindActionCreators(timelineActions, dispatch); + return { focusUiFindMatches }; +} + +// export for tests +export function mapStateToProps(state: ReduxState, ownProps: TOwnProps): TReduxProps { + const { traces } = state.trace; + const trace = ownProps.traceID ? traces[ownProps.traceID] : null; + return { + trace, + ...extractUiFindFromState(state), + }; +} + +export default withRouter( + connect( + mapStateToProps, + mapDispatchToProps + )(UnconnectedAccordianReferences) +); diff --git a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/DetailState.tsx b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/DetailState.tsx index ed822aea1d..3e856dbd01 100644 --- a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/DetailState.tsx +++ b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/DetailState.tsx @@ -22,12 +22,19 @@ export default class DetailState { isProcessOpen: boolean; logs: { isOpen: boolean; openedItems: Set }; isWarningsOpen: boolean; + isReferencesOpen: boolean; constructor(oldState?: DetailState) { - const { isTagsOpen, isProcessOpen, isWarningsOpen, logs }: DetailState | Record = - oldState || {}; + const { + isTagsOpen, + isProcessOpen, + isReferencesOpen, + isWarningsOpen, + logs, + }: DetailState | Record = oldState || {}; this.isTagsOpen = Boolean(isTagsOpen); this.isProcessOpen = Boolean(isProcessOpen); + this.isReferencesOpen = Boolean(isReferencesOpen); this.isWarningsOpen = Boolean(isWarningsOpen); this.logs = { isOpen: Boolean(logs && logs.isOpen), @@ -47,6 +54,12 @@ export default class DetailState { return next; } + toggleReferences() { + const next = new DetailState(this); + next.isReferencesOpen = !this.isReferencesOpen; + return next; + } + toggleWarnings() { const next = new DetailState(this); next.isWarningsOpen = !this.isWarningsOpen; diff --git a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/index.tsx b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/index.tsx index 19d92dd261..f603bbbfed 100644 --- a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/index.tsx +++ b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/index.tsx @@ -27,6 +27,7 @@ import { TNil } from '../../../../types'; import { KeyValuePair, Link, Log, Span } from '../../../../types/trace'; import './index.css'; +import AccordianReferences from './AccordianReferences'; type SpanDetailProps = { detailState: DetailState; @@ -38,6 +39,7 @@ type SpanDetailProps = { tagsToggle: (spanID: string) => void; traceStartTime: number; warningsToggle: (spanID: string) => void; + referencesToggle: (spanID: string) => void; }; export default function SpanDetail(props: SpanDetailProps) { @@ -51,9 +53,20 @@ export default function SpanDetail(props: SpanDetailProps) { tagsToggle, traceStartTime, warningsToggle, + referencesToggle, } = props; - const { isTagsOpen, isProcessOpen, logs: logsState, isWarningsOpen } = detailState; - const { operationName, process, duration, relativeStartTime, spanID, logs, tags, warnings } = span; + const { isTagsOpen, isProcessOpen, logs: logsState, isWarningsOpen, isReferencesOpen } = detailState; + const { + operationName, + process, + duration, + relativeStartTime, + spanID, + logs, + tags, + warnings, + references, + } = span; const overviewItems = [ { key: 'svc', @@ -125,6 +138,17 @@ export default function SpanDetail(props: SpanDetailProps) { onToggle={() => warningsToggle(spanID)} /> )} + {references && references.length > 1 && ( + References} + data={references} + isOpen={isReferencesOpen} + onToggle={() => referencesToggle(spanID)} + traceID={span.traceID} + /> + )} {spanID} void; logsToggle: (spanID: string) => void; processToggle: (spanID: string) => void; + referencesToggle: (spanID: string) => void; warningsToggle: (spanID: string) => void; span: Span; tagsToggle: (spanID: string) => void; @@ -56,6 +57,7 @@ export default class SpanDetailRow extends React.PureComponent void; detailLogsToggle: (spanID: string) => void; detailWarningsToggle: (spanID: string) => void; + detailReferencesToggle: (spanID: string) => void; detailProcessToggle: (spanID: string) => void; detailTagsToggle: (spanID: string) => void; detailToggle: (spanID: string) => void; @@ -372,6 +373,7 @@ export class VirtualizedTraceViewImpl extends React.Component({ [actionTypes.EXPAND_ONE]: (spans: Span[]) => ({ spans }), [actionTypes.DETAIL_PROCESS_TOGGLE]: (spanID: string) => ({ spanID }), [actionTypes.DETAIL_WARNINGS_TOGGLE]: (spanID: string) => ({ spanID }), + [actionTypes.DETAIL_REFERENCES_TOGGLE]: (spanID: string) => ({ spanID }), [actionTypes.DETAIL_TAGS_TOGGLE]: (spanID: string) => ({ spanID }), [actionTypes.DETAIL_TOGGLE]: (spanID: string) => ({ spanID }), [actionTypes.FOCUS_UI_FIND_MATCHES]: ( @@ -248,7 +250,7 @@ function detailToggle(state: TTraceTimeline, { spanID }: TSpanIdValue) { } function detailSubsectionToggle( - subSection: 'tags' | 'process' | 'logs' | 'warnings', + subSection: 'tags' | 'process' | 'logs' | 'warnings' | 'references', state: TTraceTimeline, { spanID }: TSpanIdValue ) { @@ -263,6 +265,8 @@ function detailSubsectionToggle( detailState = old.toggleProcess(); } else if (subSection === 'warnings') { detailState = old.toggleWarnings(); + } else if (subSection === 'references') { + detailState = old.toggleReferences(); } else { detailState = old.toggleLogs(); } @@ -275,6 +279,7 @@ const detailTagsToggle = detailSubsectionToggle.bind(null, 'tags'); const detailProcessToggle = detailSubsectionToggle.bind(null, 'process'); const detailLogsToggle = detailSubsectionToggle.bind(null, 'logs'); const detailWarningsToggle = detailSubsectionToggle.bind(null, 'warnings'); +const detailReferencesToggle = detailSubsectionToggle.bind(null, 'references'); function detailLogItemToggle(state: TTraceTimeline, { spanID, logItem }: TSpanIdLogValue) { const old = state.detailStates.get(spanID); @@ -314,6 +319,7 @@ export default handleActions( [actionTypes.DETAIL_LOG_ITEM_TOGGLE]: guardReducer(detailLogItemToggle), [actionTypes.DETAIL_PROCESS_TOGGLE]: guardReducer(detailProcessToggle), [actionTypes.DETAIL_WARNINGS_TOGGLE]: guardReducer(detailWarningsToggle), + [actionTypes.DETAIL_REFERENCES_TOGGLE]: guardReducer(detailReferencesToggle), [actionTypes.DETAIL_TAGS_TOGGLE]: guardReducer(detailTagsToggle), [actionTypes.DETAIL_TOGGLE]: guardReducer(detailToggle), [actionTypes.EXPAND_ALL]: guardReducer(expandAll), From 8426a714efff8c3d71a48e3ab90a473bae0fb1ed Mon Sep 17 00:00:00 2001 From: Ruben Vargas Date: Tue, 19 Nov 2019 23:55:20 -0600 Subject: [PATCH 11/22] Change focusSpan function so it can be reused by accordion and ref button Signed-off-by: Ruben Vargas --- .../ReferencesButton.test.js | 69 ++-------- .../TraceTimelineViewer/ReferencesButton.tsx | 69 ++-------- .../TraceTimelineViewer/SpanBarRow.tsx | 4 + .../SpanDetail/AccordianReferences.css | 16 +++ .../SpanDetail/AccordianReferences.test.js | 119 ++++++++++++++++++ .../SpanDetail/AccordianReferences.tsx | 69 ++-------- .../SpanDetail/index.test.js | 51 ++++++++ .../TraceTimelineViewer/SpanDetail/index.tsx | 3 + .../TraceTimelineViewer/SpanDetailRow.tsx | 3 + .../VirtualizedTraceView.test.js | 22 ++++ .../VirtualizedTraceView.tsx | 16 +++ .../ReferencesButton.test.js.snap | 6 +- .../TraceTimelineViewer/duck.test.js | 7 ++ 13 files changed, 272 insertions(+), 182 deletions(-) create mode 100644 packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/AccordianReferences.test.js diff --git a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.test.js b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.test.js index cf7a92c5c3..1a331c914d 100644 --- a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.test.js +++ b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.test.js @@ -15,16 +15,12 @@ import React from 'react'; import { shallow, mount } from 'enzyme'; import { Menu, Dropdown } from 'antd'; -import queryString from 'query-string'; -import { UnconnectedReferencesButton, mapDispatchToProps, mapStateToProps } from './ReferencesButton'; -import updateUiFindSpy from '../../../utils/update-ui-find'; +import ReferencesButton from './ReferencesButton'; import transformTraceData from '../../../model/transform-trace-data'; import traceGenerator from '../../../demo/trace-generators'; import NewWindowIcon from '../../common/NewWindowIcon'; -jest.mock('../../../utils/update-ui-find'); - describe('ReferencesButton', () => { const trace = transformTraceData(traceGenerator.trace({ numberOfSpans: 10 })); const focusMock = jest.fn(); @@ -48,12 +44,12 @@ describe('ReferencesButton', () => { trace: { data: trace, }, - focusUiFindMatches: focusMock, + focusSpan: focusMock, }; describe('rendering', () => { it('rendering as expected', () => { const props = { ...baseProps, references: oneReference }; - const wrapper = shallow(); + const wrapper = shallow(); expect(wrapper).toMatchSnapshot(); }); @@ -63,13 +59,13 @@ describe('ReferencesButton', () => { oneExternal[0].spanID = 'extSpanID'; const props = { ...baseProps, references: oneExternal }; - const wrapper = shallow(); + const wrapper = shallow(); expect(wrapper).toMatchSnapshot(); }); it('render with dropdown', () => { const props = { ...baseProps, references: moreReferences }; - const wrapper = shallow(); + const wrapper = shallow(); const dropdown = wrapper.find(Dropdown); expect(dropdown.length).toBe(1); const menuInstance = shallow(dropdown.first().props().overlay); @@ -84,7 +80,7 @@ describe('ReferencesButton', () => { oneExternal.spanID = 'extSpanID'; mixRef.push(oneExternal); const props = { ...baseProps, references: mixRef }; - const wrapper = shallow(); + const wrapper = shallow(); const dropdown = wrapper.find(Dropdown); expect(dropdown.length).toBe(1); const menuInstance = shallow(dropdown.first().props().overlay); @@ -102,19 +98,14 @@ describe('ReferencesButton', () => { it('calls updateUiFind and focusUiFindMatches with correct kwargs', () => { const props = { ...baseProps, references: oneReference }; - const wrapper = shallow(); + const wrapper = shallow(); wrapper.find('a').simulate('click'); - expect(updateUiFindSpy).toHaveBeenLastCalledWith({ - history: props.history, - location: props.location, - uiFind: trace.spans[1].references[0].spanID, - }); - expect(focusMock).toHaveBeenLastCalledWith(trace, trace.spans[1].references[0].spanID, true); + expect(focusMock).toHaveBeenLastCalledWith(trace.spans[1].references[0].spanID); }); it('calls updateUiFind and focusUiFindMatches with correct kwargs on dropdown', () => { const props = { ...baseProps, references: moreReferences }; - const wrapper = mount(); + const wrapper = mount(); const dropdown = wrapper.find(Dropdown); dropdown.find('.multi-parent-button').simulate('click'); const menuInstance = shallow(dropdown.first().props().overlay); @@ -123,47 +114,7 @@ describe('ReferencesButton', () => { .at(0) .find('a') .simulate('click'); - expect(focusMock).toHaveBeenLastCalledWith(trace, trace.spans[1].references[0].spanID, true); - }); - }); - - describe('mapDispatchToProps()', () => { - it('creates the actions correctly', () => { - expect(mapDispatchToProps(() => {})).toEqual({ - focusUiFindMatches: expect.any(Function), - }); - }); - }); - - describe('mapStateToProps()', () => { - const queryStringParseSpy = jest.spyOn(queryString, 'parse'); - const uiFind = 'span1'; - - beforeEach(() => { - queryStringParseSpy.mockReturnValue({ uiFind }); - }); - - it('maps state to props correctly', () => { - const state = { - router: { - location: { - search: uiFind, - }, - }, - trace: { - traces: { - [trace.traceID]: trace, - }, - }, - }; - const mappedProps = mapStateToProps(state, { - traceID: trace.traceID, - }); - - expect(mappedProps).toEqual({ - trace, - uiFind: 'span1', - }); + expect(focusMock).toHaveBeenLastCalledWith(trace.spans[1].references[0].spanID); }); }); }); diff --git a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.tsx b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.tsx index 04fe6a73a5..c45a75d1b8 100644 --- a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.tsx +++ b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.tsx @@ -14,63 +14,33 @@ import React from 'react'; import { Dropdown, Menu, Tooltip } from 'antd'; -import { bindActionCreators } from 'redux'; -import { connect, Dispatch } from 'react-redux'; -import { withRouter } from 'react-router-dom'; -import { History as RouterHistory, Location } from 'history'; - import NewWindowIcon from '../../common/NewWindowIcon'; -import updateUiFind from '../../../utils/update-ui-find'; import { getUrl } from '../url'; -import { FetchedTrace, ReduxState, TNil } from '../../../types'; -import { actions as timelineActions } from './duck'; -import { extractUiFindFromState } from '../../common/UiFindInput'; -import { SpanReference, Trace } from '../../../types/trace'; +import { SpanReference } from '../../../types/trace'; import './ReferencesButton.css'; -type TDispatchProps = { - focusUiFindMatches: (trace: Trace, uiFind: string | TNil, preserveHiddenStatus?: boolean) => void; -}; - -type TReduxProps = { - uiFind: string | TNil; - trace: FetchedTrace | TNil; -}; - -type TOwnProps = { +type TReferencesButtonProps = { references: SpanReference[]; traceID: string; - history: RouterHistory; - location: Location; - match: any; children?: React.ReactNode; tooltipText: string; + focusSpan: (spanID: string) => void; }; -type TReferencesButtonProps = TDispatchProps & TReduxProps & TOwnProps; - const linkToExternalSpan = (traceID: string, spanID: string) => `${getUrl(traceID)}/uiFind?=${spanID}`; // export for tests -export class UnconnectedReferencesButton extends React.PureComponent { - focusSpan = (uiFind: string) => { - const { trace, focusUiFindMatches, location, history } = this.props; - if (trace && trace.data) { - updateUiFind({ - location, - history, - uiFind, - }); - focusUiFindMatches(trace.data, uiFind, true); - } - }; +export default class ReferencesButton extends React.PureComponent { + _focusSpan(spanID: string) { + this.props.focusSpan(spanID); + } spanLink = (reference: SpanReference, traceID: string, children?: React.ReactNode, className?: string) => { if (traceID === reference.traceID) { return ( - this.focusSpan(reference.spanID)} className={className}> + this._focusSpan(reference.spanID)} className={className}> {children} ); @@ -139,26 +109,3 @@ export class UnconnectedReferencesButton extends React.PureComponent): TDispatchProps { - const { focusUiFindMatches } = bindActionCreators(timelineActions, dispatch); - return { focusUiFindMatches }; -} - -// export for tests -export function mapStateToProps(state: ReduxState, ownProps: TOwnProps): TReduxProps { - const { traces } = state.trace; - const trace = ownProps.traceID ? traces[ownProps.traceID] : null; - return { - trace, - ...extractUiFindFromState(state), - }; -} - -export default withRouter( - connect( - mapStateToProps, - mapDispatchToProps - )(UnconnectedReferencesButton) -); diff --git a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanBarRow.tsx b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanBarRow.tsx index 23841354c3..fd4b0d4d77 100644 --- a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanBarRow.tsx +++ b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanBarRow.tsx @@ -52,6 +52,7 @@ type SpanBarRowProps = { getViewedBounds: ViewedBoundsFunctionType; traceStartTime: number; span: Span; + focusSpan: (spanID: string) => void; }; /** @@ -90,6 +91,7 @@ export default class SpanBarRow extends React.PureComponent { getViewedBounds, traceStartTime, span, + focusSpan, } = this.props; const { duration, @@ -157,6 +159,7 @@ export default class SpanBarRow extends React.PureComponent { references={span.references} traceID={span.traceID} tooltipText="Contains multiple references" + focusSpan={focusSpan} > @@ -166,6 +169,7 @@ export default class SpanBarRow extends React.PureComponent { references={span.referrals} traceID={span.traceID} tooltipText="This span is refereed by another span" + focusSpan={focusSpan} > diff --git a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/AccordianReferences.css b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/AccordianReferences.css index 18c29f9135..0882490213 100644 --- a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/AccordianReferences.css +++ b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/AccordianReferences.css @@ -1,3 +1,19 @@ +/* +Copyright (c) 2019 Uber Technologies, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + .ReferencesList--List { width: 100%; list-style: none; diff --git a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/AccordianReferences.test.js b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/AccordianReferences.test.js new file mode 100644 index 0000000000..15f1457207 --- /dev/null +++ b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/AccordianReferences.test.js @@ -0,0 +1,119 @@ +// Copyright (c) 2019 Uber Technologies, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import React from 'react'; +import { mount } from 'enzyme'; +import AccordianReferences, { References } from './AccordianReferences'; + +/* +export type SpanReference = { + refType: 'CHILD_OF' | 'FOLLOWS_FROM'; + // eslint-disable-next-line no-use-before-define + span: Span | null | undefined; + spanID: string; + traceID: string; +}; + + */ +const references = [ + { + refType: 'CHILD_OF', + span: { + spanID: 'span2', + traceID: 'trace1', + operationName: 'op1', + process: { + serviceName: 'service1', + }, + }, + spanID: 'span1', + traceID: 'trace1', + }, + { + refType: 'CHILD_OF', + span: { + spanID: 'span3', + traceID: 'trace1', + operationName: 'op2', + process: { + serviceName: 'service2', + }, + }, + spanID: 'span4', + traceID: 'trace1', + }, + { + refType: 'CHILD_OF', + span: { + spanID: 'span6', + traceID: 'trace2', + operationName: 'op2', + process: { + serviceName: 'service2', + }, + }, + spanID: 'span5', + traceID: 'trace2', + }, +]; + +describe('', () => { + let wrapper; + const mockFocusSpan = jest.fn(); + + const props = { + compact: false, + data: references, + highContrast: false, + isOpen: false, + label: 'le-label', + onToggle: jest.fn(), + focusSpan: mockFocusSpan, + }; + + beforeEach(() => { + wrapper = mount(); + mockFocusSpan.mockReset(); + }); + + it('renders without exploding', () => { + expect(wrapper).toBeDefined(); + expect(wrapper.exists()).toBe(true); + }); + + it('renders the label', () => { + const header = wrapper.find(`.AccordianReferences--header > strong`); + expect(header.length).toBe(1); + expect(header.text()).toBe(props.label); + }); + + it('renders the content when it is expanded', () => { + wrapper.setProps({ isOpen: true }); + const content = wrapper.find(References); + expect(content.length).toBe(1); + expect(content.prop('data')).toBe(references); + const links = content.find('a'); + expect(links.length).toBe(references.length); + }); + + it('call spanFocus when click on item', () => { + wrapper.setProps({ isOpen: true }); + const content = wrapper.find(References); + content + .find('a') + .at(0) + .simulate('click'); + expect(mockFocusSpan).toHaveBeenLastCalledWith(references[0].spanID); + }); +}); diff --git a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/AccordianReferences.tsx b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/AccordianReferences.tsx index 5d823fa7f0..a5d011d1e2 100644 --- a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/AccordianReferences.tsx +++ b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/AccordianReferences.tsx @@ -16,18 +16,11 @@ import * as React from 'react'; import cx from 'classnames'; import IoIosArrowDown from 'react-icons/lib/io/ios-arrow-down'; import IoIosArrowRight from 'react-icons/lib/io/ios-arrow-right'; -import { FetchedTrace, ReduxState, TNil } from '../../../../types'; - +import { TNil } from '../../../../types'; import './AccordianReferences.css'; -import { SpanReference, Trace } from '../../../../types/trace'; -import updateUiFind from '../../../../utils/update-ui-find'; -import { connect, Dispatch } from 'react-redux'; -import { bindActionCreators } from 'redux'; -import { actions as timelineActions } from '../duck'; -import { extractUiFindFromState } from '../../../common/UiFindInput'; -import { RouteComponentProps, withRouter } from 'react-router-dom'; +import { SpanReference } from '../../../../types/trace'; -type TOwnProps = { +type AccordianReferencesProps = { className?: string | TNil; data: SpanReference[]; headerClassName?: string | TNil; @@ -37,25 +30,15 @@ type TOwnProps = { label: React.ReactNode; onToggle?: null | (() => void); traceID: string; + focusSpan: (uiFind: string) => void; }; -type TDispatchProps = { - focusUiFindMatches: (trace: Trace, uiFind: string | TNil, preserveHiddenStatus?: boolean) => void; -}; - -type TReduxProps = { - uiFind: string | TNil; - trace: FetchedTrace | TNil; -}; - -type AccordianReferencesProps = TOwnProps & TDispatchProps & TReduxProps & RouteComponentProps; - type ReferenceItemProps = { data: SpanReference[]; - focusSpan: (spanID: string) => void; + focusSpan: (uiFind: string) => void; }; -function References(props: ReferenceItemProps) { +export function References(props: ReferenceItemProps) { const { data, focusSpan } = props; return (
@@ -74,7 +57,7 @@ function References(props: ReferenceItemProps) { ); } -export class UnconnectedAccordianReferences extends React.PureComponent { +export default class AccordianReferences extends React.PureComponent { static defaultProps = { className: null, highContrast: false, @@ -82,18 +65,6 @@ export class UnconnectedAccordianReferences extends React.PureComponent { - const { trace, focusUiFindMatches, location, history } = this.props; - if (trace && trace.data) { - updateUiFind({ - location, - history, - uiFind, - }); - focusUiFindMatches(trace.data, uiFind, true); - } - }; - render() { const { className, @@ -104,6 +75,7 @@ export class UnconnectedAccordianReferences extends React.PureComponent{label} ({data.length})
- {isOpen && } + {isOpen && } ); } } - -// export for tests -export function mapDispatchToProps(dispatch: Dispatch): TDispatchProps { - const { focusUiFindMatches } = bindActionCreators(timelineActions, dispatch); - return { focusUiFindMatches }; -} - -// export for tests -export function mapStateToProps(state: ReduxState, ownProps: TOwnProps): TReduxProps { - const { traces } = state.trace; - const trace = ownProps.traceID ? traces[ownProps.traceID] : null; - return { - trace, - ...extractUiFindFromState(state), - }; -} - -export default withRouter( - connect( - mapStateToProps, - mapDispatchToProps - )(UnconnectedAccordianReferences) -); diff --git a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/index.test.js b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/index.test.js index 485ddb9294..ace3f4fad4 100644 --- a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/index.test.js +++ b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/index.test.js @@ -36,6 +36,7 @@ describe('', () => { const detailState = new DetailState() .toggleLogs() .toggleProcess() + .toggleReferences() .toggleTags(); const traceStartTime = 5; const props = { @@ -47,6 +48,7 @@ describe('', () => { processToggle: jest.fn(), tagsToggle: jest.fn(), warningsToggle: jest.fn(), + referencesToggle: jest.fn(), }; span.logs = [ { @@ -61,6 +63,48 @@ describe('', () => { span.warnings = ['Warning 1', 'Warning 2']; + span.references = [ + { + refType: 'CHILD_OF', + span: { + spanID: 'span2', + traceID: 'trace1', + operationName: 'op1', + process: { + serviceName: 'service1', + }, + }, + spanID: 'span1', + traceID: 'trace1', + }, + { + refType: 'CHILD_OF', + span: { + spanID: 'span3', + traceID: 'trace1', + operationName: 'op2', + process: { + serviceName: 'service2', + }, + }, + spanID: 'span4', + traceID: 'trace1', + }, + { + refType: 'CHILD_OF', + span: { + spanID: 'span6', + traceID: 'trace2', + operationName: 'op2', + process: { + serviceName: 'service2', + }, + }, + spanID: 'span5', + traceID: 'trace2', + }, + ]; + beforeEach(() => { formatDuration.mockReset(); props.tagsToggle.mockReset(); @@ -130,6 +174,13 @@ describe('', () => { expect(props.warningsToggle).toHaveBeenLastCalledWith(span.spanID); }); + it('renders the references', () => { + const warningElm = wrapper.find({ data: span.references }); + expect(warningElm.length).toBe(1); + warningElm.simulate('toggle'); + expect(props.referencesToggle).toHaveBeenLastCalledWith(span.spanID); + }); + it('renders CopyIcon with deep link URL', () => { expect( wrapper diff --git a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/index.tsx b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/index.tsx index f603bbbfed..60f65db352 100644 --- a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/index.tsx +++ b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/index.tsx @@ -40,6 +40,7 @@ type SpanDetailProps = { traceStartTime: number; warningsToggle: (spanID: string) => void; referencesToggle: (spanID: string) => void; + focusSpan: (uiFind: string) => void; }; export default function SpanDetail(props: SpanDetailProps) { @@ -54,6 +55,7 @@ export default function SpanDetail(props: SpanDetailProps) { traceStartTime, warningsToggle, referencesToggle, + focusSpan, } = props; const { isTagsOpen, isProcessOpen, logs: logsState, isWarningsOpen, isReferencesOpen } = detailState; const { @@ -147,6 +149,7 @@ export default function SpanDetail(props: SpanDetailProps) { isOpen={isReferencesOpen} onToggle={() => referencesToggle(spanID)} traceID={span.traceID} + focusSpan={focusSpan} /> )} diff --git a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetailRow.tsx b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetailRow.tsx index 40583f0ebc..81d83f8780 100644 --- a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetailRow.tsx +++ b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetailRow.tsx @@ -37,6 +37,7 @@ type SpanDetailRowProps = { span: Span; tagsToggle: (spanID: string) => void; traceStartTime: number; + focusSpan: (uiFind: string) => void; }; export default class SpanDetailRow extends React.PureComponent { @@ -62,6 +63,7 @@ export default class SpanDetailRow extends React.PureComponent @@ -90,6 +92,7 @@ export default class SpanDetailRow extends React.PureComponent diff --git a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/VirtualizedTraceView.test.js b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/VirtualizedTraceView.test.js index d2f84783d2..df52d163e6 100644 --- a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/VirtualizedTraceView.test.js +++ b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/VirtualizedTraceView.test.js @@ -21,12 +21,15 @@ import SpanDetailRow from './SpanDetailRow'; import { DEFAULT_HEIGHTS, VirtualizedTraceViewImpl } from './VirtualizedTraceView'; import traceGenerator from '../../../demo/trace-generators'; import transformTraceData from '../../../model/transform-trace-data'; +import updateUiFindSpy from '../../../utils/update-ui-find'; jest.mock('./SpanTreeOffset'); +jest.mock('../../../utils/update-ui-find'); describe('', () => { let wrapper; let instance; + const focusUiFindMatchesMock = jest.fn(); const trace = transformTraceData(traceGenerator.trace({ numberOfSpans: 10 })); const props = { @@ -44,11 +47,18 @@ describe('', () => { registerAccessors: jest.fn(), scrollToFirstVisibleSpan: jest.fn(), setSpanNameColumnWidth: jest.fn(), + focusUiFindMatches: focusUiFindMatchesMock, setTrace: jest.fn(), shouldScrollToFirstUiFindMatch: false, spanNameColumnWidth: 0.5, trace, uiFind: 'uiFind', + history: { + replace: () => {}, + }, + location: { + search: null, + }, }; function expandRow(rowIndex) { @@ -390,4 +400,16 @@ describe('', () => { }); }); }); + + describe('focusSpan', () => { + it('calls updateUiFind and focusUiFindMatches when focusSpan', () => { + focusUiFindMatchesMock.mockReset(); + instance.focusSpan('span1'); + expect(updateUiFindSpy).toHaveBeenLastCalledWith({ + history: props.history, + location: props.location, + uiFind: 'span1', + }); + }); + }); }); diff --git a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/VirtualizedTraceView.tsx b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/VirtualizedTraceView.tsx index c9b0ee6ccf..5525bfc4be 100644 --- a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/VirtualizedTraceView.tsx +++ b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/VirtualizedTraceView.tsx @@ -41,6 +41,7 @@ import { Log, Span, Trace, KeyValuePair } from '../../../types/trace'; import TTraceTimeline from '../../../types/TTraceTimeline'; import './VirtualizedTraceView.css'; +import updateUiFind from '../../../utils/update-ui-find'; type RowState = { isDetail: boolean; @@ -68,6 +69,7 @@ type TDispatchProps = { detailToggle: (spanID: string) => void; setSpanNameColumnWidth: (width: number) => void; setTrace: (trace: Trace | TNil, uiFind: string | TNil) => void; + focusUiFindMatches: (trace: Trace, uiFind: string | TNil, preserveHiddenStatus?: boolean) => void; }; type VirtualizedTraceViewProps = TVirtualizedTraceViewOwnProps & @@ -221,6 +223,18 @@ export class VirtualizedTraceViewImpl extends React.Component { + const { trace, focusUiFindMatches, location, history } = this.props; + if (trace) { + updateUiFind({ + location, + history, + uiFind, + }); + focusUiFindMatches(trace, uiFind, true); + } + }; + getAccessors() { const lv = this.listView; if (!lv) { @@ -361,6 +375,7 @@ export class VirtualizedTraceViewImpl extends React.Component ); @@ -402,6 +417,7 @@ export class VirtualizedTraceViewImpl extends React.Component ); diff --git a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/__snapshots__/ReferencesButton.test.js.snap b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/__snapshots__/ReferencesButton.test.js.snap index 7ac04b3e32..1cc78aaf4a 100644 --- a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/__snapshots__/ReferencesButton.test.js.snap +++ b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/__snapshots__/ReferencesButton.test.js.snap @@ -6,7 +6,8 @@ exports[`ReferencesButton rendering rendering as expected 1`] = ` autoAdjustOverflow={true} mouseEnterDelay={0.1} mouseLeaveDelay={0.5} - placement="left" + overlayClassName="ref-tooltip" + placement="bottom" prefixCls="ant-tooltip" transitionName="zoom-big-fast" > @@ -24,7 +25,8 @@ exports[`ReferencesButton rendering rendering as with external reference 1`] = ` autoAdjustOverflow={true} mouseEnterDelay={0.1} mouseLeaveDelay={0.5} - placement="left" + overlayClassName="ref-tooltip" + placement="bottom" prefixCls="ant-tooltip" transitionName="zoom-big-fast" > diff --git a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/duck.test.js b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/duck.test.js index 6af5d32e7f..5820f35f11 100644 --- a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/duck.test.js +++ b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/duck.test.js @@ -387,6 +387,13 @@ describe('TraceTimelineViewer/duck', () => { unchecked: new DetailState(), checked: baseDetail.toggleWarnings(), }, + { + msg: 'toggles references', + action: actions.detailReferencesToggle(id), + get: state => state.detailStates.get(id), + unchecked: new DetailState(), + checked: baseDetail.toggleReferences(), + }, ]; beforeEach(() => { From b0f45d643f3ec2a6ffe281fe99191067f2c470f0 Mon Sep 17 00:00:00 2001 From: Ruben Vargas Date: Wed, 20 Nov 2019 15:41:14 -0600 Subject: [PATCH 12/22] Create referenceLink component to reuse on accordion Signed-off-by: Ruben Vargas --- .../TraceTimelineViewer/ReferenceLink.test.js | 65 +++++++++++++++++ .../TraceTimelineViewer/ReferenceLink.tsx | 50 +++++++++++++ .../ReferencesButton.test.js | 71 ++++--------------- .../TraceTimelineViewer/ReferencesButton.tsx | 59 ++++++--------- .../SpanDetail/AccordianReferences.tsx | 8 ++- .../ReferencesButton.test.js.snap | 40 ----------- 6 files changed, 155 insertions(+), 138 deletions(-) create mode 100644 packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferenceLink.test.js create mode 100644 packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferenceLink.tsx delete mode 100644 packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/__snapshots__/ReferencesButton.test.js.snap diff --git a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferenceLink.test.js b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferenceLink.test.js new file mode 100644 index 0000000000..73b9fb7339 --- /dev/null +++ b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferenceLink.test.js @@ -0,0 +1,65 @@ +// Copyright (c) 2019 Uber Technologies, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import React from 'react'; +import { shallow } from 'enzyme'; + +import ReferenceLink from './ReferenceLink'; + +describe(ReferenceLink, () => { + const focusMock = jest.fn(); + const traceID = 'trace1'; + + const sameTraceRef = { + refType: 'CHILD_OF', + traceID: 'trace1', + spanID: 'span1', + }; + + const externalRef = { + refType: 'CHILD_OF', + traceID: 'trace2', + spanID: 'span2', + }; + + describe('rendering', () => { + it('render for external trace', () => { + const component = shallow( + + ); + const link = component.find('a'); + expect(link.length).toBe(1); + expect(link.props().role).toBe('button'); + }); + + it('render for this trace', () => { + const component = shallow( + + ); + const link = component.find('a[href="/trace/trace2/uiFind?=span2"]'); + expect(link.length).toBe(1); + }); + }); + describe('focus span', () => { + it('call focusSpan', () => { + focusMock.mockReset(); + const component = shallow( + + ); + const link = component.find('a'); + link.simulate('click'); + expect(focusMock).toHaveBeenLastCalledWith('span1'); + }); + }); +}); diff --git a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferenceLink.tsx b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferenceLink.tsx new file mode 100644 index 0000000000..214a1c4923 --- /dev/null +++ b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferenceLink.tsx @@ -0,0 +1,50 @@ +// Copyright (c) 2019 Uber Technologies, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import React from 'react'; +import { SpanReference } from '../../../types/trace'; +import { getUrl } from '../url'; + +type ReferenceLinkProps = { + reference: SpanReference; + traceID: string; + children?: React.ReactNode; + className?: string; + focusSpan: (spanID: string) => void; +}; + +export default class ReferenceLink extends React.PureComponent { + linkToExternalSpan = (traceID: string, spanID: string) => `${getUrl(traceID)}/uiFind?=${spanID}`; + + render() { + const { traceID, reference, children, className, focusSpan } = this.props; + if (traceID === reference.traceID) { + return ( + focusSpan(reference.spanID)} className={className}> + {children} + + ); + } + return ( + + {children} + + ); + } +} diff --git a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.test.js b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.test.js index 1a331c914d..10812d5535 100644 --- a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.test.js +++ b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.test.js @@ -13,15 +13,15 @@ // limitations under the License. import React from 'react'; -import { shallow, mount } from 'enzyme'; -import { Menu, Dropdown } from 'antd'; +import { shallow } from 'enzyme'; +import { Menu, Dropdown, Tooltip } from 'antd'; import ReferencesButton from './ReferencesButton'; import transformTraceData from '../../../model/transform-trace-data'; import traceGenerator from '../../../demo/trace-generators'; -import NewWindowIcon from '../../common/NewWindowIcon'; +import ReferenceLink from './ReferenceLink'; -describe('ReferencesButton', () => { +describe(ReferencesButton, () => { const trace = transformTraceData(traceGenerator.trace({ numberOfSpans: 10 })); const focusMock = jest.fn(); const oneReference = trace.spans[1].references; @@ -47,20 +47,17 @@ describe('ReferencesButton', () => { focusSpan: focusMock, }; describe('rendering', () => { - it('rendering as expected', () => { + it('render with dropdown', () => { const props = { ...baseProps, references: oneReference }; const wrapper = shallow(); - expect(wrapper).toMatchSnapshot(); - }); - - it('rendering as with external reference', () => { - const oneExternal = [{ ...oneReference[0] }]; - oneExternal[0].traceID = 'extTrace'; - oneExternal[0].spanID = 'extSpanID'; + const dropdown = wrapper.find(Dropdown); + const refLink = wrapper.find(ReferenceLink); + const tooltip = wrapper.find(Tooltip); - const props = { ...baseProps, references: oneExternal }; - const wrapper = shallow(); - expect(wrapper).toMatchSnapshot(); + expect(dropdown.length).toBe(0); + expect(refLink.length).toBe(1); + expect(refLink.first().props().className).toBe('multi-parent-button'); + expect(tooltip.length).toBe(1); }); it('render with dropdown', () => { @@ -72,49 +69,5 @@ describe('ReferencesButton', () => { const submenuItems = menuInstance.find(Menu.Item); expect(submenuItems.length).toBe(2); }); - - it('render with dropdown and mix of external and internal', () => { - const mixRef = oneReference.slice(); - const oneExternal = { ...oneReference[0] }; - oneExternal.traceID = 'extTrace'; - oneExternal.spanID = 'extSpanID'; - mixRef.push(oneExternal); - const props = { ...baseProps, references: mixRef }; - const wrapper = shallow(); - const dropdown = wrapper.find(Dropdown); - expect(dropdown.length).toBe(1); - const menuInstance = shallow(dropdown.first().props().overlay); - const submenuItems = menuInstance.find(Menu.Item); - expect(submenuItems.length).toBe(2); - expect(submenuItems.at(1).find('a[href="/trace/extTrace/uiFind?=extSpanID"]').length).toBe(1); - expect(submenuItems.at(1).find(NewWindowIcon).length).toBe(1); - }); - }); - - describe('navigate to reference', () => { - beforeEach(() => { - focusMock.mockReset(); - }); - - it('calls updateUiFind and focusUiFindMatches with correct kwargs', () => { - const props = { ...baseProps, references: oneReference }; - const wrapper = shallow(); - wrapper.find('a').simulate('click'); - expect(focusMock).toHaveBeenLastCalledWith(trace.spans[1].references[0].spanID); - }); - - it('calls updateUiFind and focusUiFindMatches with correct kwargs on dropdown', () => { - const props = { ...baseProps, references: moreReferences }; - const wrapper = mount(); - const dropdown = wrapper.find(Dropdown); - dropdown.find('.multi-parent-button').simulate('click'); - const menuInstance = shallow(dropdown.first().props().overlay); - const submenuItems = menuInstance.find(Menu.Item); - submenuItems - .at(0) - .find('a') - .simulate('click'); - expect(focusMock).toHaveBeenLastCalledWith(trace.spans[1].references[0].spanID); - }); }); }); diff --git a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.tsx b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.tsx index c45a75d1b8..f048b93096 100644 --- a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.tsx +++ b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.tsx @@ -15,11 +15,10 @@ import React from 'react'; import { Dropdown, Menu, Tooltip } from 'antd'; import NewWindowIcon from '../../common/NewWindowIcon'; - -import { getUrl } from '../url'; import { SpanReference } from '../../../types/trace'; import './ReferencesButton.css'; +import ReferenceLink from './ReferenceLink'; type TReferencesButtonProps = { references: SpanReference[]; @@ -29,51 +28,30 @@ type TReferencesButtonProps = { focusSpan: (spanID: string) => void; }; -const linkToExternalSpan = (traceID: string, spanID: string) => `${getUrl(traceID)}/uiFind?=${spanID}`; - // export for tests export default class ReferencesButton extends React.PureComponent { _focusSpan(spanID: string) { this.props.focusSpan(spanID); } - spanLink = (reference: SpanReference, traceID: string, children?: React.ReactNode, className?: string) => { - if (traceID === reference.traceID) { - return ( - this._focusSpan(reference.spanID)} className={className}> - {children} - - ); - } - return ( - - {children} - - ); - }; - referencesList = (references: SpanReference[]) => ( {references.map(ref => { const { span, traceID, spanID } = ref; - const child = ( - - {span - ? `${span.process.serviceName}:${span.operationName} - ${ref.spanID}` - : `(another trace) - ${ref.spanID}`} - {traceID !== this.props.traceID && ( -
- -
- )} -
+ return ( + + + {span + ? `${span.process.serviceName}:${span.operationName} - ${ref.spanID}` + : `(another trace) - ${ref.spanID}`} + {traceID !== this.props.traceID && ( +
+ +
+ )} +
+
); - return {this.spanLink(ref, this.props.traceID, child)}; })}
); @@ -104,7 +82,14 @@ export default class ReferencesButton extends React.PureComponent - {this.spanLink(ref, this.props.traceID, children, 'multi-parent-button')} + + {children} + ); } diff --git a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/AccordianReferences.tsx b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/AccordianReferences.tsx index a5d011d1e2..56160a06e2 100644 --- a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/AccordianReferences.tsx +++ b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/AccordianReferences.tsx @@ -19,6 +19,7 @@ import IoIosArrowRight from 'react-icons/lib/io/ios-arrow-right'; import { TNil } from '../../../../types'; import './AccordianReferences.css'; import { SpanReference } from '../../../../types/trace'; +import ReferenceLink from '../ReferenceLink'; type AccordianReferencesProps = { className?: string | TNil; @@ -36,16 +37,18 @@ type AccordianReferencesProps = { type ReferenceItemProps = { data: SpanReference[]; focusSpan: (uiFind: string) => void; + traceID: string; }; export function References(props: ReferenceItemProps) { - const { data, focusSpan } = props; + const { data, focusSpan, traceID } = props; return (
- {isOpen && } + {isOpen && } ); } diff --git a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/__snapshots__/ReferencesButton.test.js.snap b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/__snapshots__/ReferencesButton.test.js.snap deleted file mode 100644 index 1cc78aaf4a..0000000000 --- a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/__snapshots__/ReferencesButton.test.js.snap +++ /dev/null @@ -1,40 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`ReferencesButton rendering rendering as expected 1`] = ` - - - -`; - -exports[`ReferencesButton rendering rendering as with external reference 1`] = ` - - - -`; From 8f33d803e194d3d3c5ff33d81852546eb5057a19 Mon Sep 17 00:00:00 2001 From: Ruben Vargas Date: Wed, 20 Nov 2019 18:03:27 -0600 Subject: [PATCH 13/22] Cosmetic changes to references accordion Signed-off-by: Ruben Vargas --- .../TraceTimelineViewer/ReferencesButton.tsx | 10 ++-- .../SpanDetail/AccordianReferences.css | 16 ++++++ .../SpanDetail/AccordianReferences.test.js | 49 ++++++++++--------- .../SpanDetail/AccordianReferences.tsx | 24 +++++++-- 4 files changed, 66 insertions(+), 33 deletions(-) diff --git a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.tsx b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.tsx index f048b93096..f25fec43fb 100644 --- a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.tsx +++ b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.tsx @@ -30,17 +30,13 @@ type TReferencesButtonProps = { // export for tests export default class ReferencesButton extends React.PureComponent { - _focusSpan(spanID: string) { - this.props.focusSpan(spanID); - } - referencesList = (references: SpanReference[]) => ( {references.map(ref => { const { span, traceID, spanID } = ref; return ( - + {span ? `${span.process.serviceName}:${span.operationName} - ${ref.spanID}` : `(another trace) - ${ref.spanID}`} @@ -57,7 +53,7 @@ export default class ReferencesButton extends React.PureComponent 1) { return ( {children} diff --git a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/AccordianReferences.css b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/AccordianReferences.css index 0882490213..9d66a7e680 100644 --- a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/AccordianReferences.css +++ b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/AccordianReferences.css @@ -33,6 +33,22 @@ limitations under the License. padding: 0.25rem 0.5rem; } +.ReferencesList--Item > a { + width: 100%; + display: inline-block; +} + .ReferencesList--Item:nth-child(2n) { background: #f5f5f5; } + +.SpanReference--debugInfo { + letter-spacing: 0.25px; + margin: 0.5em 0 -0.75em; + float: right; +} + +.SpanReference--debugLabel::before { + color: #bbb; + content: attr(data-label); +} diff --git a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/AccordianReferences.test.js b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/AccordianReferences.test.js index 15f1457207..4d7f5d87dd 100644 --- a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/AccordianReferences.test.js +++ b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/AccordianReferences.test.js @@ -13,19 +13,10 @@ // limitations under the License. import React from 'react'; -import { mount } from 'enzyme'; +import { shallow } from 'enzyme'; import AccordianReferences, { References } from './AccordianReferences'; +import ReferenceLink from '../ReferenceLink'; -/* -export type SpanReference = { - refType: 'CHILD_OF' | 'FOLLOWS_FROM'; - // eslint-disable-next-line no-use-before-define - span: Span | null | undefined; - spanID: string; - traceID: string; -}; - - */ const references = [ { refType: 'CHILD_OF', @@ -83,7 +74,7 @@ describe('', () => { }; beforeEach(() => { - wrapper = mount(); + wrapper = shallow(); mockFocusSpan.mockReset(); }); @@ -103,17 +94,31 @@ describe('', () => { const content = wrapper.find(References); expect(content.length).toBe(1); expect(content.prop('data')).toBe(references); - const links = content.find('a'); - expect(links.length).toBe(references.length); }); +}); - it('call spanFocus when click on item', () => { - wrapper.setProps({ isOpen: true }); - const content = wrapper.find(References); - content - .find('a') - .at(0) - .simulate('click'); - expect(mockFocusSpan).toHaveBeenLastCalledWith(references[0].spanID); +describe('', () => { + let wrapper; + const mockFocusSpan = jest.fn(); + + const props = { + data: references, + traceID: 'trace1', + focusSpan: jest.fn(), + }; + + beforeEach(() => { + wrapper = shallow(); + mockFocusSpan.mockReset(); + }); + + it('render references list', () => { + expect(wrapper.find(ReferenceLink).length).toBe(references.length); + const spanOtherTrace = wrapper + .find('ReferenceLink') + .at(2) + .find('span.span-svc-name') + .text(); + expect(spanOtherTrace).toBe('< span in another trace >'); }); }); diff --git a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/AccordianReferences.tsx b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/AccordianReferences.tsx index 56160a06e2..425fd92cad 100644 --- a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/AccordianReferences.tsx +++ b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/AccordianReferences.tsx @@ -40,6 +40,7 @@ type ReferenceItemProps = { traceID: string; }; +// export for test export function References(props: ReferenceItemProps) { const { data, focusSpan, traceID } = props; return ( @@ -48,10 +49,25 @@ export function References(props: ReferenceItemProps) { {data.map(reference => { return (
  • - - focusSpan(reference.spanID)}> - {reference.spanID}{' '} - + + {reference.span && reference.traceID === traceID && ( + + {reference.span.process.serviceName} + {reference.span.operationName} + + {reference.spanID} + + + )} + {reference.traceID !== traceID && ( + + < span in another trace > + + {reference.spanID} + + + )} +
  • ); })} From ab4c3244ad034d7ea5a24ba49fb6d72dc036c288 Mon Sep 17 00:00:00 2001 From: Ruben Vargas Date: Fri, 22 Nov 2019 00:03:11 -0600 Subject: [PATCH 14/22] Change icon for navigate to refered spans Signed-off-by: Ruben Vargas --- .../components/TracePage/TraceTimelineViewer/SpanBarRow.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanBarRow.tsx b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanBarRow.tsx index fd4b0d4d77..4d0a88378d 100644 --- a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanBarRow.tsx +++ b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanBarRow.tsx @@ -16,7 +16,7 @@ import * as React from 'react'; import IoAlert from 'react-icons/lib/io/alert'; import IoArrowRightA from 'react-icons/lib/io/arrow-right-a'; import IoNetwork from 'react-icons/lib/io/network'; -import IoIosArrowUp from 'react-icons/lib/io/ios-arrow-up'; +import MdFileUpload from 'react-icons/lib/md/file-upload'; import ReferencesButton from './ReferencesButton'; import TimelineRow from './TimelineRow'; import { formatDuration, ViewedBoundsFunctionType } from './utils'; @@ -171,7 +171,7 @@ export default class SpanBarRow extends React.PureComponent { tooltipText="This span is refereed by another span" focusSpan={focusSpan} > - + )} From c6b3a48b8f6f48cb056aa8b48ab69e783206959e Mon Sep 17 00:00:00 2001 From: Ruben Vargas Date: Fri, 22 Nov 2019 10:47:23 -0600 Subject: [PATCH 15/22] Reference button does not show tooltip on single link case Signed-off-by: Ruben Vargas --- .../TracePage/TraceTimelineViewer/ReferenceLink.tsx | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferenceLink.tsx b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferenceLink.tsx index 214a1c4923..dc3a05c90f 100644 --- a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferenceLink.tsx +++ b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferenceLink.tsx @@ -22,16 +22,18 @@ type ReferenceLinkProps = { children?: React.ReactNode; className?: string; focusSpan: (spanID: string) => void; + onClick?: () => void; }; export default class ReferenceLink extends React.PureComponent { linkToExternalSpan = (traceID: string, spanID: string) => `${getUrl(traceID)}/uiFind?=${spanID}`; render() { - const { traceID, reference, children, className, focusSpan } = this.props; + const { traceID, reference, children, className, focusSpan, ...otherProps } = this.props; + delete otherProps.onClick; if (traceID === reference.traceID) { return ( - focusSpan(reference.spanID)} className={className}> + focusSpan(reference.spanID)} className={className} {...otherProps}> {children} ); @@ -42,6 +44,7 @@ export default class ReferenceLink extends React.PureComponent {children} From c3980a358953939a6f571bb0323dba929029f386 Mon Sep 17 00:00:00 2001 From: Ruben Vargas Date: Fri, 22 Nov 2019 12:22:11 -0600 Subject: [PATCH 16/22] Added reference type info to references accordian Signed-off-by: Ruben Vargas --- .../SpanDetail/AccordianReferences.css | 4 ++++ .../SpanDetail/AccordianReferences.tsx | 14 ++++++++++++-- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/AccordianReferences.css b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/AccordianReferences.css index 9d66a7e680..ca69460006 100644 --- a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/AccordianReferences.css +++ b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/AccordianReferences.css @@ -52,3 +52,7 @@ limitations under the License. color: #bbb; content: attr(data-label); } + +.SpanReference--debugLabel { + margin: 0 5px 0 5px; +} diff --git a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/AccordianReferences.tsx b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/AccordianReferences.tsx index 425fd92cad..caa2354df6 100644 --- a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/AccordianReferences.tsx +++ b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/AccordianReferences.tsx @@ -55,7 +55,12 @@ export function References(props: ReferenceItemProps) { {reference.span.process.serviceName} {reference.span.operationName} - {reference.spanID} + + {reference.refType} + + + {reference.spanID} + )} @@ -63,7 +68,12 @@ export function References(props: ReferenceItemProps) { < span in another trace > - {reference.spanID} + + {reference.refType} + + + {reference.spanID} + )} From 71ecc29214c2c23c74a2cde39faab82d3f4276ab Mon Sep 17 00:00:00 2001 From: Ruben Vargas Date: Wed, 11 Dec 2019 00:20:31 -0600 Subject: [PATCH 17/22] Multiple improvements to tests ,css styles and some components Signed-off-by: Ruben Vargas --- .../TraceTimelineViewer/ReferenceLink.test.js | 4 +- .../TraceTimelineViewer/ReferenceLink.tsx | 2 +- .../TraceTimelineViewer/ReferencesButton.css | 17 +++-- .../ReferencesButton.test.js | 44 ++++++------ .../TraceTimelineViewer/ReferencesButton.tsx | 20 +++--- .../TraceTimelineViewer/SpanBarRow.tsx | 8 ++- .../SpanDetail/AccordianReferences.css | 10 +-- .../SpanDetail/AccordianReferences.test.js | 43 ++++++------ .../SpanDetail/AccordianReferences.tsx | 70 +++++++------------ .../SpanDetail/index.test.js | 6 +- .../TraceTimelineViewer/SpanDetail/index.tsx | 3 - .../VirtualizedTraceView.test.js | 8 +-- .../TracePage/TraceTimelineViewer/duck.tsx | 13 ++-- .../src/model/transform-trace-data.tsx | 4 +- packages/jaeger-ui/src/reducers/trace.test.js | 37 ++++++---- packages/jaeger-ui/src/types/trace.tsx | 2 +- 16 files changed, 144 insertions(+), 147 deletions(-) diff --git a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferenceLink.test.js b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferenceLink.test.js index 73b9fb7339..893dc98056 100644 --- a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferenceLink.test.js +++ b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferenceLink.test.js @@ -34,7 +34,7 @@ describe(ReferenceLink, () => { }; describe('rendering', () => { - it('render for external trace', () => { + it('render for this trace', () => { const component = shallow( ); @@ -43,7 +43,7 @@ describe(ReferenceLink, () => { expect(link.props().role).toBe('button'); }); - it('render for this trace', () => { + it('render for external trace', () => { const component = shallow( ); diff --git a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferenceLink.tsx b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferenceLink.tsx index dc3a05c90f..874d6cb7f2 100644 --- a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferenceLink.tsx +++ b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferenceLink.tsx @@ -19,7 +19,7 @@ import { getUrl } from '../url'; type ReferenceLinkProps = { reference: SpanReference; traceID: string; - children?: React.ReactNode; + children: React.ReactNode; className?: string; focusSpan: (spanID: string) => void; onClick?: () => void; diff --git a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.css b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.css index 9118bad5e3..136bf1f015 100644 --- a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.css +++ b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.css @@ -14,16 +14,23 @@ See the License for the specific language governing permissions and limitations under the License. */ -.multi-parent-button { +.ReferencesButton-MultiParent { padding: 0 5px; color: #000; } - -.external-trace-ref { - float: right; +.ReferencesButton-MultiParent ~ .ReferencesButton-MultiParent { margin-left: 5px; } -.ref-tooltip { +a.ReferencesButton--TraceRefLink { + display: flex; + justify-content: space-between; +} + +a.ReferencesButton--TraceRefLink > .NewWindowIcon { + margin: 0.2em 0 0; +} + +.ReferencesButton-tooltip { max-width: none; } diff --git a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.test.js b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.test.js index 10812d5535..6e054ed24b 100644 --- a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.test.js +++ b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.test.js @@ -46,28 +46,32 @@ describe(ReferencesButton, () => { }, focusSpan: focusMock, }; - describe('rendering', () => { - it('render with dropdown', () => { - const props = { ...baseProps, references: oneReference }; - const wrapper = shallow(); - const dropdown = wrapper.find(Dropdown); - const refLink = wrapper.find(ReferenceLink); - const tooltip = wrapper.find(Tooltip); - expect(dropdown.length).toBe(0); - expect(refLink.length).toBe(1); - expect(refLink.first().props().className).toBe('multi-parent-button'); - expect(tooltip.length).toBe(1); - }); + it('renders single reference', () => { + const props = { ...baseProps, references: oneReference }; + const wrapper = shallow(); + const dropdown = wrapper.find(Dropdown); + const refLink = wrapper.find(ReferenceLink); + const tooltip = wrapper.find(Tooltip); + + expect(dropdown.length).toBe(0); + expect(refLink.length).toBe(1); + expect(refLink.prop('reference')).toBe(oneReference[0]); + expect(refLink.first().props().className).toBe('multi-parent-button'); + expect(tooltip.length).toBe(1); + expect(tooltip.prop('title')).toBe(props.tooltipText); + }); - it('render with dropdown', () => { - const props = { ...baseProps, references: moreReferences }; - const wrapper = shallow(); - const dropdown = wrapper.find(Dropdown); - expect(dropdown.length).toBe(1); - const menuInstance = shallow(dropdown.first().props().overlay); - const submenuItems = menuInstance.find(Menu.Item); - expect(submenuItems.length).toBe(2); + it('renders multiple references', () => { + const props = { ...baseProps, references: moreReferences }; + const wrapper = shallow(); + const dropdown = wrapper.find(Dropdown); + expect(dropdown.length).toBe(1); + const menuInstance = shallow(dropdown.first().props().overlay); + const submenuItems = menuInstance.find(Menu.Item); + expect(submenuItems.length).toBe(2); + submenuItems.forEach((submenuItem, i) => { + expect(submenuItem.find(ReferenceLink).prop('reference')).toBe(moreReferences[i]); }); }); }); diff --git a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.tsx b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.tsx index f25fec43fb..adfd597875 100644 --- a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.tsx +++ b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.tsx @@ -23,12 +23,11 @@ import ReferenceLink from './ReferenceLink'; type TReferencesButtonProps = { references: SpanReference[]; traceID: string; - children?: React.ReactNode; + children: React.ReactNode; tooltipText: string; focusSpan: (spanID: string) => void; }; -// export for tests export default class ReferencesButton extends React.PureComponent { referencesList = (references: SpanReference[]) => ( @@ -36,15 +35,16 @@ export default class ReferencesButton extends React.PureComponent - + {span ? `${span.process.serviceName}:${span.operationName} - ${ref.spanID}` : `(another trace) - ${ref.spanID}`} - {traceID !== this.props.traceID && ( -
    - -
    - )} + {traceID !== this.props.traceID && }
    ); @@ -61,10 +61,10 @@ export default class ReferencesButton extends React.PureComponent - {children} + {children} ); diff --git a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanBarRow.tsx b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanBarRow.tsx index 4d0a88378d..283bf75c46 100644 --- a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanBarRow.tsx +++ b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanBarRow.tsx @@ -164,11 +164,13 @@ export default class SpanBarRow extends React.PureComponent { )} - {span.referrals && span.referrals.length > 0 && ( + {span.subsidiarilyReferencedBy && span.subsidiarilyReferencedBy.length > 0 && ( diff --git a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/AccordianReferences.css b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/AccordianReferences.css index ca69460006..10d8cda636 100644 --- a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/AccordianReferences.css +++ b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/AccordianReferences.css @@ -29,11 +29,14 @@ limitations under the License. overflow: auto; } -.ReferencesList--Item { +.ReferencesList--itemContent { padding: 0.25rem 0.5rem; + display: flex; + width: 100%; + justify-content: space-between; } -.ReferencesList--Item > a { +.ReferencesList--itemContent > a { width: 100%; display: inline-block; } @@ -44,8 +47,7 @@ limitations under the License. .SpanReference--debugInfo { letter-spacing: 0.25px; - margin: 0.5em 0 -0.75em; - float: right; + margin: 0.5em 0 0; } .SpanReference--debugLabel::before { diff --git a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/AccordianReferences.test.js b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/AccordianReferences.test.js index 4d7f5d87dd..f5f6e04d31 100644 --- a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/AccordianReferences.test.js +++ b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/AccordianReferences.test.js @@ -17,37 +17,38 @@ import { shallow } from 'enzyme'; import AccordianReferences, { References } from './AccordianReferences'; import ReferenceLink from '../ReferenceLink'; +const traceID = 'trace1'; const references = [ { refType: 'CHILD_OF', span: { - spanID: 'span2', - traceID: 'trace1', + spanID: 'span1', + traceID, operationName: 'op1', process: { serviceName: 'service1', }, }, spanID: 'span1', - traceID: 'trace1', + traceID, }, { refType: 'CHILD_OF', span: { spanID: 'span3', - traceID: 'trace1', + traceID, operationName: 'op2', process: { serviceName: 'service2', }, }, - spanID: 'span4', - traceID: 'trace1', + spanID: 'span3', + traceID, }, { refType: 'CHILD_OF', span: { - spanID: 'span6', + spanID: 'span5', traceID: 'trace2', operationName: 'op2', process: { @@ -68,14 +69,12 @@ describe('', () => { data: references, highContrast: false, isOpen: false, - label: 'le-label', onToggle: jest.fn(), focusSpan: mockFocusSpan, }; beforeEach(() => { wrapper = shallow(); - mockFocusSpan.mockReset(); }); it('renders without exploding', () => { @@ -83,12 +82,6 @@ describe('', () => { expect(wrapper.exists()).toBe(true); }); - it('renders the label', () => { - const header = wrapper.find(`.AccordianReferences--header > strong`); - expect(header.length).toBe(1); - expect(header.text()).toBe(props.label); - }); - it('renders the content when it is expanded', () => { wrapper.setProps({ isOpen: true }); const content = wrapper.find(References); @@ -113,12 +106,18 @@ describe('', () => { }); it('render references list', () => { - expect(wrapper.find(ReferenceLink).length).toBe(references.length); - const spanOtherTrace = wrapper - .find('ReferenceLink') - .at(2) - .find('span.span-svc-name') - .text(); - expect(spanOtherTrace).toBe('< span in another trace >'); + const refLinks = wrapper.find(ReferenceLink); + expect(refLinks.length).toBe(references.length); + refLinks.forEach((refLink, i) => { + const span = references[i].span; + const serviceName = refLink.find('span.span-svc-name').text(); + if (span && span.traceID === traceID) { + const endpointName = refLink.find('small.endpoint-name').text(); + expect(serviceName).toBe(span.process.serviceName); + expect(endpointName).toBe(span.operationName); + } else { + expect(serviceName).toBe('< span in another trace >'); + } + }); }); }); diff --git a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/AccordianReferences.tsx b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/AccordianReferences.tsx index caa2354df6..015e6c81d3 100644 --- a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/AccordianReferences.tsx +++ b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/AccordianReferences.tsx @@ -16,19 +16,15 @@ import * as React from 'react'; import cx from 'classnames'; import IoIosArrowDown from 'react-icons/lib/io/ios-arrow-down'; import IoIosArrowRight from 'react-icons/lib/io/ios-arrow-right'; -import { TNil } from '../../../../types'; import './AccordianReferences.css'; import { SpanReference } from '../../../../types/trace'; import ReferenceLink from '../ReferenceLink'; type AccordianReferencesProps = { - className?: string | TNil; data: SpanReference[]; - headerClassName?: string | TNil; highContrast?: boolean; interactive?: boolean; isOpen: boolean; - label: React.ReactNode; onToggle?: null | (() => void); traceID: string; focusSpan: (uiFind: string) => void; @@ -50,33 +46,24 @@ export function References(props: ReferenceItemProps) { return (
  • - {reference.span && reference.traceID === traceID && ( - - {reference.span.process.serviceName} - {reference.span.operationName} - - - {reference.refType} - - - {reference.spanID} - - - - )} - {reference.traceID !== traceID && ( - + + {reference.span && reference.traceID === traceID ? ( + + {reference.span.process.serviceName} + {reference.span.operationName} + + ) : ( < span in another trace > - - - {reference.refType} - - - {reference.spanID} - - - - )} + )} + + + {reference.refType} + + + {reference.spanID} + + +
  • ); @@ -88,25 +75,13 @@ export function References(props: ReferenceItemProps) { export default class AccordianReferences extends React.PureComponent { static defaultProps = { - className: null, highContrast: false, interactive: true, onToggle: null, }; render() { - const { - className, - data, - headerClassName, - highContrast, - interactive, - isOpen, - label, - onToggle, - focusSpan, - traceID, - } = this.props; + const { data, highContrast, interactive, isOpen, onToggle, focusSpan, traceID } = this.props; const isEmpty = !Array.isArray(data) || !data.length; const iconCls = cx('u-align-icon', { 'AccordianKReferences--emptyIcon': isEmpty }); let arrow: React.ReactNode | null = null; @@ -120,9 +95,9 @@ export default class AccordianReferences extends React.PureComponent +
    {arrow} - {label} ({data.length}) + + References + {' '} + ({data.length})
    {isOpen && }
    diff --git a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/index.test.js b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/index.test.js index ace3f4fad4..50f08f6857 100644 --- a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/index.test.js +++ b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/index.test.js @@ -175,9 +175,9 @@ describe('', () => { }); it('renders the references', () => { - const warningElm = wrapper.find({ data: span.references }); - expect(warningElm.length).toBe(1); - warningElm.simulate('toggle'); + const refElem = wrapper.find({ data: span.references }); + expect(refElem.length).toBe(1); + refElem.simulate('toggle'); expect(props.referencesToggle).toHaveBeenLastCalledWith(span.spanID); }); diff --git a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/index.tsx b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/index.tsx index 60f65db352..c599aba89a 100644 --- a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/index.tsx +++ b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/index.tsx @@ -142,9 +142,6 @@ export default function SpanDetail(props: SpanDetailProps) { )} {references && references.length > 1 && ( References} data={references} isOpen={isReferencesOpen} onToggle={() => referencesToggle(spanID)} diff --git a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/VirtualizedTraceView.test.js b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/VirtualizedTraceView.test.js index df52d163e6..318fc18b3d 100644 --- a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/VirtualizedTraceView.test.js +++ b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/VirtualizedTraceView.test.js @@ -402,13 +402,13 @@ describe('', () => { }); describe('focusSpan', () => { - it('calls updateUiFind and focusUiFindMatches when focusSpan', () => { - focusUiFindMatchesMock.mockReset(); - instance.focusSpan('span1'); + it('calls updateUiFind and focusUiFindMatches', () => { + const spanName = 'span1'; + instance.focusSpan(spanName); expect(updateUiFindSpy).toHaveBeenLastCalledWith({ history: props.history, location: props.location, - uiFind: 'span1', + uiFind: spanName, }); }); }); diff --git a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/duck.tsx b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/duck.tsx index 773f4d73a1..cadc2dadb9 100644 --- a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/duck.tsx +++ b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/duck.tsx @@ -27,7 +27,7 @@ import spanAncestorIds from '../../../utils/span-ancestor-ids'; export type TSpanIdLogValue = { logItem: Log; spanID: string }; export type TSpanIdValue = { spanID: string }; type TSpansValue = { spans: Span[] }; -type TTraceUiFindValue = { trace: Trace; uiFind: string | TNil; preserveHiddenStatus?: boolean }; +type TTraceUiFindValue = { trace: Trace; uiFind: string | TNil; allowHide?: boolean }; export type TWidthValue = { width: number }; export type TActionTypes = | TSpanIdLogValue @@ -105,7 +105,7 @@ const fullActions = createActions({ export const actions = (fullActions as any).jaegerUi.traceTimelineViewer as TTimelineViewerActions; -function calculateFocusedFindRowStates(uiFind: string, spans: Span[], preserveHiddenStatus: boolean = false) { +function calculateFocusedFindRowStates(uiFind: string, spans: Span[], allowHide: boolean = true) { const spansMap = new Map(); const childrenHiddenIDs: Set = new Set(); const detailStates: Map = new Map(); @@ -113,7 +113,7 @@ function calculateFocusedFindRowStates(uiFind: string, spans: Span[], preserveHi spans.forEach(span => { spansMap.set(span.spanID, span); - if (!preserveHiddenStatus) { + if (allowHide) { childrenHiddenIDs.add(span.spanID); } }); @@ -133,14 +133,11 @@ function calculateFocusedFindRowStates(uiFind: string, spans: Span[], preserveHi }; } -function focusUiFindMatches( - state: TTraceTimeline, - { uiFind, trace, preserveHiddenStatus }: TTraceUiFindValue -) { +function focusUiFindMatches(state: TTraceTimeline, { uiFind, trace, allowHide }: TTraceUiFindValue) { if (!uiFind) return state; return { ...state, - ...calculateFocusedFindRowStates(uiFind, trace.spans, preserveHiddenStatus), + ...calculateFocusedFindRowStates(uiFind, trace.spans, allowHide), }; } diff --git a/packages/jaeger-ui/src/model/transform-trace-data.tsx b/packages/jaeger-ui/src/model/transform-trace-data.tsx index 00a27ea6be..a0e630cb27 100644 --- a/packages/jaeger-ui/src/model/transform-trace-data.tsx +++ b/packages/jaeger-ui/src/model/transform-trace-data.tsx @@ -118,8 +118,8 @@ export default function transformTraceData(data: TraceData & { spans: SpanData[] ref.span = refSpan; if (index > 0) { // Don't take into account the parent, just other references. - refSpan.referrals = refSpan.referrals || []; - refSpan.referrals.push({ + refSpan.subsidiarilyReferencedBy = refSpan.subsidiarilyReferencedBy || []; + refSpan.subsidiarilyReferencedBy.push({ spanID, traceID, span, diff --git a/packages/jaeger-ui/src/reducers/trace.test.js b/packages/jaeger-ui/src/reducers/trace.test.js index b481933bc6..352645dd04 100644 --- a/packages/jaeger-ui/src/reducers/trace.test.js +++ b/packages/jaeger-ui/src/reducers/trace.test.js @@ -115,24 +115,35 @@ describe('fetch multiple traces', () => { }); it('process multiple references', () => { - const multiRefTrace = traceGenerator.trace({ numberOfSpans: 6, maxDepth: 3, spansPerLevel: 4 }); - const parentID = multiRefTrace.spans[0].spanID; - const traceID = multiRefTrace.spans[0].traceID; - const noSiblingSpan = multiRefTrace.spans.filter( - span => span.references.length > 0 && span.references[0].spanID !== parentID + const multiRefTrace = traceGenerator.trace({ numberOfSpans: 7, maxDepth: 3, spansPerLevel: 4 }); + const { traceID, spanID: rootSpanId } = multiRefTrace.spans[0]; + const [willGainRef, willNotChange] = multiRefTrace.spans.filter( + span => span.references.length > 0 && span.references[0].spanID !== rootSpanId ); - const firstLevel = multiRefTrace.spans.filter( - span => span.references.length > 0 && span.references[0].spanID === parentID - ); - noSiblingSpan[0].references.push({ + const { spanID: existingRefID } = willGainRef.references[0]; + const { spanID: willBeReferencedID } = willNotChange.references[0]; + + willGainRef.references.push({ refType: 'CHILD_OF', traceID, - spanID: firstLevel[0].spanID, + spanID: willBeReferencedID, }); const tTrace = transformTraceData(multiRefTrace); - const multiRef = tTrace.spans.filter(span => span.referrals && span.referrals.length > 0); - expect(multiRef.length).toEqual(1); - expect(multiRef[0].spanID).toEqual(firstLevel[0].spanID); + const multiReference = tTrace.spans.filter(span => span.references && span.references.length > 1); + + expect(multiReference.length).toEqual(1); + expect(new Set(multiReference[0].references)).toEqual( + new Set([ + expect.objectContaining({ spanID: willBeReferencedID }), + expect.objectContaining({ spanID: existingRefID }), + ]) + ); + const hasReferral = tTrace.spans.filter( + span => span.subsidiarilyReferencedBy && span.subsidiarilyReferencedBy.length > 0 + ); + expect(new Set(hasReferral[0].subsidiarilyReferencedBy)).toEqual( + new Set([expect.objectContaining({ spanID: willGainRef.spanID })]) + ); }); }); diff --git a/packages/jaeger-ui/src/types/trace.tsx b/packages/jaeger-ui/src/types/trace.tsx index 4a299767f5..2b30b9b6f6 100644 --- a/packages/jaeger-ui/src/types/trace.tsx +++ b/packages/jaeger-ui/src/types/trace.tsx @@ -66,7 +66,7 @@ export type Span = SpanData & { tags: NonNullable; references: NonNullable; warnings: NonNullable; - referrals: Array; + subsidiarilyReferencedBy: Array; }; export type TraceData = { From b8b908b0acbe05a778d86b91be5ee15699e51092 Mon Sep 17 00:00:00 2001 From: Ruben Vargas Date: Wed, 11 Dec 2019 11:03:05 -0600 Subject: [PATCH 18/22] More improvements to tests ,css styles and some components Signed-off-by: Ruben Vargas --- .../ReferencesButton.test.js | 9 +---- .../TraceTimelineViewer/ReferencesButton.tsx | 2 +- .../SpanDetail/AccordianReferences.test.js | 15 +------- .../SpanDetail/AccordianReferences.tsx | 2 +- .../VirtualizedTraceView.tsx | 4 +- .../TracePage/TraceTimelineViewer/duck.tsx | 10 ++--- .../ReferenceLink.test.js | 0 .../ReferenceLink.tsx | 38 +++++++++---------- .../TracePage/{url.tsx => url/index.tsx} | 4 +- 9 files changed, 32 insertions(+), 52 deletions(-) rename packages/jaeger-ui/src/components/TracePage/{TraceTimelineViewer => url}/ReferenceLink.test.js (100%) rename packages/jaeger-ui/src/components/TracePage/{TraceTimelineViewer => url}/ReferenceLink.tsx (54%) rename packages/jaeger-ui/src/components/TracePage/{url.tsx => url/index.tsx} (90%) diff --git a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.test.js b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.test.js index 6e054ed24b..127b9c83c5 100644 --- a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.test.js +++ b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.test.js @@ -19,7 +19,7 @@ import { Menu, Dropdown, Tooltip } from 'antd'; import ReferencesButton from './ReferencesButton'; import transformTraceData from '../../../model/transform-trace-data'; import traceGenerator from '../../../demo/trace-generators'; -import ReferenceLink from './ReferenceLink'; +import ReferenceLink from '../url/ReferenceLink'; describe(ReferencesButton, () => { const trace = transformTraceData(traceGenerator.trace({ numberOfSpans: 10 })); @@ -33,13 +33,6 @@ describe(ReferencesButton, () => { spanID: trace.spans[2].spanID, }); const baseProps = { - uiFind: null, - history: { - replace: () => {}, - }, - location: { - search: null, - }, traceID: trace.traceID, trace: { data: trace, diff --git a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.tsx b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.tsx index adfd597875..904ee5ec37 100644 --- a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.tsx +++ b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.tsx @@ -18,7 +18,7 @@ import NewWindowIcon from '../../common/NewWindowIcon'; import { SpanReference } from '../../../types/trace'; import './ReferencesButton.css'; -import ReferenceLink from './ReferenceLink'; +import ReferenceLink from '../url/ReferenceLink'; type TReferencesButtonProps = { references: SpanReference[]; diff --git a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/AccordianReferences.test.js b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/AccordianReferences.test.js index f5f6e04d31..62f897c1fc 100644 --- a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/AccordianReferences.test.js +++ b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/AccordianReferences.test.js @@ -15,7 +15,7 @@ import React from 'react'; import { shallow } from 'enzyme'; import AccordianReferences, { References } from './AccordianReferences'; -import ReferenceLink from '../ReferenceLink'; +import ReferenceLink from '../../url/ReferenceLink'; const traceID = 'trace1'; const references = [ @@ -47,14 +47,6 @@ const references = [ }, { refType: 'CHILD_OF', - span: { - spanID: 'span5', - traceID: 'trace2', - operationName: 'op2', - process: { - serviceName: 'service2', - }, - }, spanID: 'span5', traceID: 'trace2', }, @@ -62,7 +54,6 @@ const references = [ describe('', () => { let wrapper; - const mockFocusSpan = jest.fn(); const props = { compact: false, @@ -70,7 +61,7 @@ describe('', () => { highContrast: false, isOpen: false, onToggle: jest.fn(), - focusSpan: mockFocusSpan, + focusSpan: jest.fn(), }; beforeEach(() => { @@ -92,7 +83,6 @@ describe('', () => { describe('', () => { let wrapper; - const mockFocusSpan = jest.fn(); const props = { data: references, @@ -102,7 +92,6 @@ describe('', () => { beforeEach(() => { wrapper = shallow(); - mockFocusSpan.mockReset(); }); it('render references list', () => { diff --git a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/AccordianReferences.tsx b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/AccordianReferences.tsx index 015e6c81d3..faed126ea4 100644 --- a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/AccordianReferences.tsx +++ b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/AccordianReferences.tsx @@ -18,7 +18,7 @@ import IoIosArrowDown from 'react-icons/lib/io/ios-arrow-down'; import IoIosArrowRight from 'react-icons/lib/io/ios-arrow-right'; import './AccordianReferences.css'; import { SpanReference } from '../../../../types/trace'; -import ReferenceLink from '../ReferenceLink'; +import ReferenceLink from '../../url/ReferenceLink'; type AccordianReferencesProps = { data: SpanReference[]; diff --git a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/VirtualizedTraceView.tsx b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/VirtualizedTraceView.tsx index 5525bfc4be..ddc65e2fe9 100644 --- a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/VirtualizedTraceView.tsx +++ b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/VirtualizedTraceView.tsx @@ -69,7 +69,7 @@ type TDispatchProps = { detailToggle: (spanID: string) => void; setSpanNameColumnWidth: (width: number) => void; setTrace: (trace: Trace | TNil, uiFind: string | TNil) => void; - focusUiFindMatches: (trace: Trace, uiFind: string | TNil, preserveHiddenStatus?: boolean) => void; + focusUiFindMatches: (trace: Trace, uiFind: string | TNil, allowHide?: boolean) => void; }; type VirtualizedTraceViewProps = TVirtualizedTraceViewOwnProps & @@ -231,7 +231,7 @@ export class VirtualizedTraceViewImpl extends React.Component({ [actionTypes.DETAIL_REFERENCES_TOGGLE]: (spanID: string) => ({ spanID }), [actionTypes.DETAIL_TAGS_TOGGLE]: (spanID: string) => ({ spanID }), [actionTypes.DETAIL_TOGGLE]: (spanID: string) => ({ spanID }), - [actionTypes.FOCUS_UI_FIND_MATCHES]: ( - trace: Trace, - uiFind: string | TNil, - preserveHiddenStatus?: boolean - ) => ({ trace, uiFind, preserveHiddenStatus }), + [actionTypes.FOCUS_UI_FIND_MATCHES]: (trace: Trace, uiFind: string | TNil, allowHide?: boolean) => ({ + trace, + uiFind, + allowHide, + }), [actionTypes.REMOVE_HOVER_INDENT_GUIDE_ID]: (spanID: string) => ({ spanID }), [actionTypes.SET_SPAN_NAME_COLUMN_WIDTH]: (width: number) => ({ width }), [actionTypes.SET_TRACE]: (trace: Trace, uiFind: string | TNil) => ({ trace, uiFind }), diff --git a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferenceLink.test.js b/packages/jaeger-ui/src/components/TracePage/url/ReferenceLink.test.js similarity index 100% rename from packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferenceLink.test.js rename to packages/jaeger-ui/src/components/TracePage/url/ReferenceLink.test.js diff --git a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferenceLink.tsx b/packages/jaeger-ui/src/components/TracePage/url/ReferenceLink.tsx similarity index 54% rename from packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferenceLink.tsx rename to packages/jaeger-ui/src/components/TracePage/url/ReferenceLink.tsx index 874d6cb7f2..7e42ba6f6e 100644 --- a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferenceLink.tsx +++ b/packages/jaeger-ui/src/components/TracePage/url/ReferenceLink.tsx @@ -14,7 +14,7 @@ import React from 'react'; import { SpanReference } from '../../../types/trace'; -import { getUrl } from '../url'; +import { getUrl } from '.'; type ReferenceLinkProps = { reference: SpanReference; @@ -25,29 +25,27 @@ type ReferenceLinkProps = { onClick?: () => void; }; -export default class ReferenceLink extends React.PureComponent { - linkToExternalSpan = (traceID: string, spanID: string) => `${getUrl(traceID)}/uiFind?=${spanID}`; +const linkToExternalSpan = (traceID: string, spanID: string) => `${getUrl(traceID)}/uiFind?=${spanID}`; - render() { - const { traceID, reference, children, className, focusSpan, ...otherProps } = this.props; - delete otherProps.onClick; - if (traceID === reference.traceID) { - return ( - focusSpan(reference.spanID)} className={className} {...otherProps}> - {children} - - ); - } +export default function ReferenceLink(props: ReferenceLinkProps) { + const { traceID, reference, children, className, focusSpan, ...otherProps } = props; + delete otherProps.onClick; + if (traceID === reference.traceID) { return ( - + focusSpan(reference.spanID)} className={className} {...otherProps}> {children} ); } + return ( + + {children} + + ); } diff --git a/packages/jaeger-ui/src/components/TracePage/url.tsx b/packages/jaeger-ui/src/components/TracePage/url/index.tsx similarity index 90% rename from packages/jaeger-ui/src/components/TracePage/url.tsx rename to packages/jaeger-ui/src/components/TracePage/url/index.tsx index 6f9b51929e..689d23167c 100644 --- a/packages/jaeger-ui/src/components/TracePage/url.tsx +++ b/packages/jaeger-ui/src/components/TracePage/url/index.tsx @@ -12,9 +12,9 @@ // See the License for the specific language governing permissions and // limitations under the License. -import prefixUrl from '../../utils/prefix-url'; +import prefixUrl from '../../../utils/prefix-url'; -import { TNil } from '../../types'; +import { TNil } from '../../../types'; export const ROUTE_PATH = prefixUrl('/trace/:id'); From b59b5e8c0e2a30d011c3ff93fa4ac572d6e5de75 Mon Sep 17 00:00:00 2001 From: Ruben Vargas Date: Wed, 11 Dec 2019 11:35:30 -0600 Subject: [PATCH 19/22] Fix license headers Signed-off-by: Ruben Vargas --- .../TracePage/TraceTimelineViewer/ReferencesButton.css | 2 +- .../TracePage/TraceTimelineViewer/ReferencesButton.test.js | 2 +- .../TracePage/TraceTimelineViewer/ReferencesButton.tsx | 2 +- .../TraceTimelineViewer/SpanDetail/AccordianReferences.css | 2 +- .../TraceTimelineViewer/SpanDetail/AccordianReferences.test.js | 2 +- .../TraceTimelineViewer/SpanDetail/AccordianReferences.tsx | 2 +- .../src/components/TracePage/url/ReferenceLink.test.js | 2 +- .../jaeger-ui/src/components/TracePage/url/ReferenceLink.tsx | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.css b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.css index 136bf1f015..10c17cbf36 100644 --- a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.css +++ b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.css @@ -1,5 +1,5 @@ /* -Copyright (c) 2019 Uber Technologies, Inc. +Copyright (c) 2019 The Jaeger Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.test.js b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.test.js index 127b9c83c5..539face26b 100644 --- a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.test.js +++ b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.test.js @@ -1,4 +1,4 @@ -// Copyright (c) 2019 Uber Technologies, Inc. +// Copyright (c) 2019 The Jaeger Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.tsx b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.tsx index 904ee5ec37..462b963611 100644 --- a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.tsx +++ b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.tsx @@ -1,4 +1,4 @@ -// Copyright (c) 2019 Uber Technologies, Inc. +// Copyright (c) 2019 The Jaeger Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/AccordianReferences.css b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/AccordianReferences.css index 10d8cda636..7a4931e9ac 100644 --- a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/AccordianReferences.css +++ b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/AccordianReferences.css @@ -1,5 +1,5 @@ /* -Copyright (c) 2019 Uber Technologies, Inc. +Copyright (c) 2019 The Jaeger Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/AccordianReferences.test.js b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/AccordianReferences.test.js index 62f897c1fc..f19f841279 100644 --- a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/AccordianReferences.test.js +++ b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/AccordianReferences.test.js @@ -1,4 +1,4 @@ -// Copyright (c) 2019 Uber Technologies, Inc. +// Copyright (c) 2019 The Jaeger Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/AccordianReferences.tsx b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/AccordianReferences.tsx index faed126ea4..21f5c3c17e 100644 --- a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/AccordianReferences.tsx +++ b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/AccordianReferences.tsx @@ -1,4 +1,4 @@ -// Copyright (c) 2019 Uber Technologies, Inc. +// Copyright (c) 2019 The Jaeger Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/packages/jaeger-ui/src/components/TracePage/url/ReferenceLink.test.js b/packages/jaeger-ui/src/components/TracePage/url/ReferenceLink.test.js index 893dc98056..7509bc4702 100644 --- a/packages/jaeger-ui/src/components/TracePage/url/ReferenceLink.test.js +++ b/packages/jaeger-ui/src/components/TracePage/url/ReferenceLink.test.js @@ -1,4 +1,4 @@ -// Copyright (c) 2019 Uber Technologies, Inc. +// Copyright (c) 2019 The Jaeger Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/packages/jaeger-ui/src/components/TracePage/url/ReferenceLink.tsx b/packages/jaeger-ui/src/components/TracePage/url/ReferenceLink.tsx index 7e42ba6f6e..e17c2c958c 100644 --- a/packages/jaeger-ui/src/components/TracePage/url/ReferenceLink.tsx +++ b/packages/jaeger-ui/src/components/TracePage/url/ReferenceLink.tsx @@ -1,4 +1,4 @@ -// Copyright (c) 2019 Uber Technologies, Inc. +// Copyright (c) 2019 The Jaeger Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. From 07237ef9dddd41c4aa6382c571f7574b03af8e25 Mon Sep 17 00:00:00 2001 From: Ruben Vargas Date: Wed, 11 Dec 2019 13:47:03 -0600 Subject: [PATCH 20/22] Add Reference rendering tests to SpanBarRow Signed-off-by: Ruben Vargas --- .../ReferencesButton.test.js | 30 +++++-- .../TraceTimelineViewer/SpanBarRow.test.js | 86 ++++++++++++++++++- 2 files changed, 109 insertions(+), 7 deletions(-) diff --git a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.test.js b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.test.js index 539face26b..59a4c3cb51 100644 --- a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.test.js +++ b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.test.js @@ -27,11 +27,22 @@ describe(ReferencesButton, () => { const oneReference = trace.spans[1].references; const moreReferences = oneReference.slice(); - moreReferences.push({ - refType: 'CHILD_OF', - traceID: trace.traceID, - spanID: trace.spans[2].spanID, - }); + const externalSpanID = 'extSpan'; + + moreReferences.push( + { + refType: 'CHILD_OF', + traceID: trace.traceID, + spanID: trace.spans[2].spanID, + span: trace.spans[2], + }, + { + refType: 'CHILD_OF', + traceID: 'otherTrace', + spanID: externalSpanID, + } + ); + const baseProps = { traceID: trace.traceID, trace: { @@ -62,9 +73,16 @@ describe(ReferencesButton, () => { expect(dropdown.length).toBe(1); const menuInstance = shallow(dropdown.first().props().overlay); const submenuItems = menuInstance.find(Menu.Item); - expect(submenuItems.length).toBe(2); + expect(submenuItems.length).toBe(3); submenuItems.forEach((submenuItem, i) => { expect(submenuItem.find(ReferenceLink).prop('reference')).toBe(moreReferences[i]); }); + expect( + submenuItems + .at(2) + .find(ReferenceLink) + .childAt(0) + .text() + ).toBe(`(another trace) - ${moreReferences[2].spanID}`); }); }); diff --git a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanBarRow.test.js b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanBarRow.test.js index 39cd5af596..f339653df8 100644 --- a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanBarRow.test.js +++ b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanBarRow.test.js @@ -13,10 +13,11 @@ // limitations under the License. import React from 'react'; -import { mount } from 'enzyme'; +import { mount, shallow } from 'enzyme'; import SpanBarRow from './SpanBarRow'; import SpanTreeOffset from './SpanTreeOffset'; +import ReferencesButton from './ReferencesButton'; jest.mock('./SpanTreeOffset'); @@ -78,4 +79,87 @@ describe('', () => { wrapper.find(SpanTreeOffset).prop('onClick')(); expect(onChildrenToggled.mock.calls).toEqual([[spanID]]); }); + + it('render references button', () => { + const span = Object.assign( + { + references: [ + { + refType: 'CHILD_OF', + traceID: 'trace1', + spanID: 'span0', + span: { + spanID: 'span0', + }, + }, + { + refType: 'CHILD_OF', + traceID: 'otherTrace', + spanID: 'span1', + span: { + spanID: 'span1', + }, + }, + ], + }, + props.span + ); + + const spanRow = shallow(); + const refButton = spanRow.find(ReferencesButton); + expect(refButton.length).toEqual(1); + expect(refButton.at(0).props().tooltipText).toEqual('Contains multiple references'); + }); + + it('render referenced to by single span', () => { + const span = Object.assign( + { + subsidiarilyReferencedBy: [ + { + refType: 'CHILD_OF', + traceID: 'trace1', + spanID: 'span0', + span: { + spanID: 'span0', + }, + }, + ], + }, + props.span + ); + const spanRow = shallow(); + const refButton = spanRow.find(ReferencesButton); + expect(refButton.length).toEqual(1); + expect(refButton.at(0).props().tooltipText).toEqual('This span is referenced by another span'); + }); + + it('render referenced to by multiple span', () => { + const span = Object.assign( + { + subsidiarilyReferencedBy: [ + { + refType: 'CHILD_OF', + traceID: 'trace1', + spanID: 'span0', + span: { + spanID: 'span0', + }, + }, + { + refType: 'CHILD_OF', + traceID: 'trace1', + spanID: 'span1', + span: { + spanID: 'span1', + }, + }, + ], + }, + props.span + ); + const spanRow = shallow(); + const refButton = spanRow.find(ReferencesButton); + expect(refButton.length).toEqual(1); + expect(refButton.at(0).props().tooltipText).toEqual('This span is referenced by multiple other spans'); + }); }); From c4d7b5bcfb0e5a0a6368ecc2ee8e99adb89d03ec Mon Sep 17 00:00:00 2001 From: Ruben Vargas Date: Thu, 12 Dec 2019 13:53:56 -0600 Subject: [PATCH 21/22] Small comments, improved tests and fix class names Signed-off-by: Ruben Vargas --- .../ReferencesButton.test.js | 5 ++- .../TraceTimelineViewer/ReferencesButton.tsx | 32 +++++++++---------- .../SpanDetail/AccordianReferences.tsx | 2 +- .../VirtualizedTraceView.test.js | 1 + 4 files changed, 19 insertions(+), 21 deletions(-) diff --git a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.test.js b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.test.js index 59a4c3cb51..8e4544d97e 100644 --- a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.test.js +++ b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.test.js @@ -23,7 +23,6 @@ import ReferenceLink from '../url/ReferenceLink'; describe(ReferencesButton, () => { const trace = transformTraceData(traceGenerator.trace({ numberOfSpans: 10 })); - const focusMock = jest.fn(); const oneReference = trace.spans[1].references; const moreReferences = oneReference.slice(); @@ -48,7 +47,7 @@ describe(ReferencesButton, () => { trace: { data: trace, }, - focusSpan: focusMock, + focusSpan: () => {}, }; it('renders single reference', () => { @@ -61,7 +60,7 @@ describe(ReferencesButton, () => { expect(dropdown.length).toBe(0); expect(refLink.length).toBe(1); expect(refLink.prop('reference')).toBe(oneReference[0]); - expect(refLink.first().props().className).toBe('multi-parent-button'); + expect(refLink.first().props().className).toBe('ReferencesButton-MultiParent'); expect(tooltip.length).toBe(1); expect(tooltip.prop('title')).toBe(props.tooltipText); }); diff --git a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.tsx b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.tsx index 462b963611..5f7031f8a0 100644 --- a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.tsx +++ b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.tsx @@ -14,6 +14,7 @@ import React from 'react'; import { Dropdown, Menu, Tooltip } from 'antd'; +import { TooltipPlacement } from 'antd/lib/tooltip'; import NewWindowIcon from '../../common/NewWindowIcon'; import { SpanReference } from '../../../types/trace'; @@ -32,7 +33,7 @@ export default class ReferencesButton extends React.PureComponent ( {references.map(ref => { - const { span, traceID, spanID } = ref; + const { span, spanID } = ref; return ( } + {!span && } ); @@ -54,15 +55,18 @@ export default class ReferencesButton extends React.PureComponent 1) { return ( - + {children} @@ -71,18 +75,12 @@ export default class ReferencesButton extends React.PureComponent + {children} diff --git a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/AccordianReferences.tsx b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/AccordianReferences.tsx index 21f5c3c17e..d000842c1c 100644 --- a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/AccordianReferences.tsx +++ b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/AccordianReferences.tsx @@ -47,7 +47,7 @@ export function References(props: ReferenceItemProps) {
  • - {reference.span && reference.traceID === traceID ? ( + {reference.span ? ( {reference.span.process.serviceName} {reference.span.operationName} diff --git a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/VirtualizedTraceView.test.js b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/VirtualizedTraceView.test.js index 318fc18b3d..d789c48b46 100644 --- a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/VirtualizedTraceView.test.js +++ b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/VirtualizedTraceView.test.js @@ -410,6 +410,7 @@ describe('', () => { location: props.location, uiFind: spanName, }); + expect(focusUiFindMatchesMock).toHaveBeenLastCalledWith(trace, spanName, false); }); }); }); From 24a3759b8c5469fa2d2ac7551c76964c71231753 Mon Sep 17 00:00:00 2001 From: Ruben Vargas Date: Thu, 12 Dec 2019 14:07:43 -0600 Subject: [PATCH 22/22] Unify criteria for externa/internal references for ReferenceLink and ReferencesButton components Signed-off-by: Ruben Vargas --- .../TraceTimelineViewer/ReferencesButton.test.js | 4 ---- .../TraceTimelineViewer/ReferencesButton.tsx | 9 +-------- .../TracePage/TraceTimelineViewer/SpanBarRow.tsx | 2 -- .../SpanDetail/AccordianReferences.test.js | 1 - .../SpanDetail/AccordianReferences.tsx | 11 +++++------ .../TraceTimelineViewer/SpanDetail/index.tsx | 1 - .../TracePage/url/ReferenceLink.test.js | 16 ++++++---------- .../components/TracePage/url/ReferenceLink.tsx | 5 ++--- 8 files changed, 14 insertions(+), 35 deletions(-) diff --git a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.test.js b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.test.js index 8e4544d97e..bf85d9b19b 100644 --- a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.test.js +++ b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.test.js @@ -43,10 +43,6 @@ describe(ReferencesButton, () => { ); const baseProps = { - traceID: trace.traceID, - trace: { - data: trace, - }, focusSpan: () => {}, }; diff --git a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.tsx b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.tsx index 5f7031f8a0..7525ebef48 100644 --- a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.tsx +++ b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ReferencesButton.tsx @@ -23,7 +23,6 @@ import ReferenceLink from '../url/ReferenceLink'; type TReferencesButtonProps = { references: SpanReference[]; - traceID: string; children: React.ReactNode; tooltipText: string; focusSpan: (spanID: string) => void; @@ -38,7 +37,6 @@ export default class ReferencesButton extends React.PureComponent @@ -76,12 +74,7 @@ export default class ReferencesButton extends React.PureComponent - + {children} diff --git a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanBarRow.tsx b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanBarRow.tsx index 283bf75c46..d9189c9123 100644 --- a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanBarRow.tsx +++ b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanBarRow.tsx @@ -157,7 +157,6 @@ export default class SpanBarRow extends React.PureComponent { {span.references && span.references.length > 1 && ( @@ -167,7 +166,6 @@ export default class SpanBarRow extends React.PureComponent { {span.subsidiarilyReferencedBy && span.subsidiarilyReferencedBy.length > 0 && ( ', () => { const props = { data: references, - traceID: 'trace1', focusSpan: jest.fn(), }; diff --git a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/AccordianReferences.tsx b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/AccordianReferences.tsx index d000842c1c..b4b2423b86 100644 --- a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/AccordianReferences.tsx +++ b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/AccordianReferences.tsx @@ -26,26 +26,25 @@ type AccordianReferencesProps = { interactive?: boolean; isOpen: boolean; onToggle?: null | (() => void); - traceID: string; focusSpan: (uiFind: string) => void; }; type ReferenceItemProps = { data: SpanReference[]; focusSpan: (uiFind: string) => void; - traceID: string; }; // export for test export function References(props: ReferenceItemProps) { - const { data, focusSpan, traceID } = props; + const { data, focusSpan } = props; + return (
      {data.map(reference => { return (
    • - + {reference.span ? ( @@ -81,7 +80,7 @@ export default class AccordianReferences extends React.PureComponent{' '} ({data.length})
    - {isOpen && } + {isOpen && } ); } diff --git a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/index.tsx b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/index.tsx index c599aba89a..f61282f680 100644 --- a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/index.tsx +++ b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/index.tsx @@ -145,7 +145,6 @@ export default function SpanDetail(props: SpanDetailProps) { data={references} isOpen={isReferencesOpen} onToggle={() => referencesToggle(spanID)} - traceID={span.traceID} focusSpan={focusSpan} /> )} diff --git a/packages/jaeger-ui/src/components/TracePage/url/ReferenceLink.test.js b/packages/jaeger-ui/src/components/TracePage/url/ReferenceLink.test.js index 7509bc4702..64e9980ef2 100644 --- a/packages/jaeger-ui/src/components/TracePage/url/ReferenceLink.test.js +++ b/packages/jaeger-ui/src/components/TracePage/url/ReferenceLink.test.js @@ -19,12 +19,14 @@ import ReferenceLink from './ReferenceLink'; describe(ReferenceLink, () => { const focusMock = jest.fn(); - const traceID = 'trace1'; const sameTraceRef = { refType: 'CHILD_OF', traceID: 'trace1', spanID: 'span1', + span: { + // not null or undefined is an indicator of an internal reference + }, }; const externalRef = { @@ -35,18 +37,14 @@ describe(ReferenceLink, () => { describe('rendering', () => { it('render for this trace', () => { - const component = shallow( - - ); + const component = shallow(); const link = component.find('a'); expect(link.length).toBe(1); expect(link.props().role).toBe('button'); }); it('render for external trace', () => { - const component = shallow( - - ); + const component = shallow(); const link = component.find('a[href="/trace/trace2/uiFind?=span2"]'); expect(link.length).toBe(1); }); @@ -54,9 +52,7 @@ describe(ReferenceLink, () => { describe('focus span', () => { it('call focusSpan', () => { focusMock.mockReset(); - const component = shallow( - - ); + const component = shallow(); const link = component.find('a'); link.simulate('click'); expect(focusMock).toHaveBeenLastCalledWith('span1'); diff --git a/packages/jaeger-ui/src/components/TracePage/url/ReferenceLink.tsx b/packages/jaeger-ui/src/components/TracePage/url/ReferenceLink.tsx index e17c2c958c..93cb551f09 100644 --- a/packages/jaeger-ui/src/components/TracePage/url/ReferenceLink.tsx +++ b/packages/jaeger-ui/src/components/TracePage/url/ReferenceLink.tsx @@ -18,7 +18,6 @@ import { getUrl } from '.'; type ReferenceLinkProps = { reference: SpanReference; - traceID: string; children: React.ReactNode; className?: string; focusSpan: (spanID: string) => void; @@ -28,9 +27,9 @@ type ReferenceLinkProps = { const linkToExternalSpan = (traceID: string, spanID: string) => `${getUrl(traceID)}/uiFind?=${spanID}`; export default function ReferenceLink(props: ReferenceLinkProps) { - const { traceID, reference, children, className, focusSpan, ...otherProps } = props; + const { reference, children, className, focusSpan, ...otherProps } = props; delete otherProps.onClick; - if (traceID === reference.traceID) { + if (reference.span) { return ( focusSpan(reference.spanID)} className={className} {...otherProps}> {children}