Skip to content

Commit

Permalink
feat(frontend): add independent trace vs test data (#2815)
Browse files Browse the repository at this point in the history
  • Loading branch information
jorgeepc committed Jun 28, 2023
1 parent e6a6d5e commit 62d8ccd
Show file tree
Hide file tree
Showing 43 changed files with 517 additions and 471 deletions.
@@ -1,17 +1,17 @@
import {IResult} from 'types/Assertion.types';
import AttributeCheck from './ResultCheck';
import {TTestSpec} from 'types/TestRun.types';
import ResultCheck from './ResultCheck';
import * as S from './AssertionResultChecks.styled';

interface IProps {
failed: IResult[];
passed: IResult[];
failed: TTestSpec[];
passed: TTestSpec[];
styleType?: 'node' | 'summary' | 'default';
}

const AssertionResultChecks = ({passed, failed, styleType}: IProps) => (
<S.Container>
{Boolean(passed.length) && <AttributeCheck items={passed} type="success" styleType={styleType} />}
{Boolean(failed.length) && <AttributeCheck items={failed} type="error" styleType={styleType} />}
{Boolean(passed.length) && <ResultCheck items={passed} type="success" styleType={styleType} />}
{Boolean(failed.length) && <ResultCheck items={failed} type="error" styleType={styleType} />}
</S.Container>
);

Expand Down
17 changes: 8 additions & 9 deletions web/src/components/AssertionResultChecks/ResultCheck.tsx
Expand Up @@ -3,37 +3,36 @@ import {uniqBy} from 'lodash';

import {useTestSpecs} from 'providers/TestSpecs/TestSpecs.provider';
import TraceAnalyticsService from 'services/Analytics/TestRunAnalytics.service';
import {IResult} from 'types/Assertion.types';
import {TTestSpec} from 'types/TestRun.types';
import * as S from './AssertionResultChecks.styled';

interface IProps {
items: IResult[];
items: TTestSpec[];
type: 'error' | 'success';
styleType?: 'node' | 'summary' | 'default';
}

const ResultCheck = ({items, type, styleType = 'default'}: IProps) => {
const {setSelectedSpec} = useTestSpecs();

const handleOnClick = (id: string) => {
const handleOnClick = (selector: string) => {
TraceAnalyticsService.onAttributeCheckClick();
const {assertionResult} = items.find(item => item.id === id)!;
setSelectedSpec(assertionResult.selector);
setSelectedSpec(selector);
};

const menuLayout = (
<Menu
items={uniqBy(items, 'id').map(item => ({
key: item.id,
label: item.label,
items={uniqBy(items, 'selector').map(item => ({
key: item.selector,
label: item.selector,
}))}
onClick={({key}) => handleOnClick(key)}
/>
);

if (items.length === 1) {
return (
<div onClick={() => handleOnClick(items[0].id)}>
<div onClick={() => handleOnClick(items[0].selector)}>
<S.CustomBadge status={type} text={items.length} $styleType={styleType} />
</div>
);
Expand Down
2 changes: 2 additions & 0 deletions web/src/components/AssertionResultChecks/index.ts
@@ -0,0 +1,2 @@
// eslint-disable-next-line no-restricted-exports
export {default} from './AssertionResultChecks';
28 changes: 14 additions & 14 deletions web/src/components/AttributeList/AttributeList.tsx
@@ -1,42 +1,42 @@
import AttributeRow from 'components/AttributeRow';
import {OtelReference} from 'components/TestSpecForm/hooks/useGetOTELSemanticConventionAttributesInfo';
import {TResultAssertions} from 'types/Assertion.types';
import TestRunOutput from 'models/TestRunOutput.model';
import {TSpanFlatAttribute} from 'types/Span.types';
import TestOutput from 'models/TestOutput.model';
import {TTestSpecSummary} from 'types/TestRun.types';
import * as S from './AttributeList.styled';
import EmptyAttributeList from './EmptyAttributeList';

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

const AttributeList = ({
assertions,
attributeList,
onCreateTestSpec,
onCreateOutput,
searchText,
semanticConventions,
outputs,
testSpecs,
testOutputs,
onCreateTestSpec,
onCreateOutput,
}: IProps) => {
return attributeList.length ? (
<S.AttributeList data-cy="attribute-list">
{attributeList.map(attribute => (
<AttributeRow
searchText={searchText}
assertions={assertions}
attribute={attribute}
key={attribute.key}
attribute={attribute}
searchText={searchText}
semanticConventions={semanticConventions}
testSpecs={testSpecs}
testOutputs={testOutputs}
onCreateTestSpec={onCreateTestSpec}
onCreateOutput={onCreateOutput}
semanticConventions={semanticConventions}
outputs={outputs}
/>
))}
</S.AttributeList>
Expand Down
Expand Up @@ -16,10 +16,9 @@ describe('AttributeList', () => {
const {getByTestId} = render(
<AttributeList
attributeList={attributeList}
semanticConventions={{}}
onCreateOutput={onCreateOutput}
onCreateTestSpec={onCreateTestSpec}
semanticConventions={{}}
outputs={[]}
/>
);

Expand All @@ -30,10 +29,9 @@ describe('AttributeList', () => {
const {getByTestId} = render(
<AttributeList
attributeList={[]}
semanticConventions={{}}
onCreateOutput={onCreateOutput}
onCreateTestSpec={onCreateTestSpec}
semanticConventions={{}}
outputs={[]}
/>
);

Expand Down
35 changes: 18 additions & 17 deletions web/src/components/AttributeRow/AttributeRow.tsx
Expand Up @@ -3,46 +3,47 @@ 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 {TResultAssertions} from 'types/Assertion.types';
import {TSpanFlatAttribute} from 'types/Span.types';
import TestOutput from 'models/TestOutput.model';
import {TTestSpecSummary} from 'types/TestRun.types';
import * as S from './AttributeRow.styled';
import AssertionResultChecks from '../AssertionResultChecks/AssertionResultChecks';

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

const AttributeRow = ({
assertions = {},
attribute: {key, value},
attribute,
onCreateTestSpec,
searchText,
semanticConventions,
testSpecs,
testOutputs,
onCreateTestSpec,
onCreateOutput,
outputs,
}: 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 {failed, passed} = useMemo(
() => SpanAttributeService.getAttributeAssertionResults(key, assertions),
[assertions, key]
const attributeTestSpecs = useMemo(
() => SpanAttributeService.getAttributeTestSpecs(key, testSpecs),
[key, testSpecs]
);
const attributeOutputs = useMemo(
() => SpanAttributeService.getOutputsFromAttributeName(key, outputs),
[key, outputs]
const attributeTestOutputs = useMemo(
() => SpanAttributeService.getAttributeTestOutputs(key, testOutputs),
[key, testOutputs]
);

const cypressKey = key.toLowerCase().replace('.', '-');
Expand Down Expand Up @@ -71,13 +72,13 @@ const AttributeRow = ({
</Popover>
)}

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

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

<AttributeActions attribute={attribute} onCreateTestOutput={onCreateOutput} onCreateTestSpec={onCreateTestSpec}>
Expand Down
Expand Up @@ -14,12 +14,11 @@ describe('AttributeRow', () => {
it('should render correctly', () => {
const {getByText} = render(
<AttributeRow
searchText=""
attribute={attribute}
searchText=""
semanticConventions={{}}
onCreateOutput={onCreateOutput}
onCreateTestSpec={onCreateTestSpec}
semanticConventions={{}}
outputs={[]}
/>
);

Expand Down
28 changes: 18 additions & 10 deletions web/src/components/SpanDetail/Attributes.tsx
@@ -1,22 +1,30 @@
import {useEffect, useRef, useState} from 'react';
import AttributeList from 'components/AttributeList';
import {OtelReference} from 'components/TestSpecForm/hooks/useGetOTELSemanticConventionAttributesInfo';
import {TResultAssertions} from 'types/Assertion.types';
import TestRunOutput from 'models/TestRunOutput.model';
import {TSpanFlatAttribute} from 'types/Span.types';
import TestOutput from 'models/TestOutput.model';
import {TTestSpecSummary} from 'types/TestRun.types';
import * as S from './SpanDetail.styled';

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

const Attributes = ({assertions, attributeList, outputs, onCreateTestSpec, onCreateOutput, searchText, semanticConventions}: IProps) => {
const Attributes = ({
attributeList,
searchText,
semanticConventions,
testSpecs,
testOutputs,
onCreateTestSpec,
onCreateOutput,
}: IProps) => {
const containerRef = useRef<HTMLDivElement>(null);
const [topPosition, setTopPosition] = useState(0);

Expand All @@ -27,13 +35,13 @@ const Attributes = ({assertions, attributeList, outputs, onCreateTestSpec, onCre
return (
<S.AttributesContainer $top={topPosition} ref={containerRef}>
<AttributeList
assertions={assertions}
attributeList={attributeList}
onCreateTestSpec={onCreateTestSpec}
onCreateOutput={onCreateOutput}
searchText={searchText}
semanticConventions={semanticConventions}
outputs={outputs}
testSpecs={testSpecs}
testOutputs={testOutputs}
onCreateTestSpec={onCreateTestSpec}
onCreateOutput={onCreateOutput}
/>
</S.AttributesContainer>
);
Expand Down
27 changes: 11 additions & 16 deletions web/src/components/SpanDetail/Header.tsx
@@ -1,29 +1,22 @@
import {SettingOutlined, ToolOutlined} from '@ant-design/icons';
import {Space, Tooltip} from 'antd';
import {useMemo} from 'react';
import * as SSpanNode from 'components/Visualization/components/DAG/SpanNode.styled';
import AssertionResultChecks from 'components/AssertionResultChecks';
import * as SSpanNode from 'components/Visualization/components/DAG/BaseSpanNode/BaseSpanNode.styled';
import {SemanticGroupNamesToText} from 'constants/SemanticGroupNames.constants';
import {SpanKindToText} from 'constants/Span.constants';
import SpanService from 'services/Span.service';
import {TResultAssertions} from 'types/Assertion.types';
import Span from 'models/Span.model';
import {useTestRun} from 'providers/TestRun/TestRun.provider';
import SpanService from 'services/Span.service';
import {TAnalyzerError, TTestSpecSummary} from 'types/TestRun.types';
import * as S from './SpanDetail.styled';
import AssertionResultChecks from '../AssertionResultChecks/AssertionResultChecks';

interface IProps {
span?: Span;
assertions?: TResultAssertions;
analyzerErrors?: TAnalyzerError[];
testSpecs?: TTestSpecSummary;
}

const Header = ({span, assertions = {}}: IProps) => {
const Header = ({span, analyzerErrors, testSpecs}: IProps) => {
const {kind, name, service, system, type} = SpanService.getSpanInfo(span);
const {failed, passed} = useMemo(() => SpanService.getAssertionResultSummary(assertions), [assertions]);
const {runLinterResultsBySpan} = useTestRun();
const lintErrors = useMemo(
() => SpanService.filterLintErrorsBySpan(runLinterResultsBySpan, span?.id ?? ''),
[runLinterResultsBySpan, span?.id]
);

if (!span) {
return (
Expand All @@ -38,7 +31,7 @@ const Header = ({span, assertions = {}}: IProps) => {
<S.Column>
<Space>
<SSpanNode.BadgeType $hasMargin count={SemanticGroupNamesToText[type]} $type={type} />
{!!lintErrors.length && (
{!!analyzerErrors && (
<Tooltip title="The analyzer found errors in this span">
<S.LintErrorIcon />
</Tooltip>
Expand All @@ -59,7 +52,9 @@ const Header = ({span, assertions = {}}: IProps) => {
)}
</S.Column>
<S.Row>
<AssertionResultChecks failed={failed} passed={passed} styleType="summary" />
{!!testSpecs && (
<AssertionResultChecks failed={testSpecs.failed} passed={testSpecs.passed} styleType="summary" />
)}
</S.Row>
</S.Header>
);
Expand Down

0 comments on commit 62d8ccd

Please sign in to comment.