mirror of
https://git.mirrors.martin98.com/https://github.com/SigNoz/signoz
synced 2025-08-10 02:39:02 +08:00
feat: new trace detail page code enhancemenets and cleanup
This commit is contained in:
parent
314f95a914
commit
c3ebbfa8ca
@ -1,4 +1,6 @@
|
|||||||
import { Col, ColProps, Row, RowProps } from 'antd';
|
import * as AntD from 'antd';
|
||||||
|
import { TextProps } from 'antd/lib/typography/Text';
|
||||||
|
import { TitleProps } from 'antd/lib/typography/Title';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import styled, {
|
import styled, {
|
||||||
css,
|
css,
|
||||||
@ -10,15 +12,47 @@ import styled, {
|
|||||||
import { IStyledClass } from './types';
|
import { IStyledClass } from './types';
|
||||||
|
|
||||||
const styledClass = (props: IStyledClass): FlattenSimpleInterpolation =>
|
const styledClass = (props: IStyledClass): FlattenSimpleInterpolation =>
|
||||||
props.styledClass;
|
props.styledclass;
|
||||||
|
|
||||||
interface IStyledCol extends ColProps, IStyledClass {}
|
interface IStyledCol extends AntD.ColProps, IStyledClass {}
|
||||||
const StyledCol = styled(Col)<IStyledCol>`
|
const StyledCol = styled(AntD.Col)<IStyledCol>`
|
||||||
${styledClass}
|
${styledClass}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
interface IStyledRow extends RowProps, IStyledClass {}
|
interface IStyledRow extends AntD.RowProps, IStyledClass {}
|
||||||
const StyledRow = styled(Row)<IStyledRow>`
|
const StyledRow = styled(AntD.Row)<IStyledRow>`
|
||||||
|
${styledClass}
|
||||||
|
`;
|
||||||
|
|
||||||
|
interface IStyledDivider extends AntD.DividerProps, IStyledClass {}
|
||||||
|
const StyledDivider = styled(AntD.Divider)<IStyledDivider>`
|
||||||
|
${styledClass}
|
||||||
|
`;
|
||||||
|
|
||||||
|
interface IStyledSpace extends AntD.SpaceProps, IStyledClass {}
|
||||||
|
const StyledSpace = styled(AntD.Space)<IStyledSpace>`
|
||||||
|
${styledClass}
|
||||||
|
`;
|
||||||
|
|
||||||
|
interface IStyledTabs extends AntD.TabsProps, IStyledClass {}
|
||||||
|
const StyledTabs = styled(AntD.Divider)<IStyledTabs>`
|
||||||
|
${styledClass}
|
||||||
|
`;
|
||||||
|
|
||||||
|
interface IStyledButton extends AntD.ButtonProps, IStyledClass {}
|
||||||
|
const StyledButton = styled(AntD.Button)<IStyledButton>`
|
||||||
|
${styledClass}
|
||||||
|
`;
|
||||||
|
|
||||||
|
const { Text } = AntD.Typography;
|
||||||
|
interface IStyledTypographyText extends TextProps, IStyledClass {}
|
||||||
|
const StyledTypographyText = styled(Text)<IStyledTypographyText>`
|
||||||
|
${styledClass}
|
||||||
|
`;
|
||||||
|
|
||||||
|
const { Title } = AntD.Typography;
|
||||||
|
interface IStyledTypographyTitle extends TitleProps, IStyledClass {}
|
||||||
|
const StyledTypographyTitle = styled(Title)<IStyledTypographyTitle>`
|
||||||
${styledClass}
|
${styledClass}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
@ -29,4 +63,17 @@ const StyledDiv = styled.div<IStyledDiv>`
|
|||||||
${styledClass}
|
${styledClass}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export { StyledCol, StyledDiv, StyledRow };
|
const StyledTypography = {
|
||||||
|
Text: StyledTypographyText,
|
||||||
|
Title: StyledTypographyTitle,
|
||||||
|
};
|
||||||
|
export {
|
||||||
|
StyledButton,
|
||||||
|
StyledCol,
|
||||||
|
StyledDiv,
|
||||||
|
StyledDivider,
|
||||||
|
StyledRow,
|
||||||
|
StyledSpace,
|
||||||
|
StyledTabs,
|
||||||
|
StyledTypography,
|
||||||
|
};
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { FlattenSimpleInterpolation } from 'styled-components';
|
import { FlattenSimpleInterpolation } from 'styled-components';
|
||||||
|
|
||||||
export interface IStyledClass {
|
export interface IStyledClass {
|
||||||
styledClass: FlattenSimpleInterpolation[];
|
styledclass?: FlattenSimpleInterpolation[];
|
||||||
}
|
}
|
||||||
|
@ -1,22 +1,24 @@
|
|||||||
import React, { useRef, useState, useEffect } from 'react';
|
import { CaretDownFilled, CaretRightFilled } from '@ant-design/icons';
|
||||||
|
import { Col } from 'antd';
|
||||||
|
import { StyledCol, StyledRow } from 'components/Styled';
|
||||||
|
import { IIntervalUnit } from 'container/TraceDetail/utils';
|
||||||
|
import useThemeMode from 'hooks/useThemeMode';
|
||||||
|
import { SPAN_DETAILS_LEFT_COL_WIDTH } from 'pages/TraceDetail/constants';
|
||||||
|
import React, { useEffect, useRef, useState } from 'react';
|
||||||
|
import { pushDStree } from 'store/actions';
|
||||||
|
|
||||||
|
import { ITraceMetaData } from '..';
|
||||||
|
import SpanLength from '../SpanLength';
|
||||||
|
import SpanName from '../SpanName';
|
||||||
|
import { getMetaDataFromSpanTree, getTopLeftFromBody } from '../utils';
|
||||||
import {
|
import {
|
||||||
CardComponent,
|
CardComponent,
|
||||||
CardContainer,
|
CardContainer,
|
||||||
CaretContainer,
|
CaretContainer,
|
||||||
Wrapper,
|
|
||||||
HoverCard,
|
HoverCard,
|
||||||
|
styles,
|
||||||
|
Wrapper,
|
||||||
} from './styles';
|
} 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 Trace = (props: TraceProps): JSX.Element => {
|
||||||
const {
|
const {
|
||||||
@ -38,7 +40,7 @@ const Trace = (props: TraceProps): JSX.Element => {
|
|||||||
intervalUnit,
|
intervalUnit,
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
const { isDarkMode } = useThemeMode()
|
const { isDarkMode } = useThemeMode();
|
||||||
const [isOpen, setOpen] = useState<boolean>(activeSpanPath[level] === id);
|
const [isOpen, setOpen] = useState<boolean>(activeSpanPath[level] === id);
|
||||||
|
|
||||||
const localTreeExpandInteraction = useRef<boolean | 0>(0); // Boolean is for the state of the expansion whereas the number i.e. 0 is for skipping the user interaction.
|
const localTreeExpandInteraction = useRef<boolean | 0>(0); // Boolean is for the state of the expansion whereas the number i.e. 0 is for skipping the user interaction.
|
||||||
@ -47,20 +49,18 @@ const Trace = (props: TraceProps): JSX.Element => {
|
|||||||
if (localTreeExpandInteraction.current !== 0) {
|
if (localTreeExpandInteraction.current !== 0) {
|
||||||
setOpen(localTreeExpandInteraction.current);
|
setOpen(localTreeExpandInteraction.current);
|
||||||
localTreeExpandInteraction.current = 0;
|
localTreeExpandInteraction.current = 0;
|
||||||
|
} else if (!isOpen) {
|
||||||
|
setOpen(activeSpanPath[level] === id);
|
||||||
}
|
}
|
||||||
else if (!isOpen) {
|
}, [activeSpanPath, isOpen]);
|
||||||
setOpen(activeSpanPath[level] === id)
|
|
||||||
}
|
|
||||||
}, [activeSpanPath, isOpen])
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isExpandAll) {
|
if (isExpandAll) {
|
||||||
setOpen(isExpandAll)
|
setOpen(isExpandAll);
|
||||||
|
} else {
|
||||||
|
setOpen(activeSpanPath[level] === id);
|
||||||
}
|
}
|
||||||
else {
|
}, [isExpandAll]);
|
||||||
setOpen(activeSpanPath[level] === id)
|
|
||||||
}
|
|
||||||
}, [isExpandAll])
|
|
||||||
|
|
||||||
const isOnlyChild = props.children.length === 1;
|
const isOnlyChild = props.children.length === 1;
|
||||||
const [top, setTop] = useState<number>(0);
|
const [top, setTop] = useState<number>(0);
|
||||||
@ -69,9 +69,13 @@ const Trace = (props: TraceProps): JSX.Element => {
|
|||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
if (activeSelectedId === id) {
|
if (activeSelectedId === id) {
|
||||||
ref.current?.scrollIntoView({ block: 'nearest', behavior: 'auto', inline: 'nearest' });
|
ref.current?.scrollIntoView({
|
||||||
|
block: 'nearest',
|
||||||
|
behavior: 'auto',
|
||||||
|
inline: 'nearest',
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}, [activeSelectedId])
|
}, [activeSelectedId]);
|
||||||
|
|
||||||
const onMouseEnterHandler = () => {
|
const onMouseEnterHandler = () => {
|
||||||
setActiveHoverId(props.id);
|
setActiveHoverId(props.id);
|
||||||
@ -87,18 +91,21 @@ const Trace = (props: TraceProps): JSX.Element => {
|
|||||||
|
|
||||||
const onClick = () => {
|
const onClick = () => {
|
||||||
setActiveSelectedId(id);
|
setActiveSelectedId(id);
|
||||||
}
|
};
|
||||||
|
|
||||||
const onClickTreeExpansion = (event) => {
|
const onClickTreeExpansion = (event) => {
|
||||||
event.stopPropagation()
|
event.stopPropagation();
|
||||||
setOpen((state) => { localTreeExpandInteraction.current = !isOpen; return !state });
|
setOpen((state) => {
|
||||||
}
|
localTreeExpandInteraction.current = !isOpen;
|
||||||
|
return !state;
|
||||||
|
});
|
||||||
|
};
|
||||||
const { totalSpans } = getMetaDataFromSpanTree(props);
|
const { totalSpans } = getMetaDataFromSpanTree(props);
|
||||||
|
|
||||||
const inMsCount = value;
|
const inMsCount = value;
|
||||||
const nodeLeftOffset = ((startTime - globalStart) * 1e2) / globalSpread;
|
const nodeLeftOffset = ((startTime - globalStart) * 1e2) / globalSpread;
|
||||||
const width = (value * 1e2) / (globalSpread * 1e6);
|
const width = (value * 1e2) / (globalSpread * 1e6);
|
||||||
const panelWidth = SPAN_DETAILS_LEFT_COL_WIDTH - (level * (16 + 1)) - 16;
|
const panelWidth = SPAN_DETAILS_LEFT_COL_WIDTH - level * (16 + 1) - 48;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@ -115,17 +122,12 @@ const Trace = (props: TraceProps): JSX.Element => {
|
|||||||
isDarkMode={isDarkMode}
|
isDarkMode={isDarkMode}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<CardContainer
|
<CardContainer onClick={onClick}>
|
||||||
onClick={onClick}
|
<StyledCol flex={`${panelWidth}px`} styledclass={[styles.overFlowHidden]}>
|
||||||
>
|
<StyledRow styledclass={[styles.flexNoWrap]}>
|
||||||
<Col flex={`${panelWidth}px`} style={{ overflow: 'hidden' }}>
|
|
||||||
<Row style={{ flexWrap: 'nowrap' }}>
|
|
||||||
<Col>
|
<Col>
|
||||||
{totalSpans !== 1 && (
|
{totalSpans !== 1 && (
|
||||||
<CardComponent
|
<CardComponent isDarkMode={isDarkMode} onClick={onClickTreeExpansion}>
|
||||||
isDarkMode={isDarkMode}
|
|
||||||
onClick={onClickTreeExpansion}
|
|
||||||
>
|
|
||||||
{totalSpans}
|
{totalSpans}
|
||||||
<CaretContainer>
|
<CaretContainer>
|
||||||
{isOpen ? <CaretDownFilled /> : <CaretRightFilled />}
|
{isOpen ? <CaretDownFilled /> : <CaretRightFilled />}
|
||||||
@ -136,15 +138,15 @@ const Trace = (props: TraceProps): JSX.Element => {
|
|||||||
<Col>
|
<Col>
|
||||||
<SpanName name={name} serviceName={serviceName} />
|
<SpanName name={name} serviceName={serviceName} />
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</StyledRow>
|
||||||
</Col>
|
</StyledCol>
|
||||||
<Col flex={'1'} >
|
<Col flex={'1'}>
|
||||||
<SpanLength
|
<SpanLength
|
||||||
leftOffset={nodeLeftOffset.toString()}
|
leftOffset={nodeLeftOffset.toString()}
|
||||||
width={width.toString()}
|
width={width.toString()}
|
||||||
bgColor={serviceColour}
|
bgColor={serviceColour}
|
||||||
id={id}
|
id={id}
|
||||||
inMsCount={(inMsCount / 1e6)}
|
inMsCount={inMsCount / 1e6}
|
||||||
intervalUnit={intervalUnit}
|
intervalUnit={intervalUnit}
|
||||||
/>
|
/>
|
||||||
</Col>
|
</Col>
|
||||||
|
@ -75,3 +75,16 @@ export const HoverCard = styled.div<HoverCardProps>`
|
|||||||
height: 3rem;
|
height: 3rem;
|
||||||
opacity: 0.5;
|
opacity: 0.5;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
const flexNoWrap = css`
|
||||||
|
flex-wrap: nowrap;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const overFlowHidden = css`
|
||||||
|
overflow: hidden;
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const styles = {
|
||||||
|
flexNoWrap,
|
||||||
|
overFlowHidden,
|
||||||
|
};
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
|
import { MinusSquareOutlined, PlusSquareOutlined } from '@ant-design/icons';
|
||||||
|
import { IIntervalUnit } from 'container/TraceDetail/utils';
|
||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import Trace from './Trace';
|
|
||||||
import { MinusSquareOutlined, PlusSquareOutlined } from '@ant-design/icons'
|
|
||||||
import { Wrapper, CardWrapper, CardContainer, CollapseButton } from './styles';
|
|
||||||
import { getSpanPath } from './utils';
|
|
||||||
import { IIntervalUnit } from 'container/TraceDetail/utils'
|
|
||||||
import { ITraceTree } from 'types/api/trace/getTraceItem';
|
import { ITraceTree } from 'types/api/trace/getTraceItem';
|
||||||
|
|
||||||
|
import { CardContainer, CardWrapper, CollapseButton, Wrapper } from './styles';
|
||||||
|
import Trace from './Trace';
|
||||||
|
import { getSpanPath } from './utils';
|
||||||
|
|
||||||
const GanttChart = (props: GanttChartProps): JSX.Element => {
|
const GanttChart = (props: GanttChartProps): JSX.Element => {
|
||||||
const {
|
const {
|
||||||
data,
|
data,
|
||||||
@ -15,7 +16,7 @@ const GanttChart = (props: GanttChartProps): JSX.Element => {
|
|||||||
activeSelectedId,
|
activeSelectedId,
|
||||||
setActiveSelectedId,
|
setActiveSelectedId,
|
||||||
spanId,
|
spanId,
|
||||||
intervalUnit
|
intervalUnit,
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
const { globalStart, spread: globalSpread } = traceMetaData;
|
const { globalStart, spread: globalSpread } = traceMetaData;
|
||||||
@ -24,11 +25,11 @@ const GanttChart = (props: GanttChartProps): JSX.Element => {
|
|||||||
const [activeSpanPath, setActiveSpanPath] = useState<string[]>([]);
|
const [activeSpanPath, setActiveSpanPath] = useState<string[]>([]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setActiveSpanPath(getSpanPath(data, spanId))
|
setActiveSpanPath(getSpanPath(data, spanId));
|
||||||
}, [spanId]);
|
}, [spanId]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setActiveSpanPath(getSpanPath(data, activeSelectedId))
|
setActiveSpanPath(getSpanPath(data, activeSelectedId));
|
||||||
}, [activeSelectedId]);
|
}, [activeSelectedId]);
|
||||||
|
|
||||||
const handleCollapse = () => {
|
const handleCollapse = () => {
|
||||||
@ -38,7 +39,10 @@ const GanttChart = (props: GanttChartProps): JSX.Element => {
|
|||||||
<>
|
<>
|
||||||
<Wrapper>
|
<Wrapper>
|
||||||
<CardContainer>
|
<CardContainer>
|
||||||
<CollapseButton onClick={handleCollapse} style={{ fontSize: '1.2rem' }} title={isExpandAll ? 'Collapse All' : "Expand All"}>
|
<CollapseButton
|
||||||
|
onClick={handleCollapse}
|
||||||
|
title={isExpandAll ? 'Collapse All' : 'Expand All'}
|
||||||
|
>
|
||||||
{isExpandAll ? <MinusSquareOutlined /> : <PlusSquareOutlined />}
|
{isExpandAll ? <MinusSquareOutlined /> : <PlusSquareOutlined />}
|
||||||
</CollapseButton>
|
</CollapseButton>
|
||||||
<CardWrapper>
|
<CardWrapper>
|
||||||
@ -81,7 +85,7 @@ export interface GanttChartProps {
|
|||||||
setActiveHoverId: React.Dispatch<React.SetStateAction<string>>;
|
setActiveHoverId: React.Dispatch<React.SetStateAction<string>>;
|
||||||
setActiveSelectedId: React.Dispatch<React.SetStateAction<string>>;
|
setActiveSelectedId: React.Dispatch<React.SetStateAction<string>>;
|
||||||
spanId: string;
|
spanId: string;
|
||||||
intervalUnit: IIntervalUnit
|
intervalUnit: IIntervalUnit;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default GanttChart;
|
export default GanttChart;
|
||||||
|
@ -44,4 +44,5 @@ export const CollapseButton = styled.div`
|
|||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
|
font-size: 1.2rem;
|
||||||
`;
|
`;
|
||||||
|
@ -1,15 +1,12 @@
|
|||||||
import React, { useState, useMemo } from 'react';
|
import { StyledDiv } from 'components/Styled';
|
||||||
import { isEqual } from 'lodash-es';
|
import { INTERVAL_UNITS } from 'container/TraceDetail/utils';
|
||||||
import styles from './style.module.css';
|
|
||||||
import { useMeasure } from 'react-use';
|
|
||||||
import { toFixed } from 'utils/toFixed';
|
|
||||||
import {
|
|
||||||
INTERVAL_UNITS,
|
|
||||||
resolveTimeFromInterval,
|
|
||||||
} from 'container/TraceDetail/utils';
|
|
||||||
import useThemeMode from 'hooks/useThemeMode';
|
import useThemeMode from 'hooks/useThemeMode';
|
||||||
|
import React, { useMemo, useState } from 'react';
|
||||||
|
import { useMeasure } from 'react-use';
|
||||||
|
|
||||||
|
import { styles, Svg, TimelineInterval } from './styles';
|
||||||
import { Interval } from './types';
|
import { Interval } from './types';
|
||||||
import { getIntervalSpread, getIntervals } from './utils';
|
import { getIntervals, getIntervalSpread } from './utils';
|
||||||
interface TimelineProps {
|
interface TimelineProps {
|
||||||
traceMetaData: object;
|
traceMetaData: object;
|
||||||
globalTraceMetadata: object;
|
globalTraceMetadata: object;
|
||||||
@ -21,7 +18,7 @@ const Timeline = ({
|
|||||||
globalTraceMetadata,
|
globalTraceMetadata,
|
||||||
intervalUnit,
|
intervalUnit,
|
||||||
setIntervalUnit,
|
setIntervalUnit,
|
||||||
}: TimelineProps) => {
|
}: TimelineProps): JSX.Element => {
|
||||||
const [ref, { width }] = useMeasure<HTMLDivElement>();
|
const [ref, { width }] = useMeasure<HTMLDivElement>();
|
||||||
const { isDarkMode } = useThemeMode();
|
const { isDarkMode } = useThemeMode();
|
||||||
|
|
||||||
@ -61,12 +58,10 @@ const Timeline = ({
|
|||||||
}, [traceMetaData, globalTraceMetadata]);
|
}, [traceMetaData, globalTraceMetadata]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div ref={ref} style={{ flex: 1, overflow: 'inherit' }}>
|
<StyledDiv ref={ref} styledclass={[styles.timelineContainer]}>
|
||||||
<svg
|
<Svg
|
||||||
style={{ overflow: 'inherit' }}
|
|
||||||
viewBox={`0 0 ${width} ${Timeline_Height}`}
|
viewBox={`0 0 ${width} ${Timeline_Height}`}
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
className={styles['svg-container']}
|
|
||||||
>
|
>
|
||||||
<line
|
<line
|
||||||
x1={Timeline_H_Spacing}
|
x1={Timeline_H_Spacing}
|
||||||
@ -78,13 +73,12 @@ const Timeline = ({
|
|||||||
/>
|
/>
|
||||||
{intervals &&
|
{intervals &&
|
||||||
intervals.map((interval, index) => (
|
intervals.map((interval, index) => (
|
||||||
<g
|
<TimelineInterval
|
||||||
transform={`translate(${
|
transform={`translate(${
|
||||||
Timeline_H_Spacing +
|
Timeline_H_Spacing +
|
||||||
(interval.percentage * (width - 2 * Timeline_H_Spacing)) / 100
|
(interval.percentage * (width - 2 * Timeline_H_Spacing)) / 100
|
||||||
},0)`}
|
},0)`}
|
||||||
className={styles['timeline-tick']}
|
key={`${interval.label + interval.percentage + index}`}
|
||||||
key={interval.label + interval.percentage + index}
|
|
||||||
>
|
>
|
||||||
<text y={13} fill={isDarkMode ? 'white' : 'black'}>
|
<text y={13} fill={isDarkMode ? 'white' : 'black'}>
|
||||||
{interval.label}
|
{interval.label}
|
||||||
@ -95,10 +89,10 @@ const Timeline = ({
|
|||||||
stroke={isDarkMode ? 'white' : 'black'}
|
stroke={isDarkMode ? 'white' : 'black'}
|
||||||
strokeWidth="1"
|
strokeWidth="1"
|
||||||
/>
|
/>
|
||||||
</g>
|
</TimelineInterval>
|
||||||
))}
|
))}
|
||||||
</svg>
|
</Svg>
|
||||||
</div>
|
</StyledDiv>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,8 +0,0 @@
|
|||||||
.svg-container {
|
|
||||||
overflow: visible;
|
|
||||||
position: absolute;
|
|
||||||
}
|
|
||||||
.timeline-tick {
|
|
||||||
text-anchor: middle;
|
|
||||||
font-size: 0.6rem;
|
|
||||||
}
|
|
19
frontend/src/container/Timeline/styles.ts
Normal file
19
frontend/src/container/Timeline/styles.ts
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import styled, { css } from 'styled-components';
|
||||||
|
|
||||||
|
const timelineContainer = css`
|
||||||
|
flex: 1;
|
||||||
|
overflow: visible;
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const styles = {
|
||||||
|
timelineContainer,
|
||||||
|
};
|
||||||
|
export const Svg = styled.svg`
|
||||||
|
overflow: visible !important;
|
||||||
|
position: absolute;
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const TimelineInterval = styled.g`
|
||||||
|
text-anchor: middle;
|
||||||
|
font-size: 0.6rem;
|
||||||
|
`;
|
@ -1,23 +1,24 @@
|
|||||||
import { Button, Modal, Collapse } from 'antd';
|
import { Collapse, Modal } from 'antd';
|
||||||
|
import { StyledButton } from 'components/Styled';
|
||||||
import useThemeMode from 'hooks/useThemeMode';
|
import useThemeMode from 'hooks/useThemeMode';
|
||||||
import React, { useRef, useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import { ITraceTree } from 'types/api/trace/getTraceItem';
|
import { ITraceTree } from 'types/api/trace/getTraceItem';
|
||||||
import { CustomSubText, CustomSubTitle } from './styles';
|
|
||||||
|
import { CustomSubText, CustomSubTitle, styles } from './styles';
|
||||||
// import Editor from 'components/Editor';
|
// import Editor from 'components/Editor';
|
||||||
|
|
||||||
const { Panel } = Collapse;
|
const { Panel } = Collapse;
|
||||||
|
|
||||||
const ErrorTag = ({ event }: ErrorTagProps) => {
|
const ErrorTag = ({ event }: ErrorTagProps): JSX.Element => {
|
||||||
const [isOpen, setIsOpen] = useState(false);
|
const [isOpen, setIsOpen] = useState(false);
|
||||||
const { isDarkMode } = useThemeMode();
|
const { isDarkMode } = useThemeMode();
|
||||||
// const useTextRef = useRef('');
|
|
||||||
|
|
||||||
const [text, setText] = useState({
|
const [text, setText] = useState({
|
||||||
text: '',
|
text: '',
|
||||||
subText: '',
|
subText: '',
|
||||||
});
|
});
|
||||||
|
|
||||||
const onToggleHandler = (state: boolean) => {
|
const onToggleHandler = (state: boolean): void => {
|
||||||
setIsOpen(state);
|
setIsOpen(state);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -28,6 +29,7 @@ const ErrorTag = ({ event }: ErrorTagProps) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Collapse
|
<Collapse
|
||||||
|
key={`${name}${JSON.stringify(attributeMap)}`}
|
||||||
defaultActiveKey={[name || attributeMap.event]}
|
defaultActiveKey={[name || attributeMap.event]}
|
||||||
expandIconPosition="right"
|
expandIconPosition="right"
|
||||||
>
|
>
|
||||||
@ -46,24 +48,21 @@ const ErrorTag = ({ event }: ErrorTagProps) => {
|
|||||||
{value}
|
{value}
|
||||||
<br />
|
<br />
|
||||||
{isEllipsed && (
|
{isEllipsed && (
|
||||||
<Button
|
<StyledButton
|
||||||
style={{ padding: 0, margin: 0 }}
|
styledclass={[styles.removeMargin, styles.removePadding]}
|
||||||
onClick={() => {
|
onClick={(): void => {
|
||||||
onToggleHandler(true);
|
onToggleHandler(true);
|
||||||
setText({
|
setText({
|
||||||
subText: value,
|
subText: value,
|
||||||
text: event,
|
text: event,
|
||||||
});
|
});
|
||||||
// useTextRef.current = value;
|
|
||||||
}}
|
}}
|
||||||
type="link"
|
type="link"
|
||||||
>
|
>
|
||||||
View full log event message
|
View full log event message
|
||||||
</Button>
|
</StyledButton>
|
||||||
)}
|
)}
|
||||||
</CustomSubText>
|
</CustomSubText>
|
||||||
|
|
||||||
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
@ -72,7 +71,7 @@ const ErrorTag = ({ event }: ErrorTagProps) => {
|
|||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
<Modal
|
<Modal
|
||||||
onCancel={() => onToggleHandler(false)}
|
onCancel={(): void => onToggleHandler(false)}
|
||||||
title="Log Message"
|
title="Log Message"
|
||||||
visible={isOpen}
|
visible={isOpen}
|
||||||
destroyOnClose
|
destroyOnClose
|
||||||
|
@ -1,15 +1,18 @@
|
|||||||
import { Space, Tabs, Typography } from 'antd';
|
import { Space, Tabs, Typography } from 'antd';
|
||||||
|
import { StyledSpace, StyledTabs } from 'components/Styled';
|
||||||
|
import useThemeMode from 'hooks/useThemeMode';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { ITraceTree } from 'types/api/trace/getTraceItem';
|
import { ITraceTree } from 'types/api/trace/getTraceItem';
|
||||||
|
|
||||||
|
import ErrorTag from './ErrorTag';
|
||||||
import {
|
import {
|
||||||
CardContainer,
|
CardContainer,
|
||||||
CustomSubText,
|
CustomSubText,
|
||||||
CustomSubTitle,
|
CustomSubTitle,
|
||||||
CustomText,
|
CustomText,
|
||||||
CustomTitle,
|
CustomTitle,
|
||||||
|
styles,
|
||||||
} from './styles';
|
} from './styles';
|
||||||
import ErrorTag from './ErrorTag';
|
|
||||||
import useThemeMode from 'hooks/useThemeMode';
|
|
||||||
|
|
||||||
const { TabPane } = Tabs;
|
const { TabPane } = Tabs;
|
||||||
|
|
||||||
@ -24,7 +27,11 @@ const SelectedSpanDetails = (props: SelectedSpanDetailsProps): JSX.Element => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<CardContainer>
|
<CardContainer>
|
||||||
<Space direction="vertical" style={{ marginLeft: '0.5rem' }}>
|
<StyledSpace
|
||||||
|
styledclass={[styles.selectedSpanDetailsContainer]}
|
||||||
|
direction="vertical"
|
||||||
|
style={{ marginLeft: '0.5rem' }}
|
||||||
|
>
|
||||||
<strong> Details for selected Span </strong>
|
<strong> Details for selected Span </strong>
|
||||||
<Space direction="vertical" size={2}>
|
<Space direction="vertical" size={2}>
|
||||||
<CustomTitle>Service</CustomTitle>
|
<CustomTitle>Service</CustomTitle>
|
||||||
@ -34,13 +41,16 @@ const SelectedSpanDetails = (props: SelectedSpanDetailsProps): JSX.Element => {
|
|||||||
<CustomTitle>Operation</CustomTitle>
|
<CustomTitle>Operation</CustomTitle>
|
||||||
<CustomText>{name}</CustomText>
|
<CustomText>{name}</CustomText>
|
||||||
</Space>
|
</Space>
|
||||||
</Space>
|
</StyledSpace>
|
||||||
<Tabs defaultActiveKey="1" style={{ marginTop: '1rem' }}>
|
<StyledTabs
|
||||||
|
styledclass={[styles.spanEventsTabsContainer]}
|
||||||
|
defaultActiveKey="1"
|
||||||
|
>
|
||||||
<TabPane tab="Tags" key="1">
|
<TabPane tab="Tags" key="1">
|
||||||
{tags.length !== 0 ? (
|
{tags.length !== 0 ? (
|
||||||
tags.map((tags) => {
|
tags.map((tags) => {
|
||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<React.Fragment key={JSON.stringify(tags)}>
|
||||||
{tags.value && (
|
{tags.value && (
|
||||||
<>
|
<>
|
||||||
<CustomSubTitle>{tags.key}</CustomSubTitle>
|
<CustomSubTitle>{tags.key}</CustomSubTitle>
|
||||||
@ -63,7 +73,7 @@ const SelectedSpanDetails = (props: SelectedSpanDetailsProps): JSX.Element => {
|
|||||||
<Typography>No events data in selected span</Typography>
|
<Typography>No events data in selected span</Typography>
|
||||||
)}
|
)}
|
||||||
</TabPane>
|
</TabPane>
|
||||||
</Tabs>
|
</StyledTabs>
|
||||||
</CardContainer>
|
</CardContainer>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { Typography } from 'antd';
|
import { Typography } from 'antd';
|
||||||
import styled from 'styled-components';
|
import styled, { css } from 'styled-components';
|
||||||
const { Text, Title, Paragraph } = Typography;
|
const { Text, Title, Paragraph } = Typography;
|
||||||
|
|
||||||
export const CustomTitle = styled(Title)`
|
export const CustomTitle = styled(Title)`
|
||||||
@ -44,3 +44,24 @@ export const CardContainer = styled.div`
|
|||||||
flex: 1;
|
flex: 1;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
const removeMargin = css`
|
||||||
|
margin: 0;
|
||||||
|
`;
|
||||||
|
const removePadding = css`
|
||||||
|
padding: 0;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const selectedSpanDetailsContainer = css`
|
||||||
|
margin-left: 0.5rem;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const spanEventsTabsContainer = css`
|
||||||
|
margin-top: 1rem;
|
||||||
|
`;
|
||||||
|
export const styles = {
|
||||||
|
removeMargin,
|
||||||
|
removePadding,
|
||||||
|
selectedSpanDetailsContainer,
|
||||||
|
spanEventsTabsContainer,
|
||||||
|
};
|
||||||
|
@ -1,6 +1,13 @@
|
|||||||
import { FilterOutlined } from '@ant-design/icons';
|
import { FilterOutlined } from '@ant-design/icons';
|
||||||
import { Button, Col, Divider, Row, Space, Typography } from 'antd';
|
import { Button, Col } from 'antd';
|
||||||
import { StyledCol, StyledDiv, StyledRow } from 'components/Styled';
|
import {
|
||||||
|
StyledCol,
|
||||||
|
StyledDiv,
|
||||||
|
StyledDivider,
|
||||||
|
StyledRow,
|
||||||
|
StyledSpace,
|
||||||
|
StyledTypography,
|
||||||
|
} from 'components/Styled';
|
||||||
import * as StyledStyles from 'components/Styled/styles';
|
import * as StyledStyles from 'components/Styled/styles';
|
||||||
import GanttChart from 'container/GantChart';
|
import GanttChart from 'container/GantChart';
|
||||||
import { getNodeById } from 'container/GantChart/utils';
|
import { getNodeById } from 'container/GantChart/utils';
|
||||||
@ -43,7 +50,7 @@ const TraceDetail = ({ response }: TraceDetailProps): JSX.Element => {
|
|||||||
return getSpanTreeMetadata(getSortedData(treeData), spanServiceColors);
|
return getSpanTreeMetadata(getSortedData(treeData), spanServiceColors);
|
||||||
}, [treeData]);
|
}, [treeData]);
|
||||||
|
|
||||||
const [globalTraceMetadata, _setGlobalTraceMetadata] = useState<object>({
|
const [globalTraceMetadata, _setGlobalTraceMetadata] = useState({
|
||||||
...traceMetaData,
|
...traceMetaData,
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -60,7 +67,7 @@ const TraceDetail = ({ response }: TraceDetailProps): JSX.Element => {
|
|||||||
return getNodeById(activeSelectedId, treeData);
|
return getNodeById(activeSelectedId, treeData);
|
||||||
}, [activeSelectedId, treeData]);
|
}, [activeSelectedId, treeData]);
|
||||||
|
|
||||||
const onSearchHandler = (value: string) => {
|
const onSearchHandler = (value: string): void => {
|
||||||
setSearchSpanString(value);
|
setSearchSpanString(value);
|
||||||
setTreeData(spanToTreeUtil(response[0].events));
|
setTreeData(spanToTreeUtil(response[0].events));
|
||||||
};
|
};
|
||||||
@ -71,37 +78,25 @@ const TraceDetail = ({ response }: TraceDetailProps): JSX.Element => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const onResetHandler = () => {
|
const onResetHandler = (): void => {
|
||||||
setTreeData(spanToTreeUtil(response[0].events));
|
setTreeData(spanToTreeUtil(response[0].events));
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledRow styledClass={[StyledStyles.Flex({ flex: 1 })]}>
|
<StyledRow styledclass={[StyledStyles.Flex({ flex: 1 })]}>
|
||||||
<StyledCol
|
<StyledCol flex={'auto'} styledclass={styles.leftContainer}>
|
||||||
flex={'auto'}
|
<StyledRow styledclass={styles.flameAndTimelineContainer}>
|
||||||
styledClass={[
|
<StyledCol
|
||||||
StyledStyles.Flex({ flexDirection: 'column' }),
|
styledclass={styles.traceMetaDataContainer}
|
||||||
StyledStyles.Display({ display: 'flex' }),
|
|
||||||
]}
|
|
||||||
>
|
|
||||||
<StyledRow
|
|
||||||
styledClass={[
|
|
||||||
StyledStyles.Spacing({
|
|
||||||
margin: '0 1rem 0 0',
|
|
||||||
}),
|
|
||||||
]}
|
|
||||||
>
|
|
||||||
<Col
|
|
||||||
flex={`${SPAN_DETAILS_LEFT_COL_WIDTH}px`}
|
flex={`${SPAN_DETAILS_LEFT_COL_WIDTH}px`}
|
||||||
style={{ alignItems: 'center', display: 'flex', flexDirection: 'column' }}
|
|
||||||
>
|
>
|
||||||
<Typography.Title level={5} style={{ margin: 0 }}>
|
<StyledTypography.Title styledclass={[styles.removeMargin]} level={5}>
|
||||||
Trace Details
|
Trace Details
|
||||||
</Typography.Title>
|
</StyledTypography.Title>
|
||||||
<Typography.Text style={{ margin: 0 }}>
|
<StyledTypography.Text styledclass={[styles.removeMargin]}>
|
||||||
{traceMetaData.totalSpans} Span
|
{traceMetaData.totalSpans} Span
|
||||||
</Typography.Text>
|
</StyledTypography.Text>
|
||||||
</Col>
|
</StyledCol>
|
||||||
<Col flex={'auto'}>
|
<Col flex={'auto'}>
|
||||||
<TraceFlameGraph
|
<TraceFlameGraph
|
||||||
treeData={tree}
|
treeData={tree}
|
||||||
@ -114,8 +109,8 @@ const TraceDetail = ({ response }: TraceDetailProps): JSX.Element => {
|
|||||||
/>
|
/>
|
||||||
</Col>
|
</Col>
|
||||||
</StyledRow>
|
</StyledRow>
|
||||||
<Row style={{ marginTop: '2rem' }}>
|
<StyledRow styledclass={[styles.traceDateAndTimelineContainer]}>
|
||||||
<Col
|
<StyledCol
|
||||||
flex={`${SPAN_DETAILS_LEFT_COL_WIDTH}px`}
|
flex={`${SPAN_DETAILS_LEFT_COL_WIDTH}px`}
|
||||||
style={{
|
style={{
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
@ -124,16 +119,8 @@ const TraceDetail = ({ response }: TraceDetailProps): JSX.Element => {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{dayjs(traceMetaData.globalStart / 1e6).format('hh:mm:ssa MM/DD')}
|
{dayjs(traceMetaData.globalStart / 1e6).format('hh:mm:ssa MM/DD')}
|
||||||
</Col>
|
</StyledCol>
|
||||||
<StyledCol
|
<StyledCol flex="auto" styledclass={[styles.timelineContainer]}>
|
||||||
flex="auto"
|
|
||||||
style={{ overflow: 'visible' }}
|
|
||||||
styledClass={[
|
|
||||||
StyledStyles.Spacing({
|
|
||||||
margin: '0 1rem 0 0',
|
|
||||||
}),
|
|
||||||
]}
|
|
||||||
>
|
|
||||||
<Timeline
|
<Timeline
|
||||||
globalTraceMetadata={globalTraceMetadata}
|
globalTraceMetadata={globalTraceMetadata}
|
||||||
traceMetaData={traceMetaData}
|
traceMetaData={traceMetaData}
|
||||||
@ -141,10 +128,10 @@ const TraceDetail = ({ response }: TraceDetailProps): JSX.Element => {
|
|||||||
setIntervalUnit={setIntervalUnit}
|
setIntervalUnit={setIntervalUnit}
|
||||||
/>
|
/>
|
||||||
</StyledCol>
|
</StyledCol>
|
||||||
<Divider style={{ height: '100%', margin: '0' }} />
|
<StyledDivider styledclass={[styles.verticalSeparator]} />
|
||||||
</Row>
|
</StyledRow>
|
||||||
<StyledRow
|
<StyledRow
|
||||||
styledClass={[
|
styledclass={[
|
||||||
styles.traceDetailContentSpacing,
|
styles.traceDetailContentSpacing,
|
||||||
StyledStyles.Spacing({
|
StyledStyles.Spacing({
|
||||||
margin: '1.5rem 1rem 0.5rem',
|
margin: '1.5rem 1rem 0.5rem',
|
||||||
@ -160,40 +147,17 @@ const TraceDetail = ({ response }: TraceDetailProps): JSX.Element => {
|
|||||||
/> */}
|
/> */}
|
||||||
</Col>
|
</Col>
|
||||||
<Col flex={'auto'}>
|
<Col flex={'auto'}>
|
||||||
<Space
|
<StyledSpace styledclass={[styles.floatRight]}>
|
||||||
style={{
|
|
||||||
float: 'right',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Button onClick={onFocusSelectedSpanHandler} icon={<FilterOutlined />}>
|
<Button onClick={onFocusSelectedSpanHandler} icon={<FilterOutlined />}>
|
||||||
Focus on selected span
|
Focus on selected span
|
||||||
</Button>
|
</Button>
|
||||||
<Button type="default" onClick={onResetHandler}>
|
<Button type="default" onClick={onResetHandler}>
|
||||||
Reset Focus
|
Reset Focus
|
||||||
</Button>
|
</Button>
|
||||||
</Space>
|
</StyledSpace>
|
||||||
</Col>
|
</Col>
|
||||||
</StyledRow>
|
</StyledRow>
|
||||||
<StyledDiv
|
<StyledDiv styledclass={[styles.ganttChartContainer]}>
|
||||||
styledClass={[
|
|
||||||
styles.traceDetailContentSpacing,
|
|
||||||
StyledStyles.Spacing({
|
|
||||||
margin: '1.5rem 1rem 0.5rem',
|
|
||||||
}),
|
|
||||||
StyledStyles.Flex({
|
|
||||||
flexDirection: 'column',
|
|
||||||
}),
|
|
||||||
StyledStyles.Display({
|
|
||||||
display: 'flex',
|
|
||||||
}),
|
|
||||||
]}
|
|
||||||
style={{
|
|
||||||
position: 'relative',
|
|
||||||
flex: 1,
|
|
||||||
overflowY: 'auto',
|
|
||||||
overflowX: 'hidden',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<GanttChart
|
<GanttChart
|
||||||
traceMetaData={traceMetaData}
|
traceMetaData={traceMetaData}
|
||||||
data={tree}
|
data={tree}
|
||||||
@ -207,20 +171,11 @@ const TraceDetail = ({ response }: TraceDetailProps): JSX.Element => {
|
|||||||
</StyledDiv>
|
</StyledDiv>
|
||||||
</StyledCol>
|
</StyledCol>
|
||||||
<Col>
|
<Col>
|
||||||
<Divider style={{ height: '100%', margin: '0' }} type="vertical" />
|
<StyledDivider styledclass={[styles.verticalSeparator]} type="vertical" />
|
||||||
</Col>
|
</Col>
|
||||||
<Col
|
<StyledCol md={5} sm={5} styledclass={[styles.selectedSpanDetailContainer]}>
|
||||||
md={5}
|
|
||||||
sm={5}
|
|
||||||
style={{
|
|
||||||
height: '100%',
|
|
||||||
position: 'relative',
|
|
||||||
display: 'flex',
|
|
||||||
flexDirection: 'column',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<SelectedSpanDetails tree={getSelectedNode} />
|
<SelectedSpanDetails tree={getSelectedNode} />
|
||||||
</Col>
|
</StyledCol>
|
||||||
</StyledRow>
|
</StyledRow>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -1,5 +1,79 @@
|
|||||||
import * as StyledStyles from 'components/Styled/styles';
|
import { css } from 'styled-components';
|
||||||
|
|
||||||
export const traceDetailContentSpacing = StyledStyles.Spacing({
|
/**
|
||||||
margin: '0 1rem 0 0',
|
* Styles for the left container. Containers flamegraph, timeline and gantt chart
|
||||||
});
|
*/
|
||||||
|
export const leftContainer = [
|
||||||
|
css`
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
`,
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Styles for the top container. Contains TotalSpans, FlameGraph and Timeline.
|
||||||
|
*/
|
||||||
|
export const flameAndTimelineContainer = [
|
||||||
|
css`
|
||||||
|
margin: 0 1rem 0 0;
|
||||||
|
`,
|
||||||
|
];
|
||||||
|
|
||||||
|
export const traceMetaDataContainer = [
|
||||||
|
css`
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
`,
|
||||||
|
];
|
||||||
|
|
||||||
|
export const traceDateAndTimelineContainer = css`
|
||||||
|
margin-top: 2rem;
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const traceDateTimeContainer = css`
|
||||||
|
display: flex;
|
||||||
|
aligh-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
`;
|
||||||
|
export const timelineContainer = css`
|
||||||
|
overflow: visible;
|
||||||
|
margin: 0 1rem 0 0;
|
||||||
|
`;
|
||||||
|
export const ganttChartContainer = css`
|
||||||
|
margin: 1.5rem 1rem 0.5rem;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
position: relative;
|
||||||
|
flex: 1;
|
||||||
|
overflow-y: auto;
|
||||||
|
overflow-x: hidden;
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const selectedSpanDetailContainer = css`
|
||||||
|
height: 100%;
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
`;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generic / Common styles
|
||||||
|
*/
|
||||||
|
|
||||||
|
export const verticalSeparator = css`
|
||||||
|
height: 100%;
|
||||||
|
margin: 0;
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const traceDetailContentSpacing = css`
|
||||||
|
margin: 0 1rem 0 0;
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const floatRight = css`
|
||||||
|
float: right;
|
||||||
|
`;
|
||||||
|
export const removeMargin = css`
|
||||||
|
margin: 0;
|
||||||
|
`;
|
||||||
|
@ -1,17 +1,18 @@
|
|||||||
import React, { useState, useLayoutEffect, useMemo } from 'react';
|
|
||||||
import Color from 'color';
|
import Color from 'color';
|
||||||
import { pushDStree } from 'store/actions';
|
|
||||||
import {
|
|
||||||
SpanItemContainer,
|
|
||||||
TraceFlameGraphContainer,
|
|
||||||
TOTAL_SPAN_HEIGHT,
|
|
||||||
} from './styles';
|
|
||||||
import {
|
import {
|
||||||
IIntervalUnit,
|
IIntervalUnit,
|
||||||
resolveTimeFromInterval,
|
resolveTimeFromInterval,
|
||||||
} from 'container/TraceDetail/utils';
|
} from 'container/TraceDetail/utils';
|
||||||
import { toFixed } from 'utils/toFixed';
|
|
||||||
import useThemeMode from 'hooks/useThemeMode';
|
import useThemeMode from 'hooks/useThemeMode';
|
||||||
|
import React, { useLayoutEffect, useMemo, useState } from 'react';
|
||||||
|
import { pushDStree } from 'store/actions';
|
||||||
|
import { toFixed } from 'utils/toFixed';
|
||||||
|
|
||||||
|
import {
|
||||||
|
SpanItemContainer,
|
||||||
|
TOTAL_SPAN_HEIGHT,
|
||||||
|
TraceFlameGraphContainer,
|
||||||
|
} from './styles';
|
||||||
|
|
||||||
const SpanItem = ({
|
const SpanItem = ({
|
||||||
topOffset = 0, // top offset in px
|
topOffset = 0, // top offset in px
|
||||||
@ -33,7 +34,7 @@ const SpanItem = ({
|
|||||||
onSpanHover: Function;
|
onSpanHover: Function;
|
||||||
hoveredSpanId: string;
|
hoveredSpanId: string;
|
||||||
selectedSpanId: string;
|
selectedSpanId: string;
|
||||||
}) => {
|
}): JSX.Element => {
|
||||||
const { serviceColour } = spanData;
|
const { serviceColour } = spanData;
|
||||||
const [isSelected, setIsSelected] = useState<boolean>(false);
|
const [isSelected, setIsSelected] = useState<boolean>(false);
|
||||||
const [isLocalHover, setIsLocalHover] = useState<boolean>(false);
|
const [isLocalHover, setIsLocalHover] = useState<boolean>(false);
|
||||||
@ -48,14 +49,14 @@ const SpanItem = ({
|
|||||||
}
|
}
|
||||||
}, [hoveredSpanId, selectedSpanId]);
|
}, [hoveredSpanId, selectedSpanId]);
|
||||||
|
|
||||||
const handleHover = (hoverState: boolean) => {
|
const handleHover = (hoverState: boolean): void => {
|
||||||
setIsLocalHover(hoverState);
|
setIsLocalHover(hoverState);
|
||||||
|
|
||||||
if (hoverState) onSpanHover(spanData.id);
|
if (hoverState) onSpanHover(spanData.id);
|
||||||
else onSpanHover(null);
|
else onSpanHover(null);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleClick = () => {
|
const handleClick = (): void => {
|
||||||
onSpanSelect(spanData.id);
|
onSpanSelect(spanData.id);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -96,7 +97,7 @@ const TraceFlameGraph = (props: {
|
|||||||
hoveredSpanId: string;
|
hoveredSpanId: string;
|
||||||
selectedSpanId: string;
|
selectedSpanId: string;
|
||||||
intervalUnit: IIntervalUnit;
|
intervalUnit: IIntervalUnit;
|
||||||
}) => {
|
}): null | JSX.Element => {
|
||||||
if (!props.treeData || props.treeData.id === 'empty' || !props.traceMetaData) {
|
if (!props.treeData || props.treeData.id === 'empty' || !props.traceMetaData) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -125,7 +126,7 @@ const TraceFlameGraph = (props: {
|
|||||||
onSpanSelect: Function;
|
onSpanSelect: Function;
|
||||||
hoveredSpanId: string;
|
hoveredSpanId: string;
|
||||||
selectedSpanId: string;
|
selectedSpanId: string;
|
||||||
}) => {
|
}): null | JSX.Element => {
|
||||||
if (!spanData) {
|
if (!spanData) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -4,5 +4,6 @@ export * from './global';
|
|||||||
export * from './metrics';
|
export * from './metrics';
|
||||||
export * from './MetricsActions';
|
export * from './MetricsActions';
|
||||||
export * from './serviceMap';
|
export * from './serviceMap';
|
||||||
|
export * from './traces';
|
||||||
export * from './types';
|
export * from './types';
|
||||||
export * from './usage';
|
export * from './usage';
|
||||||
|
Loading…
x
Reference in New Issue
Block a user