Skip to content

Commit

Permalink
feat(frontend): adding analyzer empty state (#2642)
Browse files Browse the repository at this point in the history
  • Loading branch information
xoscar committed Jun 2, 2023
1 parent f20a920 commit be3c75f
Show file tree
Hide file tree
Showing 8 changed files with 231 additions and 144 deletions.
@@ -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;
Expand Down Expand Up @@ -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;
`;
71 changes: 71 additions & 0 deletions 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 (
<S.Container>
<S.Title level={2}>
Analyzer Results <BetaBadge />
</S.Title>
<S.Description>
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{' '}
<Link to="/settings?tab=analyzer">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>!
</S.Description>

{plugins.length ? (
<>
<Row gutter={[16, 16]}>
<Col span={8} key="avg_result">
<Tooltip title="Tracetest core system supports analyzer evaluation as part of the testing capabilities.">
<S.ScoreContainer>
<S.Subtitle level={3}>Trace Analyzer Result</S.Subtitle> <LintScore score={score} passed={passed} />
</S.ScoreContainer>
</Tooltip>
</Col>
{plugins.map(plugin => (
<Col span={8} key={plugin.name}>
<Tooltip title={plugin.description}>
<S.ScoreContainer key={plugin.name}>
<S.Subtitle level={3}>{plugin.name}</S.Subtitle>
<LintScore score={plugin.score} passed={plugin.passed} />
</S.ScoreContainer>
</Tooltip>
</Col>
))}
</Row>
<Plugins plugins={plugins} trace={trace} />
</>
) : (
<Empty />
)}
</S.Container>
);
};

export default AnalyzerResult;
@@ -1,4 +1,4 @@
import * as S from './LintResults.styled';
import * as S from './AnalyzerResult.styled';

interface IProps {
isCollapsed: boolean;
Expand Down
22 changes: 22 additions & 0 deletions 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 (
<S.EmptyContainer data-cy="empty-analyzer-results">
<S.EmptyIcon />
<S.EmptyTitle>There are no Analyzer results yet</S.EmptyTitle>
<S.EmptyText>Please configure the Tracetest Analyzer settings to see result</S.EmptyText>
<S.ConfigureButtonContainer>
<Link to="/settings?tab=analyzer">
<Button ghost type="primary">
Configure
</Button>
</Link>
</S.ConfigureButtonContainer>
</S.EmptyContainer>
);
};

export default Empty;
105 changes: 105 additions & 0 deletions 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 (
<Collapse expandIcon={({isActive = false}) => <CollapseIcon isCollapsed={isActive} />}>
{plugins.map(plugin => (
<S.PluginPanel
header={
<Space>
<LintScore width="35px" height="35px" score={plugin.score} passed={plugin.passed} />
<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>
</div>
))}
</div>
</>
)}
</div>
))}
</S.RuleBody>
</S.RuleContainer>
))}
</S.PluginPanel>
))}
</Collapse>
);
};

export default Plugins;
2 changes: 2 additions & 0 deletions web/src/components/AnalyzerResult/index.ts
@@ -0,0 +1,2 @@
// eslint-disable-next-line no-restricted-exports
export {default} from './AnalyzerResult';
141 changes: 0 additions & 141 deletions web/src/components/RunDetailTrace/LintResults.tsx

This file was deleted.

0 comments on commit be3c75f

Please sign in to comment.