Skip to content

Commit

Permalink
feat(frontend): add errors filter for analyzer results and ux/ui impr…
Browse files Browse the repository at this point in the history
…ovements
  • Loading branch information
jorgeepc committed Jun 14, 2023
1 parent 75d7384 commit b7a1b61
Show file tree
Hide file tree
Showing 15 changed files with 180 additions and 151 deletions.
17 changes: 16 additions & 1 deletion web/src/components/AnalyzerResult/AnalyzerResult.styled.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@ import {Button, Collapse, Progress, Typography} from 'antd';
import styled from 'styled-components';
import noResultsIcon from 'assets/SpanAssertionsEmptyState.svg';

export const StyledCollapse = styled(Collapse)`
background-color: ${({theme}) => theme.color.white};
border: 0;
`;

export const Container = styled.div`
padding: 24px;
`;
Expand Down Expand Up @@ -95,6 +100,8 @@ export const ScoreProgress = styled(Progress)`

export const PluginPanel = styled(Collapse.Panel)`
background-color: ${({theme}) => theme.color.white};
border: ${({theme}) => `1px solid ${theme.color.border}`};
margin-bottom: 12px;
.ant-collapse-content {
background-color: ${({theme}) => theme.color.background};
Expand All @@ -121,7 +128,7 @@ export const CollapseIconContainer = styled.div`
position: absolute;
top: 25%;
right: 16px;
border-left: 1px solid ${({theme}) => theme.color.borderLight}};
border-left: 1px solid ${({theme}) => theme.color.borderLight};
padding-left: 14px;
height: 24px;
align-items: center;
Expand Down Expand Up @@ -163,3 +170,11 @@ export const EmptyTitle = styled(Typography.Title).attrs({level: 3})``;
export const ConfigureButtonContainer = styled.div`
margin-top: 6px;
`;

export const SwitchContainer = styled.div`
align-items: center;
display: flex;
gap: 8px;
justify-content: flex-end;
margin-bottom: 16px;
`;
19 changes: 8 additions & 11 deletions web/src/components/AnalyzerResult/AnalyzerResult.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import {Link} from 'react-router-dom';
import BetaBadge from 'components/BetaBadge/BetaBadge';
import {DISCORD_URL, OCTOLIINT_ISSUE_URL} from 'constants/Common.constants';
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 BetaBadge from '../BetaBadge/BetaBadge';
import Empty from './Empty';
import Plugins from './Plugins';
import GlobalResult from './GlobalResult';
import Plugins from './Plugins';

interface IProps {
result: LinterResult;
Expand All @@ -22,21 +22,18 @@ const AnalyzerResult = ({result: {score, minimumScore, plugins = []}, trace}: IP
<S.Title level={2}>
Analyzer Results <BetaBadge />
</S.Title>

<S.Description>
The Tracetest Analyzer is 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 ? (
{linter.enabled && (
<>
If you want to disable the analyzer for all tests, go to the{' '}
<Link to="/settings?tab=analyzer">settings page</Link>.
It can be globally disabled for all tests in <Link to="/settings?tab=analyzer">the settings page</Link>.{' '}
</>
) : (
''
)}
We have released this initial version to get feedback from the community. Have thoughts about how to improve the
Tracetest Analyzer? Add to this <a href={OCTOLIINT_ISSUE_URL}>Issue</a> or <a href={DISCORD_URL}>Discord</a>!
We value your feedback on this beta release. Share your thoughts on <a href={DISCORD_URL}>Discord</a> or add
them to this <a href={OCTOLIINT_ISSUE_URL}>Issue</a>.
</S.Description>

{plugins.length ? (
<>
<GlobalResult score={score} minimumScore={minimumScore} />
Expand Down
2 changes: 1 addition & 1 deletion web/src/components/AnalyzerResult/CollapseIcon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ interface IProps {

const CollapseIcon = ({isCollapsed}: IProps) => {
return (
<S.CollapseIconContainer>{isCollapsed ? <S.DownCollapseIcon /> : <S.UpCollapseIcon />}</S.CollapseIconContainer>
<S.CollapseIconContainer>{isCollapsed ? <S.UpCollapseIcon /> : <S.DownCollapseIcon />}</S.CollapseIconContainer>
);
};

Expand Down
19 changes: 15 additions & 4 deletions web/src/components/AnalyzerResult/GlobalResult.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import Percentage from 'components/AnalyzerScore/Percentage';
import {TooltipQuestion} from 'components/TooltipQuestion/TooltipQuestion';
import {ANALYZER_DOCUMENTATION_URL} from 'constants/Common.constants';
import * as S from './AnalyzerResult.styled';
import PercentageScore from '../LintScore/PercentageScore';
import {TooltipQuestion} from '../TooltipQuestion/TooltipQuestion';

interface IProps {
score: number;
Expand All @@ -15,10 +16,20 @@ const GlobalResult = ({score, minimumScore}: IProps) => {
<S.GlobalScoreWrapper>
<S.Subtitle level={3}>
Overall Trace Analyzer Score
<TooltipQuestion title="Tracetest core system supports analyzer evaluation as part of the testing capabilities." />
<TooltipQuestion
title={
<>
Tracetest core system supports analyzer evaluation as part of the testing capabilities.{' '}
<a href={ANALYZER_DOCUMENTATION_URL} target="_blank">
Learn more
</a>{' '}
about the Analyzer.
</>
}
/>
</S.Subtitle>
<S.GlobalScoreContainer>
<PercentageScore score={score} />
<Percentage score={score} />
</S.GlobalScoreContainer>
</S.GlobalScoreWrapper>
{!!minimumScore && (
Expand Down
154 changes: 83 additions & 71 deletions web/src/components/AnalyzerResult/Plugins.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
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 {Space, Switch, Tooltip, Typography} from 'antd';
import {useCallback, useState} from 'react';
import AnalyzerScore from 'components/AnalyzerScore/AnalyzerScore';
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 {useAppDispatch} from 'redux/hooks';
import {selectSpan} from 'redux/slices/Trace.slice';
import * as S from './AnalyzerResult.styled';
import CollapseIcon from './CollapseIcon';

const MAX_SCORE = 100;

interface IProps {
plugins: LinterResult['plugins'];
Expand All @@ -22,6 +24,7 @@ function getSpanName(spans: Span[], spanId: string) {

const Plugins = ({plugins, trace}: IProps) => {
const dispatch = useAppDispatch();
const [onlyErrors, setOnlyErrors] = useState(false);

const onSpanResultClick = useCallback(
(spanId: string) => {
Expand All @@ -31,74 +34,83 @@ const Plugins = ({plugins, trace}: IProps) => {
);

return (
<Collapse expandIcon={({isActive = false}) => <CollapseIcon isCollapsed={isActive} />}>
{plugins.map(plugin => (
<S.PluginPanel
header={
<Space>
<LintScore width="35px" height="35px" score={plugin.score} />
<Typography.Text strong>{plugin.name}</Typography.Text>
<Typography.Text type="secondary">{plugin.description}</Typography.Text>
</Space>
}
key={plugin.name}
>
{plugin.rules.map(rule => (
<S.RuleContainer key={rule.name}>
<S.Column>
<S.RuleHeader>
<Space>
{rule.passed ? <S.PassedIcon $small /> : <S.FailedIcon $small />}
<Tooltip title={rule.tips.join(' - ')}>
<Typography.Text strong>{rule.name}</Typography.Text>
</Tooltip>
</Space>
</S.RuleHeader>
<Typography.Text type="secondary" style={{paddingLeft: 20}}>
{rule.description}
</Typography.Text>
</S.Column>
<>
<S.SwitchContainer>
<Switch checked={onlyErrors} id="only_errors_enabled" onChange={() => setOnlyErrors(prev => !prev)} />
<label htmlFor="only_errors_enabled">Show only errors</label>
</S.SwitchContainer>

<S.StyledCollapse expandIcon={({isActive = false}) => <CollapseIcon isCollapsed={isActive} />}>
{plugins
.filter(plugin => !onlyErrors || plugin.score < MAX_SCORE)
.map(plugin => (
<S.PluginPanel
header={
<Space>
<AnalyzerScore width="35px" height="35px" score={plugin.score} />
<Typography.Text strong>{plugin.name}</Typography.Text>
<Typography.Text type="secondary">{plugin.description}</Typography.Text>
</Space>
}
key={plugin.name}
>
{plugin.rules.map(rule => (
<S.RuleContainer key={rule.name}>
<S.Column>
<S.RuleHeader>
<Space>
{rule.passed ? <S.PassedIcon $small /> : <S.FailedIcon $small />}
<Tooltip title={rule.tips.join(' - ')}>
<Typography.Text strong>{rule.name}</Typography.Text>
</Tooltip>
</Space>
</S.RuleHeader>
<Typography.Text type="secondary" style={{paddingLeft: 20}}>
{rule.description}
</Typography.Text>
</S.Column>

<S.RuleBody>
{rule?.results?.map((result, resultIndex) => (
// eslint-disable-next-line react/no-array-index-key
<div key={`${result.spanId}-${resultIndex}`}>
{result.passed ? (
<S.SpanButton
icon={<CaretUpFilled />}
onClick={() => onSpanResultClick(result.spanId)}
type="link"
>
{getSpanName(trace.spans, result.spanId)}
</S.SpanButton>
) : (
<>
<S.SpanButton
icon={<CaretUpFilled />}
onClick={() => onSpanResultClick(result.spanId)}
type="link"
$error
>
{getSpanName(trace.spans, result.spanId)}
</S.SpanButton>
<div>
{result.errors.map((error, index) => (
// eslint-disable-next-line react/no-array-index-key
<div key={index}>
<Typography.Text>{error}</Typography.Text>
<S.RuleBody>
{rule?.results?.map((result, resultIndex) => (
// eslint-disable-next-line react/no-array-index-key
<div key={`${result.spanId}-${resultIndex}`}>
{result.passed ? (
<S.SpanButton
icon={<CaretUpFilled />}
onClick={() => onSpanResultClick(result.spanId)}
type="link"
>
{getSpanName(trace.spans, result.spanId)}
</S.SpanButton>
) : (
<>
<S.SpanButton
icon={<CaretUpFilled />}
onClick={() => onSpanResultClick(result.spanId)}
type="link"
$error
>
{getSpanName(trace.spans, result.spanId)}
</S.SpanButton>
<div>
{result.errors.map((error, index) => (
// eslint-disable-next-line react/no-array-index-key
<div key={index}>
<Typography.Text>{error}</Typography.Text>
</div>
))}
</div>
))}
</div>
</>
)}
</div>
))}
</S.RuleBody>
</S.RuleContainer>
</>
)}
</div>
))}
</S.RuleBody>
</S.RuleContainer>
))}
</S.PluginPanel>
))}
</S.PluginPanel>
))}
</Collapse>
</S.StyledCollapse>
</>
);
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ export const ScoreTexContainer = styled.div`
height: 100%;
`;

export const Score = styled(Typography.Title)`
export const Score = styled(Typography.Title)<{$isLarge?: boolean}>`
&& {
font-size: 12px;
font-size: ${({$isLarge}) => ($isLarge ? '24px' : '12px')};
margin-bottom: 0;
}
`;
Expand Down
25 changes: 25 additions & 0 deletions web/src/components/AnalyzerScore/AnalyzerScore.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import * as S from './AnalyzerScore.styled';

interface IProps {
score: number;
height?: string;
width?: string;
}

const AnalyzerScore = ({score, height, width}: IProps) => (
<S.ScoreWrapper>
<S.ScoreTexContainer>
<S.Score level={1}>{score}</S.Score>
</S.ScoreTexContainer>
<S.ScoreProgress
$height={height}
$width={width}
format={() => ''}
percent={score || 100}
$score={score}
type="circle"
/>
</S.ScoreWrapper>
);

export default AnalyzerScore;
25 changes: 25 additions & 0 deletions web/src/components/AnalyzerScore/Percentage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import * as S from './AnalyzerScore.styled';

interface IProps {
score: number;
height?: string;
width?: string;
}

const Percentage = ({score, height, width}: IProps) => (
<S.PercentageScoreWrapper>
<S.Score level={1} $isLarge>
{score}%
</S.Score>
<S.ScoreProgress
$height={height}
$width={width}
$score={score}
format={() => ''}
percent={score || 100}
type="circle"
/>
</S.PercentageScoreWrapper>
);

export default Percentage;
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
// eslint-disable-next-line no-restricted-exports
export {default} from './LintScore';
export {default} from './AnalyzerScore';

0 comments on commit b7a1b61

Please sign in to comment.