aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--server/sonar-web/src/main/js/apps/coding-rules/components/RuleDetailsDescription.tsx11
-rw-r--r--server/sonar-web/src/main/js/apps/coding-rules/components/RuleDetailsMeta.tsx48
-rw-r--r--server/sonar-web/src/main/js/apps/coding-rules/components/__tests__/RuleDetailsDescription-test.tsx90
-rw-r--r--server/sonar-web/src/main/js/apps/coding-rules/components/__tests__/RuleDetailsMeta-test.tsx84
-rw-r--r--server/sonar-web/src/main/js/apps/coding-rules/components/__tests__/__snapshots__/RuleDetailsDescription-test.tsx.snap64
-rw-r--r--server/sonar-web/src/main/js/apps/coding-rules/components/__tests__/__snapshots__/RuleDetailsMeta-test.tsx.snap283
-rw-r--r--sonar-core/src/main/resources/org/sonar/l10n/core.properties2
7 files changed, 548 insertions, 34 deletions
diff --git a/server/sonar-web/src/main/js/apps/coding-rules/components/RuleDetailsDescription.tsx b/server/sonar-web/src/main/js/apps/coding-rules/components/RuleDetailsDescription.tsx
index b6e5b8455ef..7e8889b80ad 100644
--- a/server/sonar-web/src/main/js/apps/coding-rules/components/RuleDetailsDescription.tsx
+++ b/server/sonar-web/src/main/js/apps/coding-rules/components/RuleDetailsDescription.tsx
@@ -189,18 +189,19 @@ export default class RuleDetailsDescription extends React.PureComponent<Props, S
render() {
const { ruleDetails } = this.props;
+ const hasDescription = !ruleDetails.isExternal || ruleDetails.type !== 'UNKNOWN';
return (
<div className="js-rule-description">
- {ruleDetails.isExternal ? (
- <div className="coding-rules-detail-description rule-desc markdown">
- {translateWithParameters('issue.external_issue_description', ruleDetails.name)}
- </div>
- ) : (
+ {hasDescription ? (
<div
className="coding-rules-detail-description rule-desc markdown"
dangerouslySetInnerHTML={{ __html: ruleDetails.htmlDesc || '' }}
/>
+ ) : (
+ <div className="coding-rules-detail-description rule-desc markdown">
+ {translateWithParameters('issue.external_issue_description', ruleDetails.name)}
+ </div>
)}
{!ruleDetails.templateKey && (
diff --git a/server/sonar-web/src/main/js/apps/coding-rules/components/RuleDetailsMeta.tsx b/server/sonar-web/src/main/js/apps/coding-rules/components/RuleDetailsMeta.tsx
index 52417451371..c74e8ad3df6 100644
--- a/server/sonar-web/src/main/js/apps/coding-rules/components/RuleDetailsMeta.tsx
+++ b/server/sonar-web/src/main/js/apps/coding-rules/components/RuleDetailsMeta.tsx
@@ -28,7 +28,7 @@ import LinkIcon from '../../../components/icons-components/LinkIcon';
import RuleScopeIcon from '../../../components/icons-components/RuleScopeIcon';
import Tooltip from '../../../components/controls/Tooltip';
import DocTooltip from '../../../components/docs/DocTooltip';
-import { translate } from '../../../helpers/l10n';
+import { translate, translateWithParameters } from '../../../helpers/l10n';
import IssueTypeIcon from '../../../components/ui/IssueTypeIcon';
import SeverityHelper from '../../../components/shared/SeverityHelper';
import Dropdown from '../../../components/controls/Dropdown';
@@ -47,6 +47,8 @@ interface Props {
ruleDetails: RuleDetails;
}
+const EXTERNAL_RULE_REPO_PREFIX = 'external_';
+
export default class RuleDetailsMeta extends React.PureComponent<Props> {
renderType = () => {
const { ruleDetails } = this.props;
@@ -207,8 +209,29 @@ export default class RuleDetailsMeta extends React.PureComponent<Props> {
);
};
+ renderExternalBadge = () => {
+ const { ruleDetails } = this.props;
+ if (!ruleDetails.repo) {
+ return null;
+ }
+ const engine = ruleDetails.repo.replace(new RegExp(`^${EXTERNAL_RULE_REPO_PREFIX}`), '');
+ if (!engine) {
+ return null;
+ }
+ return (
+ <Tooltip overlay={translateWithParameters('coding_rules.external_rule.engine', engine)}>
+ <li className="coding-rules-detail-property">
+ <div className="outline-badge badge-tiny-height spacer-left vertical-text-top">
+ {engine}
+ </div>
+ </li>
+ </Tooltip>
+ );
+ };
+
render() {
const { ruleDetails } = this.props;
+ const hasTypeData = !ruleDetails.isExternal || ruleDetails.type !== 'UNKNOWN';
return (
<div className="js-rule-meta">
<header className="page-header">
@@ -230,18 +253,27 @@ export default class RuleDetailsMeta extends React.PureComponent<Props> {
</h3>
</header>
- {!ruleDetails.isExternal && (
+ {hasTypeData && (
<ul className="coding-rules-detail-properties">
{this.renderType()}
{this.renderSeverity()}
- {this.renderStatus()}
- {this.renderScope()}
+ {!ruleDetails.isExternal && (
+ <>
+ {this.renderStatus()}
+ {this.renderScope()}
+ </>
+ )}
{this.renderTags()}
- {this.renderCreationDate()}
+ {!ruleDetails.isExternal && this.renderCreationDate()}
{this.renderRepository()}
- {this.renderTemplate()}
- {this.renderParentTemplate()}
- {this.renderRemediation()}
+ {!ruleDetails.isExternal && (
+ <>
+ {this.renderTemplate()}
+ {this.renderParentTemplate()}
+ {this.renderRemediation()}
+ </>
+ )}
+ {ruleDetails.isExternal && this.renderExternalBadge()}
</ul>
)}
</div>
diff --git a/server/sonar-web/src/main/js/apps/coding-rules/components/__tests__/RuleDetailsDescription-test.tsx b/server/sonar-web/src/main/js/apps/coding-rules/components/__tests__/RuleDetailsDescription-test.tsx
new file mode 100644
index 00000000000..10179121078
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/coding-rules/components/__tests__/RuleDetailsDescription-test.tsx
@@ -0,0 +1,90 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as React from 'react';
+import { shallow } from 'enzyme';
+import RuleDetailsDescription from '../RuleDetailsDescription';
+import { click, change, waitAndUpdate } from '../../../../helpers/testUtils';
+
+jest.mock('../../../../api/rules', () => ({
+ updateRule: jest.fn().mockResolvedValue('updatedrule')
+}));
+
+const RULE = {
+ key: 'squid:S1133',
+ repo: 'squid',
+ name: 'Deprecated code should be removed',
+ createdAt: '2013-07-26T09:40:51+0200',
+ htmlDesc: '<p>Html Description</p>',
+ mdNote: 'Md Note',
+ severity: 'INFO',
+ status: 'READY',
+ lang: 'java',
+ langName: 'Java',
+ type: 'CODE_SMELL'
+};
+
+const EXTERNAL_RULE = {
+ key: 'external_xoo:OneExternalIssuePerLine',
+ repo: 'external_xoo',
+ name: 'xoo:OneExternalIssuePerLine',
+ status: 'READY',
+ isExternal: true,
+ type: 'UNKNOWN'
+};
+
+const EXTERNAL_RULE_WITH_DATA = {
+ key: 'external_xoo:OneExternalIssueWithDetailsPerLine',
+ repo: 'external_xoo',
+ name: 'One external issue per line',
+ createdAt: '2018-05-31T11:19:51+0200',
+ htmlDesc: '<p>Html Description</p>',
+ status: 'READY',
+ isExternal: true,
+ type: 'BUG'
+};
+
+it('should display correctly', () => {
+ expect(getWrapper()).toMatchSnapshot();
+ expect(getWrapper({ ruleDetails: EXTERNAL_RULE })).toMatchSnapshot();
+ expect(getWrapper({ ruleDetails: EXTERNAL_RULE_WITH_DATA })).toMatchSnapshot();
+});
+
+it('should add extra description', async () => {
+ const onChange = jest.fn();
+ const wrapper = getWrapper({ canWrite: true, onChange });
+ click(wrapper.find('#coding-rules-detail-extend-description'));
+ expect(wrapper.find('textarea').exists()).toBeTruthy();
+ change(wrapper.find('textarea'), 'new description');
+ click(wrapper.find('#coding-rules-detail-extend-description-submit'));
+ await waitAndUpdate(wrapper);
+ expect(onChange).toBeCalledWith('updatedrule');
+});
+
+function getWrapper(props = {}) {
+ return shallow(
+ <RuleDetailsDescription
+ canWrite={false}
+ onChange={jest.fn()}
+ organization={undefined}
+ ruleDetails={RULE}
+ {...props}
+ />
+ );
+}
diff --git a/server/sonar-web/src/main/js/apps/coding-rules/components/__tests__/RuleDetailsMeta-test.tsx b/server/sonar-web/src/main/js/apps/coding-rules/components/__tests__/RuleDetailsMeta-test.tsx
index 0a725bc6d02..1380e6c0bfc 100644
--- a/server/sonar-web/src/main/js/apps/coding-rules/components/__tests__/RuleDetailsMeta-test.tsx
+++ b/server/sonar-web/src/main/js/apps/coding-rules/components/__tests__/RuleDetailsMeta-test.tsx
@@ -20,33 +20,61 @@
import * as React from 'react';
import { shallow } from 'enzyme';
import RuleDetailsMeta from '../RuleDetailsMeta';
-import { RuleDetails } from '../../../../app/types';
+import { RuleScope } from '../../../../app/types';
import RuleDetailsTagsPopup from '../RuleDetailsTagsPopup';
-const ruleDetails: RuleDetails = {
- createdAt: '',
- repo: '',
- key: 'key',
- lang: '',
- langName: '',
- name: '',
- severity: '',
- status: '',
- type: ''
+const RULE = {
+ key: 'squid:S1133',
+ repo: 'squid',
+ name: 'Deprecated code should be removed',
+ createdAt: '2013-07-26T09:40:51+0200',
+ severity: 'INFO',
+ status: 'READY',
+ lang: 'java',
+ langName: 'Java',
+ scope: RuleScope.Main,
+ type: 'CODE_SMELL'
};
+const EXTERNAL_RULE = {
+ key: 'external_xoo:OneExternalIssuePerLine',
+ repo: 'external_xoo',
+ name: 'xoo:OneExternalIssuePerLine',
+ createdAt: '2018-05-31T11:22:13+0200',
+ status: 'READY',
+ scope: RuleScope.All,
+ isExternal: true,
+ type: 'UNKNOWN'
+};
+
+const EXTERNAL_RULE_WITH_DATA = {
+ key: 'external_xoo:OneExternalIssueWithDetailsPerLine',
+ repo: 'external_xoo',
+ name: 'One external issue per line',
+ createdAt: '2018-05-31T11:19:51+0200',
+ severity: 'MAJOR',
+ status: 'READY',
+ tags: ['tag'],
+ lang: 'xoo',
+ langName: 'Xoo',
+ scope: RuleScope.All,
+ isExternal: true,
+ type: 'BUG'
+};
+
+it('should display right meta info', () => {
+ expect(getWrapper()).toMatchSnapshot();
+ expect(
+ getWrapper({ hideSimilarRulesFilter: true, ruleDetails: EXTERNAL_RULE })
+ ).toMatchSnapshot();
+ expect(
+ getWrapper({ hideSimilarRulesFilter: true, ruleDetails: EXTERNAL_RULE_WITH_DATA })
+ ).toMatchSnapshot();
+});
+
it('should edit tags', () => {
const onTagsChange = jest.fn();
- const wrapper = shallow(
- <RuleDetailsMeta
- canWrite={true}
- onFilterChange={jest.fn()}
- onTagsChange={onTagsChange}
- organization={undefined}
- referencedRepositories={{}}
- ruleDetails={ruleDetails}
- />
- );
+ const wrapper = getWrapper({ onTagsChange });
expect(wrapper.find('[data-meta="tags"]')).toMatchSnapshot();
const overlay = wrapper
.find('[data-meta="tags"]')
@@ -56,3 +84,17 @@ it('should edit tags', () => {
overlay.props.setTags(['foo', 'bar']);
expect(onTagsChange).toBeCalledWith(['foo', 'bar']);
});
+
+function getWrapper(props = {}) {
+ return shallow(
+ <RuleDetailsMeta
+ canWrite={true}
+ onFilterChange={jest.fn()}
+ onTagsChange={jest.fn()}
+ organization={undefined}
+ referencedRepositories={{}}
+ ruleDetails={RULE}
+ {...props}
+ />
+ );
+}
diff --git a/server/sonar-web/src/main/js/apps/coding-rules/components/__tests__/__snapshots__/RuleDetailsDescription-test.tsx.snap b/server/sonar-web/src/main/js/apps/coding-rules/components/__tests__/__snapshots__/RuleDetailsDescription-test.tsx.snap
new file mode 100644
index 00000000000..2e50c52359b
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/coding-rules/components/__tests__/__snapshots__/RuleDetailsDescription-test.tsx.snap
@@ -0,0 +1,64 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should display correctly 1`] = `
+<div
+ className="js-rule-description"
+>
+ <div
+ className="coding-rules-detail-description rule-desc markdown"
+ dangerouslySetInnerHTML={
+ Object {
+ "__html": "<p>Html Description</p>",
+ }
+ }
+ />
+ <div
+ className="coding-rules-detail-description coding-rules-detail-description-extra"
+ >
+ <div
+ id="coding-rules-detail-description-extra"
+ />
+ </div>
+</div>
+`;
+
+exports[`should display correctly 2`] = `
+<div
+ className="js-rule-description"
+>
+ <div
+ className="coding-rules-detail-description rule-desc markdown"
+ >
+ issue.external_issue_description.xoo:OneExternalIssuePerLine
+ </div>
+ <div
+ className="coding-rules-detail-description coding-rules-detail-description-extra"
+ >
+ <div
+ id="coding-rules-detail-description-extra"
+ />
+ </div>
+</div>
+`;
+
+exports[`should display correctly 3`] = `
+<div
+ className="js-rule-description"
+>
+ <div
+ className="coding-rules-detail-description rule-desc markdown"
+ dangerouslySetInnerHTML={
+ Object {
+ "__html": "<p>Html Description</p>",
+ }
+ }
+ />
+ <div
+ className="coding-rules-detail-description coding-rules-detail-description-extra"
+ >
+ <div
+ id="coding-rules-detail-description-extra"
+ />
+ </div>
+</div>
+`;
diff --git a/server/sonar-web/src/main/js/apps/coding-rules/components/__tests__/__snapshots__/RuleDetailsMeta-test.tsx.snap b/server/sonar-web/src/main/js/apps/coding-rules/components/__tests__/__snapshots__/RuleDetailsMeta-test.tsx.snap
index 8e501772a23..2f6ac55b176 100644
--- a/server/sonar-web/src/main/js/apps/coding-rules/components/__tests__/__snapshots__/RuleDetailsMeta-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/coding-rules/components/__tests__/__snapshots__/RuleDetailsMeta-test.tsx.snap
@@ -1,5 +1,288 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
+exports[`should display right meta info 1`] = `
+<div
+ className="js-rule-meta"
+>
+ <header
+ className="page-header"
+ >
+ <div
+ className="pull-right"
+ >
+ <span
+ className="note text-middle"
+ >
+ squid:S1133
+ </span>
+ <Link
+ className="coding-rules-detail-permalink link-no-underline spacer-left text-middle"
+ onlyActiveOnIndex={false}
+ style={Object {}}
+ to={
+ Object {
+ "pathname": "/coding_rules",
+ "query": Object {
+ "open": "squid:S1133",
+ "rule_key": "squid:S1133",
+ },
+ }
+ }
+ >
+ <LinkIcon />
+ </Link>
+ <SimilarRulesFilter
+ onFilterChange={[MockFunction]}
+ rule={
+ Object {
+ "createdAt": "2013-07-26T09:40:51+0200",
+ "key": "squid:S1133",
+ "lang": "java",
+ "langName": "Java",
+ "name": "Deprecated code should be removed",
+ "repo": "squid",
+ "scope": "MAIN",
+ "severity": "INFO",
+ "status": "READY",
+ "type": "CODE_SMELL",
+ }
+ }
+ />
+ </div>
+ <h3
+ className="page-title coding-rules-detail-header"
+ >
+ <big>
+ Deprecated code should be removed
+ </big>
+ </h3>
+ </header>
+ <ul
+ className="coding-rules-detail-properties"
+ >
+ <Tooltip
+ overlay="coding_rules.type.tooltip.CODE_SMELL"
+ >
+ <li
+ className="coding-rules-detail-property"
+ data-meta="type"
+ >
+ <IssueTypeIcon
+ className="little-spacer-right"
+ query="CODE_SMELL"
+ />
+ issue.type.CODE_SMELL
+ </li>
+ </Tooltip>
+ <Tooltip
+ overlay="default_severity"
+ >
+ <li
+ className="coding-rules-detail-property"
+ data-meta="severity"
+ >
+ <SeverityHelper
+ className="display-inline-flex-center"
+ severity="INFO"
+ />
+ </li>
+ </Tooltip>
+ <React.Fragment>
+ <Tooltip
+ overlay="coding_rules.scope.title"
+ >
+ <li
+ className="coding-rules-detail-property"
+ >
+ <RuleScopeIcon
+ className="little-spacer-right"
+ />
+ coding_rules.scope.MAIN
+ </li>
+ </Tooltip>
+ </React.Fragment>
+ <li
+ className="coding-rules-detail-property"
+ data-meta="tags"
+ >
+ <Dropdown
+ closeOnClick={false}
+ closeOnClickOutside={true}
+ overlay={
+ <RuleDetailsTagsPopup
+ organization={undefined}
+ setTags={[MockFunction]}
+ sysTags={Array []}
+ tags={Array []}
+ />
+ }
+ overlayPlacement="bottom-left"
+ >
+ <Button
+ className="button-link"
+ >
+ <TagsList
+ allowUpdate={true}
+ tags={
+ Array [
+ "coding_rules.no_tags",
+ ]
+ }
+ />
+ </Button>
+ </Dropdown>
+ </li>
+ <li
+ className="coding-rules-detail-property"
+ data-meta="available-since"
+ >
+ <span
+ className="little-spacer-right"
+ >
+ coding_rules.available_since
+ </span>
+ <DateFormatter
+ date="2013-07-26T09:40:51+0200"
+ />
+ </li>
+ <React.Fragment />
+ </ul>
+</div>
+`;
+
+exports[`should display right meta info 2`] = `
+<div
+ className="js-rule-meta"
+>
+ <header
+ className="page-header"
+ >
+ <div
+ className="pull-right"
+ >
+ <span
+ className="note text-middle"
+ >
+ external_xoo:OneExternalIssuePerLine
+ </span>
+ </div>
+ <h3
+ className="page-title coding-rules-detail-header"
+ >
+ <big>
+ xoo:OneExternalIssuePerLine
+ </big>
+ </h3>
+ </header>
+</div>
+`;
+
+exports[`should display right meta info 3`] = `
+<div
+ className="js-rule-meta"
+>
+ <header
+ className="page-header"
+ >
+ <div
+ className="pull-right"
+ >
+ <span
+ className="note text-middle"
+ >
+ external_xoo:OneExternalIssueWithDetailsPerLine
+ </span>
+ </div>
+ <h3
+ className="page-title coding-rules-detail-header"
+ >
+ <big>
+ One external issue per line
+ </big>
+ </h3>
+ </header>
+ <ul
+ className="coding-rules-detail-properties"
+ >
+ <Tooltip
+ overlay="coding_rules.type.tooltip.BUG"
+ >
+ <li
+ className="coding-rules-detail-property"
+ data-meta="type"
+ >
+ <IssueTypeIcon
+ className="little-spacer-right"
+ query="BUG"
+ />
+ issue.type.BUG
+ </li>
+ </Tooltip>
+ <Tooltip
+ overlay="default_severity"
+ >
+ <li
+ className="coding-rules-detail-property"
+ data-meta="severity"
+ >
+ <SeverityHelper
+ className="display-inline-flex-center"
+ severity="MAJOR"
+ />
+ </li>
+ </Tooltip>
+ <li
+ className="coding-rules-detail-property"
+ data-meta="tags"
+ >
+ <Dropdown
+ closeOnClick={false}
+ closeOnClickOutside={true}
+ overlay={
+ <RuleDetailsTagsPopup
+ organization={undefined}
+ setTags={[MockFunction]}
+ sysTags={Array []}
+ tags={
+ Array [
+ "tag",
+ ]
+ }
+ />
+ }
+ overlayPlacement="bottom-left"
+ >
+ <Button
+ className="button-link"
+ >
+ <TagsList
+ allowUpdate={true}
+ tags={
+ Array [
+ "tag",
+ ]
+ }
+ />
+ </Button>
+ </Dropdown>
+ </li>
+ <Tooltip
+ overlay="coding_rules.external_rule.engine.xoo"
+ >
+ <li
+ className="coding-rules-detail-property"
+ >
+ <div
+ className="outline-badge badge-tiny-height spacer-left vertical-text-top"
+ >
+ xoo
+ </div>
+ </li>
+ </Tooltip>
+ </ul>
+</div>
+`;
+
exports[`should edit tags 1`] = `
<li
className="coding-rules-detail-property"
diff --git a/sonar-core/src/main/resources/org/sonar/l10n/core.properties b/sonar-core/src/main/resources/org/sonar/l10n/core.properties
index b3d6d238765..5f7d150df99 100644
--- a/sonar-core/src/main/resources/org/sonar/l10n/core.properties
+++ b/sonar-core/src/main/resources/org/sonar/l10n/core.properties
@@ -1334,6 +1334,8 @@ coding_rules.scope.MAIN=Main sources
coding_rules.scope.TEST=Test sources
coding_rules.scope.ALL=Main and Test sources
+coding_rules.external_rule.engine=Rule provided by an external rule engine: {0}
+
#------------------------------------------------------------------------------
#
# EMAIL CONFIGURATION