|
|
|
@@ -15,6 +15,8 @@
|
|
|
|
|
import * as React from 'react';
|
|
|
|
|
import { css } from '@emotion/css';
|
|
|
|
|
|
|
|
|
|
import { isEqual } from 'lodash';
|
|
|
|
|
import memoizeOne from 'memoize-one';
|
|
|
|
|
import ListView from './ListView';
|
|
|
|
|
import SpanBarRow from './SpanBarRow';
|
|
|
|
|
import DetailState from './SpanDetail/DetailState';
|
|
|
|
@@ -148,28 +150,25 @@ function getClipping(currentViewRange: [number, number]) {
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function generateRowStatesFromTrace(
|
|
|
|
|
trace: Trace | TNil,
|
|
|
|
|
childrenHiddenIDs: Set<string>,
|
|
|
|
|
detailStates: Map<string, DetailState | TNil>
|
|
|
|
|
): RowState[] {
|
|
|
|
|
return trace ? generateRowStates(trace.spans, childrenHiddenIDs, detailStates) : [];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const memoizedGenerateRowStates = memoizeOne(generateRowStatesFromTrace);
|
|
|
|
|
const memoizedViewBoundsFunc = memoizeOne(createViewedBoundsFunc, isEqual);
|
|
|
|
|
const memoizedGetClipping = memoizeOne(getClipping, isEqual);
|
|
|
|
|
|
|
|
|
|
// export from tests
|
|
|
|
|
export class UnthemedVirtualizedTraceView extends React.Component<VirtualizedTraceViewProps> {
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
|
|
const { setTrace, trace, uiFind } = props;
|
|
|
|
|
setTrace(trace, uiFind);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -191,50 +190,54 @@ export class UnthemedVirtualizedTraceView extends React.Component<VirtualizedTra
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
UNSAFE_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 || (trace !== nextTrace && nextTrace)) {
|
|
|
|
|
this.clipping = getClipping(nextViewRangeTime);
|
|
|
|
|
const [zoomStart, zoomEnd] = nextViewRangeTime;
|
|
|
|
|
this.getViewedBounds = createViewedBoundsFunc({
|
|
|
|
|
min: nextTrace.startTime,
|
|
|
|
|
max: nextTrace.endTime,
|
|
|
|
|
viewStart: zoomStart,
|
|
|
|
|
viewEnd: zoomEnd,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
if (this.listView && registerAccessors !== nextRegisterAccessors) {
|
|
|
|
|
nextRegisterAccessors(this.getAccessors());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
componentDidUpdate() {
|
|
|
|
|
componentDidUpdate(prevProps: Readonly<VirtualizedTraceViewProps>) {
|
|
|
|
|
const { registerAccessors, trace } = prevProps;
|
|
|
|
|
const {
|
|
|
|
|
shouldScrollToFirstUiFindMatch,
|
|
|
|
|
clearShouldScrollToFirstUiFindMatch,
|
|
|
|
|
scrollToFirstVisibleSpan,
|
|
|
|
|
registerAccessors: nextRegisterAccessors,
|
|
|
|
|
setTrace,
|
|
|
|
|
trace: nextTrace,
|
|
|
|
|
uiFind,
|
|
|
|
|
} = this.props;
|
|
|
|
|
|
|
|
|
|
if (trace !== nextTrace) {
|
|
|
|
|
setTrace(nextTrace, uiFind);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (this.listView && registerAccessors !== nextRegisterAccessors) {
|
|
|
|
|
nextRegisterAccessors(this.getAccessors());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (shouldScrollToFirstUiFindMatch) {
|
|
|
|
|
scrollToFirstVisibleSpan();
|
|
|
|
|
clearShouldScrollToFirstUiFindMatch();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
getRowStates(): RowState[] {
|
|
|
|
|
const { childrenHiddenIDs, detailStates, trace } = this.props;
|
|
|
|
|
return memoizedGenerateRowStates(trace, childrenHiddenIDs, detailStates);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
getClipping(): { left: boolean; right: boolean } {
|
|
|
|
|
const { currentViewRangeTime } = this.props;
|
|
|
|
|
return memoizedGetClipping(currentViewRangeTime);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
getViewedBounds(): ViewedBoundsFunctionType {
|
|
|
|
|
const { currentViewRangeTime, trace } = this.props;
|
|
|
|
|
const [zoomStart, zoomEnd] = currentViewRangeTime;
|
|
|
|
|
|
|
|
|
|
return memoizedViewBoundsFunc({
|
|
|
|
|
min: trace.startTime,
|
|
|
|
|
max: trace.endTime,
|
|
|
|
|
viewStart: zoomStart,
|
|
|
|
|
viewEnd: zoomEnd,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
getAccessors() {
|
|
|
|
|
const lv = this.listView;
|
|
|
|
|
if (!lv) {
|
|
|
|
@@ -259,12 +262,12 @@ export class UnthemedVirtualizedTraceView extends React.Component<VirtualizedTra
|
|
|
|
|
|
|
|
|
|
getCollapsedChildren = () => this.props.childrenHiddenIDs;
|
|
|
|
|
|
|
|
|
|
mapRowIndexToSpanIndex = (index: number) => this.rowStates[index].spanIndex;
|
|
|
|
|
mapRowIndexToSpanIndex = (index: number) => this.getRowStates()[index].spanIndex;
|
|
|
|
|
|
|
|
|
|
mapSpanIndexToRowIndex = (index: number) => {
|
|
|
|
|
const max = this.rowStates.length;
|
|
|
|
|
const max = this.getRowStates().length;
|
|
|
|
|
for (let i = 0; i < max; i++) {
|
|
|
|
|
const { spanIndex } = this.rowStates[i];
|
|
|
|
|
const { spanIndex } = this.getRowStates()[i];
|
|
|
|
|
if (spanIndex === index) {
|
|
|
|
|
return i;
|
|
|
|
|
}
|
|
|
|
@@ -283,7 +286,7 @@ export class UnthemedVirtualizedTraceView extends React.Component<VirtualizedTra
|
|
|
|
|
// 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];
|
|
|
|
|
const { isDetail, span } = this.getRowStates()[index];
|
|
|
|
|
return `${span.spanID}--${isDetail ? 'detail' : 'bar'}`;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
@@ -291,9 +294,9 @@ export class UnthemedVirtualizedTraceView extends React.Component<VirtualizedTra
|
|
|
|
|
const parts = key.split('--');
|
|
|
|
|
const _spanID = parts[0];
|
|
|
|
|
const _isDetail = parts[1] === 'detail';
|
|
|
|
|
const max = this.rowStates.length;
|
|
|
|
|
const max = this.getRowStates().length;
|
|
|
|
|
for (let i = 0; i < max; i++) {
|
|
|
|
|
const { span, isDetail } = this.rowStates[i];
|
|
|
|
|
const { span, isDetail } = this.getRowStates()[i];
|
|
|
|
|
if (span.spanID === _spanID && isDetail === _isDetail) {
|
|
|
|
|
return i;
|
|
|
|
|
}
|
|
|
|
@@ -302,7 +305,7 @@ export class UnthemedVirtualizedTraceView extends React.Component<VirtualizedTra
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
getRowHeight = (index: number) => {
|
|
|
|
|
const { span, isDetail } = this.rowStates[index];
|
|
|
|
|
const { span, isDetail } = this.getRowStates()[index];
|
|
|
|
|
if (!isDetail) {
|
|
|
|
|
return DEFAULT_HEIGHTS.bar;
|
|
|
|
|
}
|
|
|
|
@@ -313,7 +316,7 @@ export class UnthemedVirtualizedTraceView extends React.Component<VirtualizedTra
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
renderRow = (key: string, style: React.CSSProperties, index: number, attrs: {}) => {
|
|
|
|
|
const { isDetail, span, spanIndex } = this.rowStates[index];
|
|
|
|
|
const { isDetail, span, spanIndex } = this.getRowStates()[index];
|
|
|
|
|
return isDetail
|
|
|
|
|
? this.renderSpanDetailRow(span, key, style, attrs)
|
|
|
|
|
: this.renderSpanBarRow(span, spanIndex, key, style, attrs);
|
|
|
|
@@ -352,7 +355,7 @@ export class UnthemedVirtualizedTraceView extends React.Component<VirtualizedTra
|
|
|
|
|
if (isCollapsed) {
|
|
|
|
|
const rpcSpan = findServerChildSpan(trace.spans.slice(spanIndex));
|
|
|
|
|
if (rpcSpan) {
|
|
|
|
|
const rpcViewBounds = this.getViewedBounds(rpcSpan.startTime, rpcSpan.startTime + rpcSpan.duration);
|
|
|
|
|
const rpcViewBounds = this.getViewedBounds()(rpcSpan.startTime, rpcSpan.startTime + rpcSpan.duration);
|
|
|
|
|
rpc = {
|
|
|
|
|
color: getColorByKey(rpcSpan.process.serviceName, theme),
|
|
|
|
|
operationName: rpcSpan.operationName,
|
|
|
|
@@ -378,8 +381,8 @@ export class UnthemedVirtualizedTraceView extends React.Component<VirtualizedTra
|
|
|
|
|
return (
|
|
|
|
|
<div className={styles.row} key={key} style={style} {...attrs}>
|
|
|
|
|
<SpanBarRow
|
|
|
|
|
clippingLeft={this.clipping.left}
|
|
|
|
|
clippingRight={this.clipping.right}
|
|
|
|
|
clippingLeft={this.getClipping().left}
|
|
|
|
|
clippingRight={this.getClipping().right}
|
|
|
|
|
color={color}
|
|
|
|
|
columnDivision={spanNameColumnWidth}
|
|
|
|
|
isChildrenExpanded={!isCollapsed}
|
|
|
|
@@ -391,7 +394,7 @@ export class UnthemedVirtualizedTraceView extends React.Component<VirtualizedTra
|
|
|
|
|
rpc={rpc}
|
|
|
|
|
noInstrumentedServer={noInstrumentedServer}
|
|
|
|
|
showErrorIcon={showErrorIcon}
|
|
|
|
|
getViewedBounds={this.getViewedBounds}
|
|
|
|
|
getViewedBounds={this.getViewedBounds()}
|
|
|
|
|
traceStartTime={trace.startTime}
|
|
|
|
|
span={span}
|
|
|
|
|
focusSpan={focusSpan}
|
|
|
|
@@ -467,7 +470,7 @@ export class UnthemedVirtualizedTraceView extends React.Component<VirtualizedTra
|
|
|
|
|
<div>
|
|
|
|
|
<ListView
|
|
|
|
|
ref={this.setListView}
|
|
|
|
|
dataLength={this.rowStates.length}
|
|
|
|
|
dataLength={this.getRowStates().length}
|
|
|
|
|
itemHeightGetter={this.getRowHeight}
|
|
|
|
|
itemRenderer={this.renderRow}
|
|
|
|
|
viewBuffer={50}
|
|
|
|
|