Skip to content

Commit

Permalink
feat(frontend): trace vs test data for timeline and attribute list (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
jorgeepc committed Jun 30, 2023
1 parent cb7456b commit 2e25d52
Show file tree
Hide file tree
Showing 58 changed files with 542 additions and 330 deletions.
4 changes: 4 additions & 0 deletions web/src/assets/error.svg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 4 additions & 2 deletions web/src/components/AttributeList/AttributeList.tsx
@@ -1,4 +1,4 @@
import AttributeRow from 'components/AttributeRow';
import {IPropsAttributeRow} from 'components/SpanDetail/SpanDetail';
import {OtelReference} from 'components/TestSpecForm/hooks/useGetOTELSemanticConventionAttributesInfo';
import TestRunOutput from 'models/TestRunOutput.model';
import {TSpanFlatAttribute} from 'types/Span.types';
Expand All @@ -14,6 +14,7 @@ interface IProps {
testOutputs?: TestRunOutput[];
onCreateTestSpec(attribute: TSpanFlatAttribute): void;
onCreateOutput(attribute: TSpanFlatAttribute): void;
AttributeRowComponent: React.ComponentType<IPropsAttributeRow>;
}

const AttributeList = ({
Expand All @@ -24,11 +25,12 @@ const AttributeList = ({
testOutputs,
onCreateTestSpec,
onCreateOutput,
AttributeRowComponent,
}: IProps) => {
return attributeList.length ? (
<S.AttributeList data-cy="attribute-list">
{attributeList.map(attribute => (
<AttributeRow
<AttributeRowComponent
key={attribute.key}
attribute={attribute}
searchText={searchText}
Expand Down
Expand Up @@ -19,6 +19,7 @@ describe('AttributeList', () => {
semanticConventions={{}}
onCreateOutput={onCreateOutput}
onCreateTestSpec={onCreateTestSpec}
AttributeRowComponent={() => <div />}
/>
);

Expand All @@ -32,6 +33,7 @@ describe('AttributeList', () => {
semanticConventions={{}}
onCreateOutput={onCreateOutput}
onCreateTestSpec={onCreateTestSpec}
AttributeRowComponent={() => <div />}
/>
);

Expand Down
2 changes: 0 additions & 2 deletions web/src/components/AttributeRow/index.ts

This file was deleted.

42 changes: 19 additions & 23 deletions web/src/components/ResizablePanels/Splitter.tsx
Expand Up @@ -6,7 +6,6 @@ interface IProps {
isOpen: boolean;
onClick(): void;
id?: string;
key: string | number;
className?: string;
name: string;
tooltip?: string;
Expand All @@ -20,32 +19,29 @@ const Splitter = ({
name,
onClick,
id,
key,
className,
onMouseDown,
onTouchStart,
tooltip,
tooltipPlacement = 'right',
}: IProps) => {
return (
<S.SplitterContainer id={id} key={key} className={className} onMouseDown={onMouseDown} onTouchStart={onTouchStart}>
<S.ButtonContainer>
<Tooltip title={tooltip} trigger="hover" placement={tooltipPlacement} overlayClassName="splitter">
<S.SplitterButton
data-cy={`toggle-drawer-${name}`}
icon={isOpen ? <DoubleLeftOutlined /> : <DoubleRightOutlined />}
onClick={event => {
event.stopPropagation();
onClick();
}}
onMouseDown={event => event.stopPropagation()}
shape="circle"
type="primary"
/>
</Tooltip>
</S.ButtonContainer>
</S.SplitterContainer>
);
};
}: IProps) => (
<S.SplitterContainer id={id} key={id} className={className} onMouseDown={onMouseDown} onTouchStart={onTouchStart}>
<S.ButtonContainer>
<Tooltip title={tooltip} trigger="hover" placement={tooltipPlacement} overlayClassName="splitter">
<S.SplitterButton
data-cy={`toggle-drawer-${name}`}
icon={isOpen ? <DoubleLeftOutlined /> : <DoubleRightOutlined />}
onClick={event => {
event.stopPropagation();
onClick();
}}
onMouseDown={event => event.stopPropagation()}
shape="circle"
type="primary"
/>
</Tooltip>
</S.ButtonContainer>
</S.SplitterContainer>
);

export default Splitter;
4 changes: 2 additions & 2 deletions web/src/components/RunDetailTest/SpanDetailsPanel.tsx
@@ -1,5 +1,5 @@
import SpanDetail, {TestAttributeRow, TestSubHeader} from 'components/SpanDetail';
import {useSpan} from 'providers/Span/Span.provider';
import SpanDetail from '../SpanDetail/SpanDetail';
import {LeftPanel, PanelContainer} from '../ResizablePanels';

const panel = {
Expand All @@ -18,7 +18,7 @@ const SpanDetailsPanel = () => {
>
{size => (
<PanelContainer $isOpen={size.isOpen}>
<SpanDetail span={selectedSpan} />
<SpanDetail span={selectedSpan} AttributeRowComponent={TestAttributeRow} SubHeaderComponent={TestSubHeader} />
</PanelContainer>
)}
</LeftPanel>
Expand Down
2 changes: 2 additions & 0 deletions web/src/components/RunDetailTest/Visualization.tsx
Expand Up @@ -7,6 +7,7 @@ import {useTestSpecForm} from 'components/TestSpecForm/TestSpecForm.provider';
import DAG from 'components/Visualization/components/DAG';
import Timeline from 'components/Visualization/components/Timeline';
import {TestRunStage} from 'constants/TestRunEvents.constants';
import {NodeTypesEnum} from 'constants/Visualization.constants';
import Span from 'models/Span.model';
import TestRunEvent from 'models/TestRunEvent.model';
import {useSpan} from 'providers/Span/Span.provider';
Expand Down Expand Up @@ -88,6 +89,7 @@ const Visualization = ({runEvents, runState, spans, type}: IProps) => {
<Timeline
isMatchedMode={matchedSpans.length > 0 || isOpen}
matchedSpans={matchedSpans}
nodeType={NodeTypesEnum.TestSpan}
onNavigateToSpan={onNavigateToSpan}
onNodeClick={onNodeClickTimeline}
selectedSpan={selectedSpan?.id ?? ''}
Expand Down
28 changes: 13 additions & 15 deletions web/src/components/RunDetailTrace/AnalyzerPanel.tsx
Expand Up @@ -15,20 +15,18 @@ const panel = {
isDefaultOpen: true,
};

const AnalyzerPanel = ({run}: IProps) => {
return (
<RightPanel panel={panel}>
{size => (
<PanelContainer $isOpen={size.isOpen}>
{isRunStateFinished(run.state) ? (
<AnalyzerResult result={run.linter} trace={run?.trace ?? Trace({})} />
) : (
<SkeletonResponse />
)}
</PanelContainer>
)}
</RightPanel>
);
};
const AnalyzerPanel = ({run}: IProps) => (
<RightPanel panel={panel}>
{size => (
<PanelContainer $isOpen={size.isOpen}>
{isRunStateFinished(run.state) ? (
<AnalyzerResult result={run.linter} trace={run?.trace ?? Trace({})} />
) : (
<SkeletonResponse />
)}
</PanelContainer>
)}
</RightPanel>
);

export default AnalyzerPanel;
12 changes: 9 additions & 3 deletions web/src/components/RunDetailTrace/SpanDetailsPanel.tsx
@@ -1,10 +1,10 @@
import {useNavigate} from 'react-router-dom';
import {useCallback} from 'react';
import {useAppSelector} from 'redux/hooks';
import TraceSelectors from 'selectors/Trace.selectors';
import SpanDetail, {TraceAttributeRow, TraceSubHeader} from 'components/SpanDetail';
import TestRun from 'models/TestRun.model';
import SpanSelectors from 'selectors/Span.selectors';
import SpanDetail from '../SpanDetail/SpanDetail';
import TraceSelectors from 'selectors/Trace.selectors';
import {LeftPanel, PanelContainer} from '../ResizablePanels';

interface IProps {
Expand Down Expand Up @@ -35,7 +35,13 @@ const SpanDetailsPanel = ({run, testId}: IProps) => {
>
{size => (
<PanelContainer $isOpen={size.isOpen}>
<SpanDetail onCreateTestSpec={handleOnCreateSpec} searchText={searchText} span={span} />
<SpanDetail
onCreateTestSpec={handleOnCreateSpec}
searchText={searchText}
span={span}
AttributeRowComponent={TraceAttributeRow}
SubHeaderComponent={TraceSubHeader}
/>
</PanelContainer>
)}
</LeftPanel>
Expand Down
2 changes: 2 additions & 0 deletions web/src/components/RunDetailTrace/Visualization.tsx
@@ -1,5 +1,6 @@
import RunEvents from 'components/RunEvents';
import {TestRunStage} from 'constants/TestRunEvents.constants';
import {NodeTypesEnum} from 'constants/Visualization.constants';
import TestRunEvent from 'models/TestRunEvent.model';
import {useCallback, useEffect} from 'react';
import {Node, NodeChange} from 'react-flow-renderer';
Expand Down Expand Up @@ -84,6 +85,7 @@ const Visualization = ({runEvents, runState, spans, type}: IProps) => {
<Timeline
isMatchedMode={isMatchedMode}
matchedSpans={matchedSpans}
nodeType={NodeTypesEnum.TraceSpan}
onNavigateToSpan={onNavigateToSpan}
onNodeClick={onNodeClickTimeline}
selectedSpan={selectedSpan}
Expand Down
4 changes: 4 additions & 0 deletions web/src/components/SpanDetail/Attributes.tsx
Expand Up @@ -4,6 +4,7 @@ import {OtelReference} from 'components/TestSpecForm/hooks/useGetOTELSemanticCon
import TestRunOutput from 'models/TestRunOutput.model';
import {TSpanFlatAttribute} from 'types/Span.types';
import {TTestSpecSummary} from 'types/TestRun.types';
import {IPropsAttributeRow} from './SpanDetail';
import * as S from './SpanDetail.styled';

interface IProps {
Expand All @@ -14,6 +15,7 @@ interface IProps {
testOutputs?: TestRunOutput[];
onCreateTestSpec(attribute: TSpanFlatAttribute): void;
onCreateOutput(attribute: TSpanFlatAttribute): void;
AttributeRowComponent: React.ComponentType<IPropsAttributeRow>;
}

const Attributes = ({
Expand All @@ -24,6 +26,7 @@ const Attributes = ({
testOutputs,
onCreateTestSpec,
onCreateOutput,
AttributeRowComponent,
}: IProps) => {
const containerRef = useRef<HTMLDivElement>(null);
const [topPosition, setTopPosition] = useState(0);
Expand All @@ -42,6 +45,7 @@ const Attributes = ({
testOutputs={testOutputs}
onCreateTestSpec={onCreateTestSpec}
onCreateOutput={onCreateOutput}
AttributeRowComponent={AttributeRowComponent}
/>
</S.AttributesContainer>
);
Expand Down
@@ -1,17 +1,17 @@
import Highlighted from '../Highlighted';
import {Text, TextContainer} from './AttributeRow.styled';
import Highlighted from 'components/Highlighted';
import * as S from './BaseAttributeRow.styled';

interface IProps {
searchText?: string;
title: string;
}

const AttributeTitle = ({searchText = '', title}: IProps) => (
<TextContainer>
<Text type="secondary">
<S.TextContainer>
<S.Text type="secondary">
<Highlighted text={title} highlight={searchText} />
</Text>
</TextContainer>
</S.Text>
</S.TextContainer>
);

export default AttributeTitle;
@@ -1,21 +1,10 @@
import {InfoCircleOutlined} from '@ant-design/icons';
import {Tag as AntdTag, Typography} from 'antd';
import styled from 'styled-components';
import TestOutputMark from 'components/TestOutputMark';
import moreIcon from 'assets/more.svg';

export {default as AttributeTitle} from './AttributeTitle';

export const Container = styled.div`
background-color: ${({theme}) => theme.color.white};
display: flex;
margin-bottom: 4px;
padding: 12px;
transition: background-color 0.2s ease;
&:hover {
background-color: ${({theme}) => theme.color.background};
}
`;

export const Header = styled.div`
Expand Down Expand Up @@ -68,13 +57,6 @@ export const InfoIcon = styled(InfoCircleOutlined)`
margin: 4px;
`;

export const OutputsMark = styled(TestOutputMark)`
&& {
color: ${({theme}) => theme.color.textSecondary};
margin: 4px;
}
`;

export const MoreIcon = styled.img.attrs({
src: moreIcon,
})``;
Expand Up @@ -3,49 +3,33 @@ import parse from 'html-react-parser';
import MarkdownIt from 'markdown-it';
import {useMemo} from 'react';

import AssertionResultChecks from 'components/AssertionResultChecks';
import AttributeActions from 'components/AttributeActions/AttributeActions';
import AttributeValue from 'components/AttributeValue';
import {OtelReference} from 'components/TestSpecForm/hooks/useGetOTELSemanticConventionAttributesInfo';
import TestOutput from 'models/TestOutput.model';
import TestRunOutput from 'models/TestRunOutput.model';
import SpanAttributeService from 'services/SpanAttribute.service';
import {TSpanFlatAttribute} from 'types/Span.types';
import {TTestSpecSummary} from 'types/TestRun.types';
import * as S from './AttributeRow.styled';
import AttributeTitle from './AttributeTitle';
import * as S from './BaseAttributeRow.styled';

interface IProps {
attribute: TSpanFlatAttribute;
searchText?: string;
semanticConventions: OtelReference;
testSpecs?: TTestSpecSummary;
testOutputs?: TestRunOutput[];
onCreateTestSpec(attribute: TSpanFlatAttribute): void;
onCreateOutput(attribute: TSpanFlatAttribute): void;
}

const AttributeRow = ({
const BaseAttributeRow = ({
attribute: {key, value},
attribute,
searchText,
semanticConventions,
testSpecs,
testOutputs,
onCreateTestSpec,
onCreateOutput,
}: IProps) => {
const semanticConvention = SpanAttributeService.getReferencePicker(semanticConventions, key);
const description = useMemo(() => parse(MarkdownIt().render(semanticConvention.description)), [semanticConvention]);
const note = useMemo(() => parse(MarkdownIt().render(semanticConvention.note)), [semanticConvention]);
const attributeTestSpecs = useMemo(
() => SpanAttributeService.getAttributeTestSpecs(key, testSpecs),
[key, testSpecs]
);
const attributeTestOutputs = useMemo(
() => SpanAttributeService.getAttributeTestOutputs(key, testOutputs),
[key, testOutputs]
);

const cypressKey = key.toLowerCase().replace('.', '-');

const content = (
Expand All @@ -64,21 +48,18 @@ const AttributeRow = ({
<S.Container data-cy={`attribute-row-${cypressKey}`}>
<S.Header>
<S.SectionTitle>
<S.AttributeTitle title={key} searchText={searchText} />
<AttributeTitle title={key} searchText={searchText} />

{semanticConvention.description !== '' && (
<Popover content={content} placement="right" title={<S.Title level={3}>{key}</S.Title>}>
<S.InfoIcon />
</Popover>
)}

{!!attributeTestOutputs.length && <S.OutputsMark outputs={attributeTestOutputs as TestOutput[]} />}
</S.SectionTitle>

<S.AttributeValueRow>
<AttributeValue value={value} searchText={searchText} />
</S.AttributeValueRow>
<AssertionResultChecks failed={attributeTestSpecs.failed} passed={attributeTestSpecs.passed} />
</S.Header>

<AttributeActions attribute={attribute} onCreateTestOutput={onCreateOutput} onCreateTestSpec={onCreateTestSpec}>
Expand All @@ -90,4 +71,4 @@ const AttributeRow = ({
);
};

export default AttributeRow;
export default BaseAttributeRow;

0 comments on commit 2e25d52

Please sign in to comment.