187 lines
4.5 KiB
TypeScript
Raw Normal View History

Fe: Feat/trace detail (#764) * feat: new trace detail page flame graph * feat: new trace detail page layout * test: trace detail is wip * chore: trace details in wip * feat: trace detail page timeline component * chore: spantoTree is updated * chore: gantchart is updated * chore: onClick is added * chore: isSpanPresentInSearchString util is added * chore: trace graph is updated * chore: added the hack to work * feat: is span present util is added * chore: in span ms is added * chore: tooltip is updated * WIP: chore: trace details changes are updated * feat: getTraceItem is added * feat: trace detail page is updated * feat: trace detail styling changes * feat: trace detail page is updated * feat: implement span hover, select, focus and reset * feat: reset focus * feat: spanId as query table and unfurling * feat: trace details is updated * chore: remove lodash * chore: remove lodash * feat: trace details is updated * feat: new trace detail page styling changes * feat: new trace detail page styling changes * feat: improved styling * feat: remove horizontal scrolling * feat: new trace detail page modify caret icon * chore styles are updated * Revert "chore: Trace styles" * chore styles are updated * feat: timeline normalisation * chore: remove mock data * chore: sort tree data util is added and selected span component is updated * chore: trace changes are updated * chore: trace changes are updated * chore: trace changes are updated * feat: refactored time units for new trace detail page * chore: remove mockdata * feat: new trace detail page themeing and interval loop fix * chore: error tag is updated * chore: error tag is updated * chore: error tag is updated * chore: error tag is updated * chore: console is removed * fix: error tag expand button * chore: expanded panel is updated * feat: scroll span from gantt chart intoview * chore: trace detail is removed Co-authored-by: Pranshu Chittora <pranshu@signoz.io>
2022-03-03 19:04:23 +05:30
import React, { useRef, useState, useEffect } from 'react';
import {
CardComponent,
CardContainer,
CaretContainer,
Wrapper,
HoverCard,
} from './styles';
import { CaretDownFilled, CaretRightFilled } from '@ant-design/icons';
import SpanLength from '../SpanLength';
import SpanName from '../SpanName';
import { pushDStree } from 'store/actions';
import { getMetaDataFromSpanTree, getTopLeftFromBody } from '../utils';
import { ITraceMetaData } from '..';
import { Col, Row } from 'antd';
import { SPAN_DETAILS_LEFT_COL_WIDTH } from 'pages/TraceDetail/constants'
import { IIntervalUnit, resolveTimeFromInterval } from 'container/TraceDetail/utils';
import useThemeMode from 'hooks/useThemeMode';
const Trace = (props: TraceProps): JSX.Element => {
const {
name,
activeHoverId,
setActiveHoverId,
globalSpread,
globalStart,
serviceName,
startTime,
value,
serviceColour,
id,
setActiveSelectedId,
activeSelectedId,
level,
activeSpanPath,
isExpandAll,
intervalUnit,
} = props;
const { isDarkMode } = useThemeMode()
const [isOpen, setOpen] = useState<boolean>(activeSpanPath[level] === id);
useEffect(() => {
if (!isOpen) {
setOpen(activeSpanPath[level] === id)
}
}, [activeSpanPath, isOpen])
useEffect(() => {
if (isExpandAll) {
setOpen(isExpandAll)
}
else {
setOpen(activeSpanPath[level] === id)
}
}, [isExpandAll])
const isOnlyChild = props.children.length === 1;
const [top, setTop] = useState<number>(0);
const ref = useRef<HTMLUListElement>(null);
React.useEffect(() => {
if (activeSelectedId === id) {
ref.current?.scrollIntoView({ block: 'nearest', behavior: 'auto', inline: 'nearest' });
}
}, [activeSelectedId])
const onMouseEnterHandler = () => {
setActiveHoverId(props.id);
if (ref.current) {
const { top } = getTopLeftFromBody(ref.current);
setTop(top);
}
};
const onMouseLeaveHandler = () => {
setActiveHoverId('');
};
const onClick = () => {
setActiveSelectedId(id);
}
const { totalSpans } = getMetaDataFromSpanTree(props);
const inMsCount = value;
const nodeLeftOffset = ((startTime - globalStart) * 1e2) / globalSpread;
const width = (value * 1e2) / (globalSpread * 1e6);
const panelWidth = SPAN_DETAILS_LEFT_COL_WIDTH - (level * (16 + 1)) - 16;
return (
<>
<Wrapper
onMouseEnter={onMouseEnterHandler}
onMouseLeave={onMouseLeaveHandler}
isOnlyChild={isOnlyChild}
ref={ref}
>
<HoverCard
top={top}
isHovered={activeHoverId === id}
isSelected={activeSelectedId === id}
isDarkMode={isDarkMode}
/>
<CardContainer
onClick={onClick}
>
<Col flex={`${panelWidth}px`} style={{ overflow: 'hidden' }}>
<Row style={{ flexWrap: 'nowrap' }}>
<Col>
{totalSpans !== 1 && (
<CardComponent
isDarkMode={isDarkMode}
onClick={(e) => {
e.stopPropagation()
setOpen((state) => !state);
}}
>
{totalSpans}
<CaretContainer>
{isOpen ? <CaretDownFilled /> : <CaretRightFilled />}
</CaretContainer>
</CardComponent>
)}
</Col>
<Col>
<SpanName name={name} serviceName={serviceName} />
</Col>
</Row>
</Col>
<Col flex={'1'} >
<SpanLength
leftOffset={nodeLeftOffset.toString()}
width={width.toString()}
bgColor={serviceColour}
id={id}
inMsCount={(inMsCount / 1e6)}
intervalUnit={intervalUnit}
/>
</Col>
</CardContainer>
{isOpen && (
<>
{props.children.map((child) => (
<Trace
key={child.id}
activeHoverId={props.activeHoverId}
setActiveHoverId={props.setActiveHoverId}
{...child}
globalSpread={globalSpread}
globalStart={globalStart}
setActiveSelectedId={setActiveSelectedId}
activeSelectedId={activeSelectedId}
level={level + 1}
activeSpanPath={activeSpanPath}
isExpandAll={isExpandAll}
intervalUnit={intervalUnit}
/>
))}
</>
)}
</Wrapper>
</>
);
};
interface ITraceGlobal {
globalSpread: ITraceMetaData['spread'];
globalStart: ITraceMetaData['globalStart'];
}
interface TraceProps extends pushDStree, ITraceGlobal {
activeHoverId: string;
setActiveHoverId: React.Dispatch<React.SetStateAction<string>>;
setActiveSelectedId: React.Dispatch<React.SetStateAction<string>>;
activeSelectedId: string;
level: number;
activeSpanPath: string[];
isExpandAll: boolean;
intervalUnit: IIntervalUnit;
}
export default Trace;