| 
									
										
										
										
											2020-04-02 19:34:16 +08:00
										 |  |  | // Copyright (c) 2017 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 { css } from 'emotion'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ListView from './ListView'; | 
					
						
							|  |  |  | import SpanBarRow from './SpanBarRow'; | 
					
						
							|  |  |  | import DetailState from './SpanDetail/DetailState'; | 
					
						
							|  |  |  | import SpanDetailRow from './SpanDetailRow'; | 
					
						
							|  |  |  | import { | 
					
						
							|  |  |  |   createViewedBoundsFunc, | 
					
						
							|  |  |  |   findServerChildSpan, | 
					
						
							|  |  |  |   isErrorSpan, | 
					
						
							|  |  |  |   spanContainsErredSpan, | 
					
						
							|  |  |  |   ViewedBoundsFunctionType, | 
					
						
							|  |  |  | } from './utils'; | 
					
						
							|  |  |  | import { Accessors } from '../ScrollManager'; | 
					
						
							| 
									
										
										
										
											2020-04-14 19:26:33 +08:00
										 |  |  | import { getColorByKey } from '../utils/color-generator'; | 
					
						
							| 
									
										
										
										
											2020-04-02 19:34:16 +08:00
										 |  |  | import { TNil } from '../types'; | 
					
						
							|  |  |  | import { Log, Span, Trace, KeyValuePair, Link } from '../types/trace'; | 
					
						
							|  |  |  | import TTraceTimeline from '../types/TTraceTimeline'; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-14 19:26:33 +08:00
										 |  |  | import { createStyle, Theme, withTheme } from '../Theme'; | 
					
						
							| 
									
										
										
										
											2020-04-02 19:34:16 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | type TExtractUiFindFromStateReturn = { | 
					
						
							|  |  |  |   uiFind: string | undefined; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const getStyles = createStyle(() => { | 
					
						
							|  |  |  |   return { | 
					
						
							|  |  |  |     rowsWrapper: css`
 | 
					
						
							|  |  |  |       width: 100%; | 
					
						
							|  |  |  |     `,
 | 
					
						
							|  |  |  |     row: css`
 | 
					
						
							|  |  |  |       width: 100%; | 
					
						
							|  |  |  |     `,
 | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type RowState = { | 
					
						
							|  |  |  |   isDetail: boolean; | 
					
						
							|  |  |  |   span: Span; | 
					
						
							|  |  |  |   spanIndex: number; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type TVirtualizedTraceViewOwnProps = { | 
					
						
							|  |  |  |   currentViewRangeTime: [number, number]; | 
					
						
							|  |  |  |   findMatchesIDs: Set<string> | TNil; | 
					
						
							|  |  |  |   scrollToFirstVisibleSpan: () => void; | 
					
						
							|  |  |  |   registerAccessors: (accesors: Accessors) => void; | 
					
						
							|  |  |  |   trace: Trace; | 
					
						
							|  |  |  |   focusSpan: (uiFind: string) => void; | 
					
						
							|  |  |  |   linksGetter: (span: Span, items: KeyValuePair[], itemIndex: number) => Link[]; | 
					
						
							|  |  |  |   childrenToggle: (spanID: string) => void; | 
					
						
							|  |  |  |   clearShouldScrollToFirstUiFindMatch: () => void; | 
					
						
							|  |  |  |   detailLogItemToggle: (spanID: string, log: Log) => 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; | 
					
						
							|  |  |  |   setSpanNameColumnWidth: (width: number) => void; | 
					
						
							|  |  |  |   setTrace: (trace: Trace | TNil, uiFind: string | TNil) => void; | 
					
						
							|  |  |  |   hoverIndentGuideIds: Set<string>; | 
					
						
							|  |  |  |   addHoverIndentGuideId: (spanID: string) => void; | 
					
						
							|  |  |  |   removeHoverIndentGuideId: (spanID: string) => void; | 
					
						
							| 
									
										
										
										
											2020-04-14 19:26:33 +08:00
										 |  |  |   theme: Theme; | 
					
						
							| 
									
										
										
										
											2020-04-02 19:34:16 +08:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type VirtualizedTraceViewProps = TVirtualizedTraceViewOwnProps & TExtractUiFindFromStateReturn & TTraceTimeline; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // export for tests
 | 
					
						
							|  |  |  | export const DEFAULT_HEIGHTS = { | 
					
						
							|  |  |  |   bar: 28, | 
					
						
							|  |  |  |   detail: 161, | 
					
						
							|  |  |  |   detailWithLogs: 197, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const NUM_TICKS = 5; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function generateRowStates( | 
					
						
							|  |  |  |   spans: Span[] | TNil, | 
					
						
							|  |  |  |   childrenHiddenIDs: Set<string>, | 
					
						
							|  |  |  |   detailStates: Map<string, DetailState | TNil> | 
					
						
							|  |  |  | ): RowState[] { | 
					
						
							|  |  |  |   if (!spans) { | 
					
						
							|  |  |  |     return []; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   let collapseDepth = null; | 
					
						
							|  |  |  |   const rowStates = []; | 
					
						
							|  |  |  |   for (let i = 0; i < spans.length; i++) { | 
					
						
							|  |  |  |     const span = spans[i]; | 
					
						
							|  |  |  |     const { spanID, depth } = span; | 
					
						
							|  |  |  |     let hidden = false; | 
					
						
							|  |  |  |     if (collapseDepth != null) { | 
					
						
							|  |  |  |       if (depth >= collapseDepth) { | 
					
						
							|  |  |  |         hidden = true; | 
					
						
							|  |  |  |       } else { | 
					
						
							|  |  |  |         collapseDepth = null; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (hidden) { | 
					
						
							|  |  |  |       continue; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (childrenHiddenIDs.has(spanID)) { | 
					
						
							|  |  |  |       collapseDepth = depth + 1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     rowStates.push({ | 
					
						
							|  |  |  |       span, | 
					
						
							|  |  |  |       isDetail: false, | 
					
						
							|  |  |  |       spanIndex: i, | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |     if (detailStates.has(spanID)) { | 
					
						
							|  |  |  |       rowStates.push({ | 
					
						
							|  |  |  |         span, | 
					
						
							|  |  |  |         isDetail: true, | 
					
						
							|  |  |  |         spanIndex: i, | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return rowStates; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function getClipping(currentViewRange: [number, number]) { | 
					
						
							|  |  |  |   const [zoomStart, zoomEnd] = currentViewRange; | 
					
						
							|  |  |  |   return { | 
					
						
							|  |  |  |     left: zoomStart > 0, | 
					
						
							|  |  |  |     right: zoomEnd < 1, | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // export from tests
 | 
					
						
							| 
									
										
										
										
											2020-04-14 19:26:33 +08:00
										 |  |  | export class UnthemedVirtualizedTraceView extends React.Component<VirtualizedTraceViewProps> { | 
					
						
							| 
									
										
										
										
											2020-04-02 19:34:16 +08:00
										 |  |  |   clipping: { left: boolean; right: boolean }; | 
					
						
							|  |  |  |   listView: ListView | TNil; | 
					
						
							|  |  |  |   rowStates: RowState[]; | 
					
						
							|  |  |  |   getViewedBounds: ViewedBoundsFunctionType; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   constructor(props: VirtualizedTraceViewProps) { | 
					
						
							|  |  |  |     super(props); | 
					
						
							|  |  |  |     // keep "prop derivations" on the instance instead of calculating in
 | 
					
						
							|  |  |  |     // `.render()` to avoid recalculating in every invocation of `.renderRow()`
 | 
					
						
							|  |  |  |     const { currentViewRangeTime, childrenHiddenIDs, detailStates, setTrace, trace, uiFind } = props; | 
					
						
							|  |  |  |     this.clipping = getClipping(currentViewRangeTime); | 
					
						
							|  |  |  |     const [zoomStart, zoomEnd] = currentViewRangeTime; | 
					
						
							|  |  |  |     this.getViewedBounds = createViewedBoundsFunc({ | 
					
						
							|  |  |  |       min: trace.startTime, | 
					
						
							|  |  |  |       max: trace.endTime, | 
					
						
							|  |  |  |       viewStart: zoomStart, | 
					
						
							|  |  |  |       viewEnd: zoomEnd, | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |     this.rowStates = generateRowStates(trace.spans, childrenHiddenIDs, detailStates); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     setTrace(trace, uiFind); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   shouldComponentUpdate(nextProps: VirtualizedTraceViewProps) { | 
					
						
							|  |  |  |     // If any prop updates, VirtualizedTraceViewImpl should update.
 | 
					
						
							|  |  |  |     const nextPropKeys = Object.keys(nextProps) as Array<keyof VirtualizedTraceViewProps>; | 
					
						
							|  |  |  |     for (let i = 0; i < nextPropKeys.length; i += 1) { | 
					
						
							|  |  |  |       if (nextProps[nextPropKeys[i]] !== this.props[nextPropKeys[i]]) { | 
					
						
							|  |  |  |         // Unless the only change was props.shouldScrollToFirstUiFindMatch changing to false.
 | 
					
						
							|  |  |  |         if (nextPropKeys[i] === 'shouldScrollToFirstUiFindMatch') { | 
					
						
							|  |  |  |           if (nextProps[nextPropKeys[i]]) { | 
					
						
							|  |  |  |             return true; | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |           return true; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return false; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   componentWillUpdate(nextProps: VirtualizedTraceViewProps) { | 
					
						
							|  |  |  |     const { childrenHiddenIDs, detailStates, registerAccessors, trace, currentViewRangeTime } = this.props; | 
					
						
							|  |  |  |     const { | 
					
						
							|  |  |  |       currentViewRangeTime: nextViewRangeTime, | 
					
						
							|  |  |  |       childrenHiddenIDs: nextHiddenIDs, | 
					
						
							|  |  |  |       detailStates: nextDetailStates, | 
					
						
							|  |  |  |       registerAccessors: nextRegisterAccessors, | 
					
						
							|  |  |  |       setTrace, | 
					
						
							|  |  |  |       trace: nextTrace, | 
					
						
							|  |  |  |       uiFind, | 
					
						
							|  |  |  |     } = nextProps; | 
					
						
							|  |  |  |     if (trace !== nextTrace) { | 
					
						
							|  |  |  |       setTrace(nextTrace, uiFind); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (trace !== nextTrace || childrenHiddenIDs !== nextHiddenIDs || detailStates !== nextDetailStates) { | 
					
						
							|  |  |  |       this.rowStates = nextTrace ? generateRowStates(nextTrace.spans, nextHiddenIDs, nextDetailStates) : []; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (currentViewRangeTime !== nextViewRangeTime) { | 
					
						
							|  |  |  |       this.clipping = getClipping(nextViewRangeTime); | 
					
						
							|  |  |  |       const [zoomStart, zoomEnd] = nextViewRangeTime; | 
					
						
							|  |  |  |       this.getViewedBounds = createViewedBoundsFunc({ | 
					
						
							|  |  |  |         min: trace.startTime, | 
					
						
							|  |  |  |         max: trace.endTime, | 
					
						
							|  |  |  |         viewStart: zoomStart, | 
					
						
							|  |  |  |         viewEnd: zoomEnd, | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (this.listView && registerAccessors !== nextRegisterAccessors) { | 
					
						
							|  |  |  |       nextRegisterAccessors(this.getAccessors()); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   componentDidUpdate() { | 
					
						
							|  |  |  |     const { | 
					
						
							|  |  |  |       shouldScrollToFirstUiFindMatch, | 
					
						
							|  |  |  |       clearShouldScrollToFirstUiFindMatch, | 
					
						
							|  |  |  |       scrollToFirstVisibleSpan, | 
					
						
							|  |  |  |     } = this.props; | 
					
						
							|  |  |  |     if (shouldScrollToFirstUiFindMatch) { | 
					
						
							|  |  |  |       scrollToFirstVisibleSpan(); | 
					
						
							|  |  |  |       clearShouldScrollToFirstUiFindMatch(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   getAccessors() { | 
					
						
							|  |  |  |     const lv = this.listView; | 
					
						
							|  |  |  |     if (!lv) { | 
					
						
							|  |  |  |       throw new Error('ListView unavailable'); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return { | 
					
						
							|  |  |  |       getViewRange: this.getViewRange, | 
					
						
							|  |  |  |       getSearchedSpanIDs: this.getSearchedSpanIDs, | 
					
						
							|  |  |  |       getCollapsedChildren: this.getCollapsedChildren, | 
					
						
							|  |  |  |       getViewHeight: lv.getViewHeight, | 
					
						
							|  |  |  |       getBottomRowIndexVisible: lv.getBottomVisibleIndex, | 
					
						
							|  |  |  |       getTopRowIndexVisible: lv.getTopVisibleIndex, | 
					
						
							|  |  |  |       getRowPosition: lv.getRowPosition, | 
					
						
							|  |  |  |       mapRowIndexToSpanIndex: this.mapRowIndexToSpanIndex, | 
					
						
							|  |  |  |       mapSpanIndexToRowIndex: this.mapSpanIndexToRowIndex, | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   getViewRange = () => this.props.currentViewRangeTime; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   getSearchedSpanIDs = () => this.props.findMatchesIDs; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   getCollapsedChildren = () => this.props.childrenHiddenIDs; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   mapRowIndexToSpanIndex = (index: number) => this.rowStates[index].spanIndex; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   mapSpanIndexToRowIndex = (index: number) => { | 
					
						
							|  |  |  |     const max = this.rowStates.length; | 
					
						
							|  |  |  |     for (let i = 0; i < max; i++) { | 
					
						
							|  |  |  |       const { spanIndex } = this.rowStates[i]; | 
					
						
							|  |  |  |       if (spanIndex === index) { | 
					
						
							|  |  |  |         return i; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     throw new Error(`unable to find row for span index: ${index}`); | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   setListView = (listView: ListView | TNil) => { | 
					
						
							|  |  |  |     const isChanged = this.listView !== listView; | 
					
						
							|  |  |  |     this.listView = listView; | 
					
						
							|  |  |  |     if (listView && isChanged) { | 
					
						
							|  |  |  |       this.props.registerAccessors(this.getAccessors()); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // use long form syntax to avert flow error
 | 
					
						
							|  |  |  |   // https://github.com/facebook/flow/issues/3076#issuecomment-290944051
 | 
					
						
							|  |  |  |   getKeyFromIndex = (index: number) => { | 
					
						
							|  |  |  |     const { isDetail, span } = this.rowStates[index]; | 
					
						
							|  |  |  |     return `${span.spanID}--${isDetail ? 'detail' : 'bar'}`; | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   getIndexFromKey = (key: string) => { | 
					
						
							|  |  |  |     const parts = key.split('--'); | 
					
						
							|  |  |  |     const _spanID = parts[0]; | 
					
						
							|  |  |  |     const _isDetail = parts[1] === 'detail'; | 
					
						
							|  |  |  |     const max = this.rowStates.length; | 
					
						
							|  |  |  |     for (let i = 0; i < max; i++) { | 
					
						
							|  |  |  |       const { span, isDetail } = this.rowStates[i]; | 
					
						
							|  |  |  |       if (span.spanID === _spanID && isDetail === _isDetail) { | 
					
						
							|  |  |  |         return i; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return -1; | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   getRowHeight = (index: number) => { | 
					
						
							|  |  |  |     const { span, isDetail } = this.rowStates[index]; | 
					
						
							|  |  |  |     if (!isDetail) { | 
					
						
							|  |  |  |       return DEFAULT_HEIGHTS.bar; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (Array.isArray(span.logs) && span.logs.length) { | 
					
						
							|  |  |  |       return DEFAULT_HEIGHTS.detailWithLogs; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return DEFAULT_HEIGHTS.detail; | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   renderRow = (key: string, style: React.CSSProperties, index: number, attrs: {}) => { | 
					
						
							|  |  |  |     const { isDetail, span, spanIndex } = this.rowStates[index]; | 
					
						
							|  |  |  |     return isDetail | 
					
						
							|  |  |  |       ? this.renderSpanDetailRow(span, key, style, attrs) | 
					
						
							|  |  |  |       : this.renderSpanBarRow(span, spanIndex, key, style, attrs); | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   renderSpanBarRow(span: Span, spanIndex: number, key: string, style: React.CSSProperties, attrs: {}) { | 
					
						
							|  |  |  |     const { spanID } = span; | 
					
						
							|  |  |  |     const { serviceName } = span.process; | 
					
						
							|  |  |  |     const { | 
					
						
							|  |  |  |       childrenHiddenIDs, | 
					
						
							|  |  |  |       childrenToggle, | 
					
						
							|  |  |  |       detailStates, | 
					
						
							|  |  |  |       detailToggle, | 
					
						
							|  |  |  |       findMatchesIDs, | 
					
						
							|  |  |  |       spanNameColumnWidth, | 
					
						
							|  |  |  |       trace, | 
					
						
							|  |  |  |       focusSpan, | 
					
						
							|  |  |  |       hoverIndentGuideIds, | 
					
						
							|  |  |  |       addHoverIndentGuideId, | 
					
						
							|  |  |  |       removeHoverIndentGuideId, | 
					
						
							| 
									
										
										
										
											2020-04-14 19:26:33 +08:00
										 |  |  |       theme, | 
					
						
							| 
									
										
										
										
											2020-04-02 19:34:16 +08:00
										 |  |  |     } = this.props; | 
					
						
							|  |  |  |     // to avert flow error
 | 
					
						
							|  |  |  |     if (!trace) { | 
					
						
							|  |  |  |       return null; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-04-14 19:26:33 +08:00
										 |  |  |     const color = getColorByKey(serviceName, theme); | 
					
						
							| 
									
										
										
										
											2020-04-02 19:34:16 +08:00
										 |  |  |     const isCollapsed = childrenHiddenIDs.has(spanID); | 
					
						
							|  |  |  |     const isDetailExpanded = detailStates.has(spanID); | 
					
						
							|  |  |  |     const isMatchingFilter = findMatchesIDs ? findMatchesIDs.has(spanID) : false; | 
					
						
							|  |  |  |     const showErrorIcon = isErrorSpan(span) || (isCollapsed && spanContainsErredSpan(trace.spans, spanIndex)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Check for direct child "server" span if the span is a "client" span.
 | 
					
						
							|  |  |  |     let rpc = null; | 
					
						
							|  |  |  |     if (isCollapsed) { | 
					
						
							|  |  |  |       const rpcSpan = findServerChildSpan(trace.spans.slice(spanIndex)); | 
					
						
							|  |  |  |       if (rpcSpan) { | 
					
						
							|  |  |  |         const rpcViewBounds = this.getViewedBounds(rpcSpan.startTime, rpcSpan.startTime + rpcSpan.duration); | 
					
						
							|  |  |  |         rpc = { | 
					
						
							| 
									
										
										
										
											2020-04-14 19:26:33 +08:00
										 |  |  |           color: getColorByKey(rpcSpan.process.serviceName, theme), | 
					
						
							| 
									
										
										
										
											2020-04-02 19:34:16 +08:00
										 |  |  |           operationName: rpcSpan.operationName, | 
					
						
							|  |  |  |           serviceName: rpcSpan.process.serviceName, | 
					
						
							|  |  |  |           viewEnd: rpcViewBounds.end, | 
					
						
							|  |  |  |           viewStart: rpcViewBounds.start, | 
					
						
							|  |  |  |         }; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     const styles = getStyles(); | 
					
						
							|  |  |  |     return ( | 
					
						
							|  |  |  |       <div className={styles.row} key={key} style={style} {...attrs}> | 
					
						
							|  |  |  |         <SpanBarRow | 
					
						
							|  |  |  |           clippingLeft={this.clipping.left} | 
					
						
							|  |  |  |           clippingRight={this.clipping.right} | 
					
						
							|  |  |  |           color={color} | 
					
						
							|  |  |  |           columnDivision={spanNameColumnWidth} | 
					
						
							|  |  |  |           isChildrenExpanded={!isCollapsed} | 
					
						
							|  |  |  |           isDetailExpanded={isDetailExpanded} | 
					
						
							|  |  |  |           isMatchingFilter={isMatchingFilter} | 
					
						
							|  |  |  |           numTicks={NUM_TICKS} | 
					
						
							|  |  |  |           onDetailToggled={detailToggle} | 
					
						
							|  |  |  |           onChildrenToggled={childrenToggle} | 
					
						
							|  |  |  |           rpc={rpc} | 
					
						
							|  |  |  |           showErrorIcon={showErrorIcon} | 
					
						
							|  |  |  |           getViewedBounds={this.getViewedBounds} | 
					
						
							|  |  |  |           traceStartTime={trace.startTime} | 
					
						
							|  |  |  |           span={span} | 
					
						
							|  |  |  |           focusSpan={focusSpan} | 
					
						
							|  |  |  |           hoverIndentGuideIds={hoverIndentGuideIds} | 
					
						
							|  |  |  |           addHoverIndentGuideId={addHoverIndentGuideId} | 
					
						
							|  |  |  |           removeHoverIndentGuideId={removeHoverIndentGuideId} | 
					
						
							|  |  |  |         /> | 
					
						
							|  |  |  |       </div> | 
					
						
							|  |  |  |     ); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   renderSpanDetailRow(span: Span, key: string, style: React.CSSProperties, attrs: {}) { | 
					
						
							|  |  |  |     const { spanID } = span; | 
					
						
							|  |  |  |     const { serviceName } = span.process; | 
					
						
							|  |  |  |     const { | 
					
						
							|  |  |  |       detailLogItemToggle, | 
					
						
							|  |  |  |       detailLogsToggle, | 
					
						
							|  |  |  |       detailProcessToggle, | 
					
						
							|  |  |  |       detailReferencesToggle, | 
					
						
							|  |  |  |       detailWarningsToggle, | 
					
						
							|  |  |  |       detailStates, | 
					
						
							|  |  |  |       detailTagsToggle, | 
					
						
							|  |  |  |       detailToggle, | 
					
						
							|  |  |  |       spanNameColumnWidth, | 
					
						
							|  |  |  |       trace, | 
					
						
							|  |  |  |       focusSpan, | 
					
						
							|  |  |  |       hoverIndentGuideIds, | 
					
						
							|  |  |  |       addHoverIndentGuideId, | 
					
						
							|  |  |  |       removeHoverIndentGuideId, | 
					
						
							|  |  |  |       linksGetter, | 
					
						
							| 
									
										
										
										
											2020-04-14 19:26:33 +08:00
										 |  |  |       theme, | 
					
						
							| 
									
										
										
										
											2020-04-02 19:34:16 +08:00
										 |  |  |     } = this.props; | 
					
						
							|  |  |  |     const detailState = detailStates.get(spanID); | 
					
						
							|  |  |  |     if (!trace || !detailState) { | 
					
						
							|  |  |  |       return null; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-04-14 19:26:33 +08:00
										 |  |  |     const color = getColorByKey(serviceName, theme); | 
					
						
							| 
									
										
										
										
											2020-04-02 19:34:16 +08:00
										 |  |  |     const styles = getStyles(); | 
					
						
							|  |  |  |     return ( | 
					
						
							|  |  |  |       <div className={styles.row} key={key} style={{ ...style, zIndex: 1 }} {...attrs}> | 
					
						
							|  |  |  |         <SpanDetailRow | 
					
						
							|  |  |  |           color={color} | 
					
						
							|  |  |  |           columnDivision={spanNameColumnWidth} | 
					
						
							|  |  |  |           onDetailToggled={detailToggle} | 
					
						
							|  |  |  |           detailState={detailState} | 
					
						
							|  |  |  |           linksGetter={linksGetter} | 
					
						
							|  |  |  |           logItemToggle={detailLogItemToggle} | 
					
						
							|  |  |  |           logsToggle={detailLogsToggle} | 
					
						
							|  |  |  |           processToggle={detailProcessToggle} | 
					
						
							|  |  |  |           referencesToggle={detailReferencesToggle} | 
					
						
							|  |  |  |           warningsToggle={detailWarningsToggle} | 
					
						
							|  |  |  |           span={span} | 
					
						
							|  |  |  |           tagsToggle={detailTagsToggle} | 
					
						
							|  |  |  |           traceStartTime={trace.startTime} | 
					
						
							|  |  |  |           focusSpan={focusSpan} | 
					
						
							|  |  |  |           hoverIndentGuideIds={hoverIndentGuideIds} | 
					
						
							|  |  |  |           addHoverIndentGuideId={addHoverIndentGuideId} | 
					
						
							|  |  |  |           removeHoverIndentGuideId={removeHoverIndentGuideId} | 
					
						
							|  |  |  |         /> | 
					
						
							|  |  |  |       </div> | 
					
						
							|  |  |  |     ); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   render() { | 
					
						
							|  |  |  |     const styles = getStyles(); | 
					
						
							|  |  |  |     return ( | 
					
						
							|  |  |  |       <div> | 
					
						
							|  |  |  |         <ListView | 
					
						
							|  |  |  |           ref={this.setListView} | 
					
						
							|  |  |  |           dataLength={this.rowStates.length} | 
					
						
							|  |  |  |           itemHeightGetter={this.getRowHeight} | 
					
						
							|  |  |  |           itemRenderer={this.renderRow} | 
					
						
							|  |  |  |           viewBuffer={300} | 
					
						
							|  |  |  |           viewBufferMin={100} | 
					
						
							|  |  |  |           itemsWrapperClassName={styles.rowsWrapper} | 
					
						
							|  |  |  |           getKeyFromIndex={this.getKeyFromIndex} | 
					
						
							|  |  |  |           getIndexFromKey={this.getIndexFromKey} | 
					
						
							|  |  |  |           windowScroller | 
					
						
							|  |  |  |         /> | 
					
						
							|  |  |  |       </div> | 
					
						
							|  |  |  |     ); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2020-04-14 19:26:33 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | export default withTheme(UnthemedVirtualizedTraceView); |