Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Chore performance improvements span search #3629

16 changes: 4 additions & 12 deletions web/src/components/AnalyzerResult/AnalyzerResult.styled.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,27 +47,19 @@ export const GlobalScoreContainer = styled.div`
justify-content: center;
`;

export const RuleContainer = styled.div`
border-bottom: ${({theme}) => `1px dashed ${theme.color.borderLight}`};
padding-bottom: 16px;
margin-bottom: 16px;
margin-left: 43px;
`;

export const RuleHeader = styled.div`
display: flex;
flex-direction: row;
justify-content: space-between;
`;

export const Column = styled.div`
display: flex;
flex-direction: column;
margin-bottom: 8px;
export const Column = styled(RuleHeader)`
width: 95%;
`;

export const RuleBody = styled(Column)`
export const RuleBody = styled(Column)<{$resultCount: number}>`
padding-left: 20px;
height: ${({$resultCount}) => ($resultCount > 10 ? '100vh' : `${$resultCount * 32}px`)};
`;

export const Subtitle = styled(Typography.Title)`
Expand Down
10 changes: 4 additions & 6 deletions web/src/components/AnalyzerResult/AnalyzerResult.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import BetaBadge from 'components/BetaBadge/BetaBadge';
import Link from 'components/Link';
import {COMMUNITY_SLACK_URL, OCTOLIINT_ISSUE_URL} from 'constants/Common.constants';
import LinterResult from 'models/LinterResult.model';
import Trace from 'models/Trace.model';
import {useSettingsValues} from 'providers/SettingsValues/SettingsValues.provider';
import * as S from './AnalyzerResult.styled';
import Empty from './Empty';
Expand All @@ -11,10 +10,9 @@ import Plugins from './Plugins';

interface IProps {
result: LinterResult;
trace: Trace;
}

const AnalyzerResult = ({result: {score, minimumScore, plugins = [], passed}, trace}: IProps) => {
const AnalyzerResult = ({result: {score, minimumScore, plugins = [], passed}}: IProps) => {
const {linter} = useSettingsValues();

return (
Expand All @@ -31,13 +29,13 @@ const AnalyzerResult = ({result: {score, minimumScore, plugins = [], passed}, tr
It can be globally disabled for all tests in <Link to="/settings?tab=analyzer">the settings page</Link>.{' '}
</>
)}
We value your feedback on this beta release. Share your thoughts on <a href={COMMUNITY_SLACK_URL}>Slack</a> or add
them to this <a href={OCTOLIINT_ISSUE_URL}>Issue</a>.
We value your feedback on this beta release. Share your thoughts on <a href={COMMUNITY_SLACK_URL}>Slack</a> or
add them to this <a href={OCTOLIINT_ISSUE_URL}>Issue</a>.
</S.Description>
{plugins.length ? (
<>
<GlobalResult score={score} minimumScore={minimumScore} allRulesPassed={passed} />
<Plugins plugins={plugins} trace={trace} />
<Plugins plugins={plugins} />
</>
) : (
<Empty />
Expand Down
11 changes: 6 additions & 5 deletions web/src/components/AnalyzerResult/Plugins.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import {Space, Switch, Typography} from 'antd';
import {useState} from 'react';
import {LinterResultPlugin} from 'models/LinterResult.model';
import Trace from 'models/Trace.model';
import {useAppSelector} from 'redux/hooks';
import TraceSelectors from 'selectors/Trace.selectors';
import TraceAnalyzerAnalytics from 'services/Analytics/TraceAnalyzer.service';
import AnalyzerService from 'services/Analyzer.service';
import * as S from './AnalyzerResult.styled';
Expand All @@ -11,12 +12,12 @@ import Collapse, {CollapsePanel} from '../Collapse';

interface IProps {
plugins: LinterResultPlugin[];
trace: Trace;
}

const Plugins = ({plugins: rawPlugins, trace}: IProps) => {
const Plugins = ({plugins: rawPlugins}: IProps) => {
const [onlyErrors, setOnlyErrors] = useState(false);
const plugins = AnalyzerService.getPlugins(rawPlugins, onlyErrors);
const matchedSpans = useAppSelector(TraceSelectors.selectMatchedSpans);
const plugins = AnalyzerService.getPlugins(rawPlugins, onlyErrors, matchedSpans);

return (
<>
Expand All @@ -38,7 +39,7 @@ const Plugins = ({plugins: rawPlugins, trace}: IProps) => {
key={plugin.name}
>
{plugin.rules.map(rule => (
<Rule rule={rule} key={rule.name} trace={trace} />
<Rule rule={rule} key={rule.name} />
))}
</CollapsePanel>
))}
Expand Down
120 changes: 38 additions & 82 deletions web/src/components/AnalyzerResult/Rule.tsx
Original file line number Diff line number Diff line change
@@ -1,98 +1,54 @@
import {useCallback} from 'react';
import {CaretUpFilled} from '@ant-design/icons';
import {FixedSizeList as List} from 'react-window';
import AutoSizer, {Size} from 'react-virtualized-auto-sizer';
import {Space, Tooltip, Typography} from 'antd';
import {PercentageOutlined} from '@ant-design/icons';
import {LinterResultPluginRule} from 'models/LinterResult.model';
import Trace from 'models/Trace.model';
import {LinterRuleErrorLevel} from 'models/Linter.model';
import {useAppDispatch} from 'redux/hooks';
import {selectSpan} from 'redux/slices/Trace.slice';
import TraceAnalyzerAnalytics from 'services/Analytics/TraceAnalyzer.service';
import * as S from './AnalyzerResult.styled';
import RuleIcon from './RuleIcon';
import RuleLink from './RuleLink';
import RuleResult from './RuleResult';
import Collapse, {CollapsePanel} from '../Collapse';

interface IProps {
rule: LinterResultPluginRule;
trace: Trace;
}

const Rule = ({
rule: {id, tips, passed, description, name, errorDescription, results = [], level, weight = 0},
trace,
}: IProps) => {
const dispatch = useAppDispatch();

const onSpanResultClick = useCallback(
(spanId: string) => {
TraceAnalyzerAnalytics.onSpanNameClick();
dispatch(selectSpan({spanId}));
},
[dispatch]
);

const Rule = ({rule: {tips, id, passed, description, name, level, results, weight = 0}, rule}: IProps) => {
return (
<S.RuleContainer>
<S.Column>
<S.RuleHeader>
<Space>
<RuleIcon passed={passed} level={level} />
<Tooltip title={tips.join(' - ')}>
<Typography.Text strong>{name}</Typography.Text>
</Tooltip>
</Space>
</S.RuleHeader>
<Typography.Text type="secondary" style={{paddingLeft: 20}}>
{description}
</Typography.Text>
{level === LinterRuleErrorLevel.ERROR && (
<Typography.Text type="secondary" style={{paddingLeft: 20}}>
Weight: {weight}
</Typography.Text>
)}
</S.Column>

<S.RuleBody>
{/* TODO: Add a search capability to look for spans in the result list */}
{results?.map((result, resultIndex) => (
// eslint-disable-next-line react/no-array-index-key
<div key={`${result.spanId}-${resultIndex}`}>
<S.SpanButton
icon={<CaretUpFilled />}
onClick={() => onSpanResultClick(result.spanId)}
type="link"
$error={!result.passed}
>
{trace.flat[result.spanId].name ?? ''}
</S.SpanButton>

{!result.passed && result.errors.length > 1 && (
<>
<div>
<Typography.Text>{errorDescription}</Typography.Text>
</div>
<S.List>
{result.errors.map(error => (
<li key={error.value}>
<Tooltip title={error.description}>
<Typography.Text>{error.value}</Typography.Text>
</Tooltip>
</li>
))}
</S.List>
</>
<Collapse>
<CollapsePanel
header={
<S.Column>
<S.RuleHeader>
<Space>
<RuleIcon passed={passed} level={level} />
<Tooltip title={tips.join(' - ')}>
<Typography.Text strong>{name}</Typography.Text>
</Tooltip>
<Typography.Text type="secondary">{description}</Typography.Text>
</Space>
</S.RuleHeader>
{level === LinterRuleErrorLevel.ERROR && (
<Typography.Text type="secondary" style={{paddingLeft: 20}}>
{weight}
<PercentageOutlined />
</Typography.Text>
)}

{!result.passed && result.errors.length === 1 && (
<div>
<Typography.Text>{result.errors[0].description}</Typography.Text>
</div>
</S.Column>
}
key={id}
>
<S.RuleBody $resultCount={results.length}>
<AutoSizer>
{({height, width}: Size) => (
<List height={height} itemCount={results.length} itemData={rule} itemSize={32} width={width}>
{RuleResult}
</List>
)}

{!result.passed && <RuleLink id={id} />}
</div>
))}
</S.RuleBody>
</S.RuleContainer>
</AutoSizer>
</S.RuleBody>
</CollapsePanel>
</Collapse>
);
};

Expand Down
64 changes: 64 additions & 0 deletions web/src/components/AnalyzerResult/RuleResult.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import {Tooltip, Typography} from 'antd';
import {CaretUpFilled} from '@ant-design/icons';
import {useCallback, useMemo} from 'react';
import {LinterResultPluginRule} from 'models/LinterResult.model';
import {useAppDispatch} from 'redux/hooks';
import {selectSpan} from 'redux/slices/Trace.slice';
import {useTestRun} from 'providers/TestRun/TestRun.provider';
import TraceAnalyzerAnalytics from 'services/Analytics/TraceAnalyzer.service';
import * as S from './AnalyzerResult.styled';
import RuleLink from './RuleLink';

interface IProps {
index: number;
data: LinterResultPluginRule;
style: React.CSSProperties;
}

const RuleResult = ({index, data: {results, id, errorDescription}, style}: IProps) => {
const {spanId, passed, errors} = useMemo(() => results[index], [results, index]);
const dispatch = useAppDispatch();
const {
run: {trace},
} = useTestRun();

const onClick = useCallback(() => {
TraceAnalyzerAnalytics.onSpanNameClick();
dispatch(selectSpan({spanId}));
}, [dispatch, spanId]);

return (
<div key={`${spanId}-${index}`} style={style}>
<S.SpanButton icon={<CaretUpFilled />} onClick={onClick} type="link" $error={!passed}>
{trace.flat[spanId].name ?? ''}
</S.SpanButton>

{!passed && errors.length > 1 && (
<>
<div>
<Typography.Text>{errorDescription}</Typography.Text>
</div>
<S.List>
{errors.map(error => (
<li key={error.value}>
<Tooltip title={error.description}>
<Typography.Text>{error.value}</Typography.Text>
</Tooltip>
</li>
))}
</S.List>
</>
)}

{!passed && errors.length === 1 && (
<div>
<Typography.Text>{errors[0].description}</Typography.Text>
</div>
)}

{!passed && <RuleLink id={id} />}
</div>
);
};

export default RuleResult;
7 changes: 3 additions & 4 deletions web/src/components/Fields/Auth/AuthApiKeyBase.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import {Form} from 'antd';
import {Editor} from 'components/Inputs';
import {SupportedEditors} from 'constants/Editor.constants';
import * as S from './Auth.styled';
import SingleLine from '../../Inputs/SingleLine';

interface IProps {
baseName: string[];
Expand All @@ -17,7 +16,7 @@ const AuthApiKeyBase = ({baseName}: IProps) => (
label="Key"
rules={[{required: true}]}
>
<Editor type={SupportedEditors.Interpolation} placeholder="Enter key" />
<SingleLine placeholder="Enter key" />
</Form.Item>
<Form.Item
data-cy="apiKey-value"
Expand All @@ -26,7 +25,7 @@ const AuthApiKeyBase = ({baseName}: IProps) => (
label="Value"
rules={[{required: true}]}
>
<Editor type={SupportedEditors.Interpolation} placeholder="Enter value" />
<SingleLine placeholder="Enter value" />
</Form.Item>
</S.FlexContainer>
</S.Row>
Expand Down
8 changes: 3 additions & 5 deletions web/src/components/Fields/Auth/AuthBasic.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import {Form} from 'antd';
import React from 'react';
import {Editor} from 'components/Inputs';
import {SupportedEditors} from 'constants/Editor.constants';
import * as S from './Auth.styled';
import SingleLine from '../../Inputs/SingleLine';

interface IProps {
baseName: string[];
Expand All @@ -18,7 +16,7 @@ const AuthBasic = ({baseName}: IProps) => (
label="Username"
rules={[{required: true}]}
>
<Editor type={SupportedEditors.Interpolation} />
<SingleLine />
</Form.Item>
<Form.Item
style={{flexBasis: '50%', overflow: 'hidden'}}
Expand All @@ -27,7 +25,7 @@ const AuthBasic = ({baseName}: IProps) => (
data-cy="basic-password"
rules={[{required: true}]}
>
<Editor type={SupportedEditors.Interpolation} />
<SingleLine />
</Form.Item>
</S.FlexContainer>
</S.Row>
Expand Down
5 changes: 2 additions & 3 deletions web/src/components/Fields/Auth/AuthBearer.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
import {Form} from 'antd';
import {Editor} from 'components/Inputs';
import {SupportedEditors} from 'constants/Editor.constants';
import SingleLine from '../../Inputs/SingleLine';

interface IProps {
baseName: string[];
}

const AuthBearer = ({baseName}: IProps) => (
<Form.Item data-cy="bearer-token" name={[...baseName, 'bearer', 'token']} label="Token" rules={[{required: true}]}>
<Editor type={SupportedEditors.Interpolation} />
<SingleLine />
</Form.Item>
);

Expand Down
Loading
Loading