diff --git a/web/src/components/RunDetailTrace/LintResults.styled.ts b/web/src/components/AnalyzerResult/AnalyzerResult.styled.ts similarity index 82% rename from web/src/components/RunDetailTrace/LintResults.styled.ts rename to web/src/components/AnalyzerResult/AnalyzerResult.styled.ts index de10138bd6..251d93c095 100644 --- a/web/src/components/RunDetailTrace/LintResults.styled.ts +++ b/web/src/components/AnalyzerResult/AnalyzerResult.styled.ts @@ -1,6 +1,7 @@ import {CheckCircleFilled, CloseCircleFilled, DownOutlined, UpOutlined} from '@ant-design/icons'; import {Button, Collapse, Progress, Typography} from 'antd'; import styled from 'styled-components'; +import noResultsIcon from 'assets/SpanAssertionsEmptyState.svg'; export const Container = styled.div` padding: 24px; @@ -133,3 +134,30 @@ export const UpCollapseIcon = styled(UpOutlined)` opacity: 0.5; font-size: ${({theme}) => theme.size.xs}; `; + +export const EmptyContainer = styled.div` + align-items: center; + display: flex; + flex-direction: column; + height: calc(100% - 70px); + justify-content: center; + margin-top: 50px; +`; + +export const EmptyIcon = styled.img.attrs({ + src: noResultsIcon, +})` + height: auto; + margin-bottom: 16px; + width: 90px; +`; + +export const EmptyText = styled(Typography.Text)` + color: ${({theme}) => theme.color.textSecondary}; +`; + +export const EmptyTitle = styled(Typography.Title).attrs({level: 3})``; + +export const ConfigureButtonContainer = styled.div` + margin-top: 6px; +`; diff --git a/web/src/components/AnalyzerResult/AnalyzerResult.tsx b/web/src/components/AnalyzerResult/AnalyzerResult.tsx new file mode 100644 index 0000000000..b6fe069b0d --- /dev/null +++ b/web/src/components/AnalyzerResult/AnalyzerResult.tsx @@ -0,0 +1,71 @@ +import {Link} from 'react-router-dom'; +import {Col, Row, Tooltip} from 'antd'; +import LinterResult from 'models/LinterResult.model'; +import Trace from 'models/Trace.model'; +import {DISCORD_URL, OCTOLIINT_ISSUE_URL} from 'constants/Common.constants'; +import {useSettingsValues} from 'providers/SettingsValues/SettingsValues.provider'; +import * as S from './AnalyzerResult.styled'; +import LintScore from '../LintScore/LintScore'; +import BetaBadge from '../BetaBadge/BetaBadge'; +import Empty from './Empty'; +import Plugins from './Plugins'; + +interface IProps { + result: LinterResult; + trace: Trace; +} + +const AnalyzerResult = ({result: {score, passed, plugins = []}, trace}: IProps) => { + const {linter} = useSettingsValues(); + + return ( + + + Analyzer Results + + + The Tracetest Analyzer its a plugin based framework used to analyze OpenTelemetry traces to help teams improve + their instrumentation data, find potential problems and provide tips to fix the problems.{' '} + {linter.enabled ? ( + <> + If you want to disable the analyzer for all tests, go to the{' '} + settings page. + + ) : ( + '' + )} + We have released this initial version to get feedback from the community. Have thoughts about how to improve the + Tracetest Analyzer? Add to this Issue or Discord! + + + {plugins.length ? ( + <> + + + + + Trace Analyzer Result + + + + {plugins.map(plugin => ( + + + + {plugin.name} + + + + + ))} + + + + ) : ( + + )} + + ); +}; + +export default AnalyzerResult; diff --git a/web/src/components/RunDetailTrace/CollapseIcon.tsx b/web/src/components/AnalyzerResult/CollapseIcon.tsx similarity index 85% rename from web/src/components/RunDetailTrace/CollapseIcon.tsx rename to web/src/components/AnalyzerResult/CollapseIcon.tsx index 19daf86e2e..7e22481eca 100644 --- a/web/src/components/RunDetailTrace/CollapseIcon.tsx +++ b/web/src/components/AnalyzerResult/CollapseIcon.tsx @@ -1,4 +1,4 @@ -import * as S from './LintResults.styled'; +import * as S from './AnalyzerResult.styled'; interface IProps { isCollapsed: boolean; diff --git a/web/src/components/AnalyzerResult/Empty.tsx b/web/src/components/AnalyzerResult/Empty.tsx new file mode 100644 index 0000000000..b5ac0b7783 --- /dev/null +++ b/web/src/components/AnalyzerResult/Empty.tsx @@ -0,0 +1,22 @@ +import {Button} from 'antd'; +import {Link} from 'react-router-dom'; +import * as S from './AnalyzerResult.styled'; + +const Empty = () => { + return ( + + + There are no Analyzer results yet + Please configure the Tracetest Analyzer settings to see result + + + + + + + ); +}; + +export default Empty; diff --git a/web/src/components/AnalyzerResult/Plugins.tsx b/web/src/components/AnalyzerResult/Plugins.tsx new file mode 100644 index 0000000000..9e2c50ac47 --- /dev/null +++ b/web/src/components/AnalyzerResult/Plugins.tsx @@ -0,0 +1,105 @@ +import {useCallback} from 'react'; +import {CaretUpFilled} from '@ant-design/icons'; +import {Collapse, Space, Tooltip, Typography} from 'antd'; +import {useAppDispatch} from 'redux/hooks'; +import {selectSpan} from 'redux/slices/Trace.slice'; +import LinterResult from 'models/LinterResult.model'; +import Trace from 'models/Trace.model'; +import Span from 'models/Span.model'; +import CollapseIcon from './CollapseIcon'; +import LintScore from '../LintScore/LintScore'; +import * as S from './AnalyzerResult.styled'; + +interface IProps { + plugins: LinterResult['plugins']; + trace: Trace; +} + +function getSpanName(spans: Span[], spanId: string) { + const span = spans.find(s => s.id === spanId); + return span?.name ?? ''; +} + +const Plugins = ({plugins, trace}: IProps) => { + const dispatch = useAppDispatch(); + + const onSpanResultClick = useCallback( + (spanId: string) => { + dispatch(selectSpan({spanId})); + }, + [dispatch] + ); + + return ( + }> + {plugins.map(plugin => ( + + + {plugin.name} + {plugin.description} + + } + key={plugin.name} + > + {plugin.rules.map(rule => ( + + + + + {rule.passed ? : } + + {rule.name} + + + + + {rule.description} + + + + + {rule?.results?.map((result, resultIndex) => ( + // eslint-disable-next-line react/no-array-index-key +
+ {result.passed ? ( + } + onClick={() => onSpanResultClick(result.spanId)} + type="link" + > + {getSpanName(trace.spans, result.spanId)} + + ) : ( + <> + } + onClick={() => onSpanResultClick(result.spanId)} + type="link" + $error + > + {getSpanName(trace.spans, result.spanId)} + +
+ {result.errors.map((error, index) => ( + // eslint-disable-next-line react/no-array-index-key +
+ {error} +
+ ))} +
+ + )} +
+ ))} +
+
+ ))} +
+ ))} +
+ ); +}; + +export default Plugins; diff --git a/web/src/components/AnalyzerResult/index.ts b/web/src/components/AnalyzerResult/index.ts new file mode 100644 index 0000000000..1bcb02b1bb --- /dev/null +++ b/web/src/components/AnalyzerResult/index.ts @@ -0,0 +1,2 @@ +// eslint-disable-next-line no-restricted-exports +export {default} from './AnalyzerResult'; diff --git a/web/src/components/RunDetailTrace/LintResults.tsx b/web/src/components/RunDetailTrace/LintResults.tsx deleted file mode 100644 index ef91c94195..0000000000 --- a/web/src/components/RunDetailTrace/LintResults.tsx +++ /dev/null @@ -1,141 +0,0 @@ -import {CaretUpFilled} from '@ant-design/icons'; -import {Link} from 'react-router-dom'; -import {Col, Collapse, Row, Space, Tooltip, Typography} from 'antd'; -import {useCallback} from 'react'; -import LinterResult from 'models/LinterResult.model'; -import Span from 'models/Span.model'; -import Trace from 'models/Trace.model'; -import {useAppDispatch} from 'redux/hooks'; -import {selectSpan} from 'redux/slices/Trace.slice'; -import {DISCORD_URL, OCTOLIINT_ISSUE_URL} from 'constants/Common.constants'; -import * as S from './LintResults.styled'; -import LintScore from '../LintScore/LintScore'; -import CollapseIcon from './CollapseIcon'; -import BetaBadge from '../BetaBadge/BetaBadge'; - -interface IProps { - linterResult: LinterResult; - trace: Trace; -} - -function getSpanName(spans: Span[], traceId: string) { - const span = spans.find(s => s.id === traceId); - return span?.name ?? ''; -} - -const LintResults = ({linterResult, trace}: IProps) => { - const dispatch = useAppDispatch(); - - const onSpanResultClick = useCallback( - (spanId: string) => { - dispatch(selectSpan({spanId})); - }, - [dispatch] - ); - - return ( - - - Analyzer Results - - - The Tracetest Analyzer its a plugin based framework used to analyze OpenTelemetry traces to help teams improve - their instrumentation data, find potential problems and provide tips to fix the problems. If you want to disable - the analyzer for all tests, go to the settings page. We have released - this initial version to get feedback from the community. Have thoughts about how to improve the Tracetest - Analyzer? Add to this Issue or Discord! - - - - - - - Trace Analyzer Result{' '} - - - - - {linterResult?.plugins?.map(plugin => ( - - - - {plugin.name} - - - - - ))} - - - }> - {linterResult?.plugins?.map(plugin => ( - - - {plugin.name} - {plugin.description} - - } - key={plugin.name} - > - {plugin.rules.map(rule => ( - - - - - {rule.passed ? : } - - {rule.name} - - - - - {rule.description} - - - - - {rule?.results?.map((result, resultIndex) => ( - // eslint-disable-next-line react/no-array-index-key -
- {result.passed ? ( - } - onClick={() => onSpanResultClick(result.spanId)} - type="link" - > - {getSpanName(trace.spans, result.spanId)} - - ) : ( - <> - } - onClick={() => onSpanResultClick(result.spanId)} - type="link" - $error - > - {getSpanName(trace.spans, result.spanId)} - -
- {result.errors.map(error => ( -
- {error} -
- ))} -
- - )} -
- ))} -
-
- ))} -
- ))} -
-
- ); -}; - -export default LintResults; diff --git a/web/src/components/RunDetailTrace/RunDetailTrace.tsx b/web/src/components/RunDetailTrace/RunDetailTrace.tsx index e443f4d597..2d4fc2c68b 100644 --- a/web/src/components/RunDetailTrace/RunDetailTrace.tsx +++ b/web/src/components/RunDetailTrace/RunDetailTrace.tsx @@ -12,7 +12,7 @@ import TestRunEvent from 'models/TestRunEvent.model'; import SpanSelectors from 'selectors/Span.selectors'; import TraceSelectors from 'selectors/Trace.selectors'; import TraceAnalyticsService from 'services/Analytics/TestRunAnalytics.service'; -import LintResults from './LintResults'; +import AnalyzerResult from '../AnalyzerResult'; import * as S from './RunDetailTrace.styled'; import Search from './Search'; import Visualization from './Visualization'; @@ -75,7 +75,7 @@ const RunDetailTrace = ({run, runEvents, testId}: IProps) => { {isRunStateFinished(run.state) ? ( - + ) : ( )}