소스 검색

SONAR-13058 Add tooltip to issue markers in code margin

tags/8.5.0.37579
Wouter Admiraal 3 년 전
부모
커밋
df26b4e4f9

+ 39
- 17
server/sonar-web/src/main/js/components/SourceViewer/components/LineIssuesIndicator.tsx 파일 보기

@@ -18,9 +18,11 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import * as classNames from 'classnames';
import { uniq } from 'lodash';
import * as React from 'react';
import Tooltip from 'sonar-ui-common/components/controls/Tooltip';
import IssueIcon from 'sonar-ui-common/components/icons/IssueIcon';
import { translate } from 'sonar-ui-common/helpers/l10n';
import { translate, translateWithParameters } from 'sonar-ui-common/helpers/l10n';
import { sortByType } from '../../../helpers/issues';

export interface LineIssuesIndicatorProps {
@@ -36,26 +38,46 @@ export function LineIssuesIndicator(props: LineIssuesIndicatorProps) {
const className = classNames('source-meta', 'source-line-issues', {
'source-line-with-issues': hasIssues
});
const mostImportantIssue = hasIssues ? sortByType(issues)[0] : null;

const handleClick = (e: React.MouseEvent<HTMLElement>) => {
e.preventDefault();
e.currentTarget.blur();
props.onClick();
};
if (!hasIssues) {
return <td className={className} data-line-number={line.line} />;
}

const mostImportantIssue = sortByType(issues)[0];
const issueTypes = uniq(issues.map(i => i.type));

let tooltipContent;
if (issueTypes.length > 1) {
tooltipContent = translate('source_viewer.issues_on_line.multiple_issues');
} else if (issues.length === 1) {
tooltipContent = translateWithParameters(
'source_viewer.issues_on_line.issue_of_type_X',
translate('issue.type', mostImportantIssue.type)
);
} else {
tooltipContent = translateWithParameters(
'source_viewer.issues_on_line.X_issues_of_type_Y',
issues.length,
translate('issue.type', mostImportantIssue.type, 'plural')
);
}

return (
<td className={className} data-line-number={line.line}>
{hasIssues && (
<span
aria-label={translate('source_viewer.issues_on_line', issuesOpen ? 'hide' : 'show')}
onClick={handleClick}
role="button"
tabIndex={0}>
{mostImportantIssue != null && <IssueIcon type={mostImportantIssue.type} />}
{issues.length > 1 && <span className="source-line-issues-counter">{issues.length}</span>}
</span>
)}
<span
aria-label={translate('source_viewer.issues_on_line', issuesOpen ? 'hide' : 'show')}
onClick={(e: React.MouseEvent<HTMLElement>) => {
e.preventDefault();
e.currentTarget.blur();
props.onClick();
}}
role="button"
tabIndex={0}>
<Tooltip overlay={tooltipContent}>
<IssueIcon type={mostImportantIssue.type} />
</Tooltip>
{issues.length > 1 && <span className="source-line-issues-counter">{issues.length}</span>}
</span>
</td>
);
}

+ 5
- 2
server/sonar-web/src/main/js/components/SourceViewer/components/__tests__/LineIssuesIndicator-test.tsx 파일 보기

@@ -29,10 +29,13 @@ it('should render correctly', () => {
shallowRender({
issues: [
mockIssue(false, { key: 'foo', type: 'VULNERABILITY' }),
mockIssue(false, { key: 'bar', type: 'SECURITY_HOTSPOT' })
mockIssue(false, { key: 'bar', type: 'VULNERABILITY' })
]
})
).toMatchSnapshot('diff issue types');
).toMatchSnapshot('multiple issues, same type');
expect(
shallowRender({ issues: [mockIssue(false, { key: 'foo', type: 'VULNERABILITY' })] })
).toMatchSnapshot('single issue');
expect(shallowRender({ issues: [] })).toMatchSnapshot('no issues');
});


+ 37
- 7
server/sonar-web/src/main/js/components/SourceViewer/components/__tests__/__snapshots__/LineIssuesIndicator-test.tsx.snap 파일 보기

@@ -11,9 +11,13 @@ exports[`should render correctly: default 1`] = `
role="button"
tabIndex={0}
>
<IssueIcon
type="BUG"
/>
<Tooltip
overlay="source_viewer.issues_on_line.multiple_issues"
>
<IssueIcon
type="BUG"
/>
</Tooltip>
<span
className="source-line-issues-counter"
>
@@ -23,7 +27,7 @@ exports[`should render correctly: default 1`] = `
</td>
`;

exports[`should render correctly: diff issue types 1`] = `
exports[`should render correctly: multiple issues, same type 1`] = `
<td
className="source-meta source-line-issues source-line-with-issues"
data-line-number={3}
@@ -34,9 +38,13 @@ exports[`should render correctly: diff issue types 1`] = `
role="button"
tabIndex={0}
>
<IssueIcon
type="VULNERABILITY"
/>
<Tooltip
overlay="source_viewer.issues_on_line.X_issues_of_type_Y.2.issue.type.VULNERABILITY.plural"
>
<IssueIcon
type="VULNERABILITY"
/>
</Tooltip>
<span
className="source-line-issues-counter"
>
@@ -52,3 +60,25 @@ exports[`should render correctly: no issues 1`] = `
data-line-number={3}
/>
`;

exports[`should render correctly: single issue 1`] = `
<td
className="source-meta source-line-issues source-line-with-issues"
data-line-number={3}
>
<span
aria-label="source_viewer.issues_on_line.show"
onClick={[Function]}
role="button"
tabIndex={0}
>
<Tooltip
overlay="source_viewer.issues_on_line.issue_of_type_X.issue.type.VULNERABILITY"
>
<IssueIcon
type="VULNERABILITY"
/>
</Tooltip>
</span>
</td>
`;

+ 3
- 0
sonar-core/src/main/resources/org/sonar/l10n/core.properties 파일 보기

@@ -2540,6 +2540,9 @@ source_viewer.tooltip.no_information_about_tests=There is no extra information a
source_viewer.tooltip.scm.commited_on=Committed on
source_viewer.tooltip.scm.revision=Revision

source_viewer.issues_on_line.multiple_issues=There are multiple issues on this line.
source_viewer.issues_on_line.issue_of_type_X=There is a {0} on this line
source_viewer.issues_on_line.X_issues_of_type_Y=There are {0} {1} on this line
source_viewer.issues_on_line.show=Click to show all issues on this line
source_viewer.issues_on_line.hide=Click to hide all issues on this line


Loading…
취소
저장