]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-15473 Add SonarLint promotion for quick fix on issue
authorMathieu Suen <mathieu.suen@sonarsource.com>
Wed, 6 Oct 2021 09:33:14 +0000 (11:33 +0200)
committersonartech <sonartech@sonarsource.com>
Wed, 13 Oct 2021 20:03:34 +0000 (20:03 +0000)
server/sonar-web/src/main/js/components/issue/components/IssueMessage.tsx
server/sonar-web/src/main/js/components/issue/components/IssueTitleBar.tsx
server/sonar-web/src/main/js/components/issue/components/__tests__/IssueMessage-test.tsx
server/sonar-web/src/main/js/components/issue/components/__tests__/__snapshots__/IssueMessage-test.tsx.snap
server/sonar-web/src/main/js/types/types.d.ts
sonar-core/src/main/resources/org/sonar/l10n/core.properties

index 3662530064e5360a7be9c39b9c1dbcb59d5fe777..bd59dbebd82a01f72012aa1b45bcc1c5190fed8c 100644 (file)
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
 import * as React from 'react';
+import { FormattedMessage } from 'react-intl';
 import { ButtonLink } from '../../../components/controls/buttons';
 import Tooltip from '../../../components/controls/Tooltip';
 import { translate, translateWithParameters } from '../../../helpers/l10n';
 import { RuleStatus } from '../../../types/rules';
 import DocumentationTooltip from '../../common/DocumentationTooltip';
+import SonarLintIcon from '../../icons/SonarLintIcon';
 import { WorkspaceContextShape } from '../../workspace/context';
 
 export interface IssueMessageProps {
   engine?: string;
   engineName?: string;
+  quickFixAvailable?: boolean;
   manualVulnerability: boolean;
   message: string;
   onOpenRule: WorkspaceContextShape['openRule'];
@@ -36,12 +39,42 @@ export interface IssueMessageProps {
 }
 
 export default function IssueMessage(props: IssueMessageProps) {
-  const { engine, engineName, manualVulnerability, message, ruleKey, ruleStatus } = props;
+  const {
+    engine,
+    engineName,
+    quickFixAvailable,
+    manualVulnerability,
+    message,
+    ruleKey,
+    ruleStatus
+  } = props;
   const ruleEngine = engineName ? engineName : engine;
 
   return (
-    <div className="issue-message break-word">
+    <div className="display-inline-flex-center issue-message break-word">
       <span className="spacer-right">{message}</span>
+      {quickFixAvailable && (
+        <Tooltip
+          overlay={
+            <FormattedMessage
+              id="issue.quick_fix_available_with_sonarlint"
+              defaultMessage={translate('issue.quick_fix_available_with_sonarlint')}
+              values={{
+                link: (
+                  <a
+                    href="https://www.sonarqube.org/sonarlint/?referrer=sonarqube-quick-fix"
+                    rel="noopener noreferrer"
+                    target="_blank">
+                    SonarLint
+                  </a>
+                )
+              }}
+            />
+          }
+          mouseLeaveDelay={0.5}>
+          <SonarLintIcon className="spacer-right" size={15} />
+        </Tooltip>
+      )}
       <ButtonLink
         aria-label={translate('issue.why_this_issue.long')}
         className="issue-see-rule spacer-right text-baseline"
@@ -52,7 +85,6 @@ export default function IssueMessage(props: IssueMessageProps) {
         }>
         {translate('issue.why_this_issue')}
       </ButtonLink>
-
       {ruleStatus && (ruleStatus === RuleStatus.Deprecated || ruleStatus === RuleStatus.Removed) && (
         <DocumentationTooltip
           className="spacer-left"
@@ -68,7 +100,6 @@ export default function IssueMessage(props: IssueMessageProps) {
           </span>
         </DocumentationTooltip>
       )}
-
       {ruleEngine && (
         <Tooltip overlay={translateWithParameters('issue.from_external_rule_engine', ruleEngine)}>
           <div className="badge spacer-right text-baseline">{ruleEngine}</div>
index e4af5329dee6680068f6c329d2fbc9e221f99799..2b3bb81a35b15f066f20ba274b74fcf6589b68a2 100644 (file)
@@ -81,6 +81,7 @@ export default function IssueTitleBar(props: IssueTitleBarProps) {
               externalRulesRepoNames &&
               externalRulesRepoNames[issue.externalRuleEngine]
             }
+            quickFixAvailable={issue.quickFixAvailable}
             manualVulnerability={issue.fromHotspot && issue.type === 'VULNERABILITY'}
             message={issue.message}
             onOpenRule={openRule}
index 3e1d43c3c7ef33f9e3e6f4655df43cfa00c9d3d4..a47a0d59f03eafcbce6e63b4cc3da36591cd636d 100644 (file)
@@ -27,6 +27,7 @@ import IssueMessage, { IssueMessageProps } from '../IssueMessage';
 it('should render correctly', () => {
   expect(shallowRender()).toMatchSnapshot('default');
   expect(shallowRender({ engine: 'js' })).toMatchSnapshot('with engine info');
+  expect(shallowRender({ quickFixAvailable: true })).toMatchSnapshot('with quick fix');
   expect(shallowRender({ engineName: 'JS' })).toMatchSnapshot('with engine name');
   expect(shallowRender({ manualVulnerability: true })).toMatchSnapshot('is manual vulnerability');
   expect(shallowRender({ ruleStatus: RuleStatus.Deprecated })).toMatchSnapshot(
index 05ac47ff7ea7d88e342c358bc8a5b63b8f41b80e..94baa6b09fdbdd7f05c1d9da29d2914af03ecc11 100644 (file)
@@ -2,7 +2,7 @@
 
 exports[`should render correctly: default 1`] = `
 <div
-  className="issue-message break-word"
+  className="display-inline-flex-center issue-message break-word"
 >
   <span
     className="spacer-right"
@@ -21,7 +21,7 @@ exports[`should render correctly: default 1`] = `
 
 exports[`should render correctly: is deprecated rule 1`] = `
 <div
-  className="issue-message break-word"
+  className="display-inline-flex-center issue-message break-word"
 >
   <span
     className="spacer-right"
@@ -58,7 +58,7 @@ exports[`should render correctly: is deprecated rule 1`] = `
 
 exports[`should render correctly: is manual vulnerability 1`] = `
 <div
-  className="issue-message break-word"
+  className="display-inline-flex-center issue-message break-word"
 >
   <span
     className="spacer-right"
@@ -86,7 +86,7 @@ exports[`should render correctly: is manual vulnerability 1`] = `
 
 exports[`should render correctly: is removed rule 1`] = `
 <div
-  className="issue-message break-word"
+  className="display-inline-flex-center issue-message break-word"
 >
   <span
     className="spacer-right"
@@ -123,7 +123,7 @@ exports[`should render correctly: is removed rule 1`] = `
 
 exports[`should render correctly: with engine info 1`] = `
 <div
-  className="issue-message break-word"
+  className="display-inline-flex-center issue-message break-word"
 >
   <span
     className="spacer-right"
@@ -151,7 +151,7 @@ exports[`should render correctly: with engine info 1`] = `
 
 exports[`should render correctly: with engine name 1`] = `
 <div
-  className="issue-message break-word"
+  className="display-inline-flex-center issue-message break-word"
 >
   <span
     className="spacer-right"
@@ -176,3 +176,47 @@ exports[`should render correctly: with engine name 1`] = `
   </Tooltip>
 </div>
 `;
+
+exports[`should render correctly: with quick fix 1`] = `
+<div
+  className="display-inline-flex-center issue-message break-word"
+>
+  <span
+    className="spacer-right"
+  >
+    Reduce the number of conditional operators (4) used in the expression
+  </span>
+  <Tooltip
+    mouseLeaveDelay={0.5}
+    overlay={
+      <FormattedMessage
+        defaultMessage="issue.quick_fix_available_with_sonarlint"
+        id="issue.quick_fix_available_with_sonarlint"
+        values={
+          Object {
+            "link": <a
+              href="https://www.sonarqube.org/sonarlint/?referrer=sonarqube-quick-fix"
+              rel="noopener noreferrer"
+              target="_blank"
+            >
+              SonarLint
+            </a>,
+          }
+        }
+      />
+    }
+  >
+    <SonarLintIcon
+      className="spacer-right"
+      size={15}
+    />
+  </Tooltip>
+  <ButtonLink
+    aria-label="issue.why_this_issue.long"
+    className="issue-see-rule spacer-right text-baseline"
+    onClick={[Function]}
+  >
+    issue.why_this_issue
+  </ButtonLink>
+</div>
+`;
index 8173bca1ff14bda69d8fb9d710aeee97f90d1873..74ccbfd754b5b80375098195f27f0a839b4b62b8 100644 (file)
@@ -343,6 +343,7 @@ declare namespace T {
     effort?: string;
     externalRuleEngine?: string;
     fromExternalRule?: boolean;
+    quickFixAvailable?: boolean;
     key: string;
     flows: FlowLocation[][];
     fromHotspot: boolean;
index d5da4dd1415d3ea0ff79ab29196c8de90ffbce7b..f97f1cfd414e55639aa768ff54c0ecf52cca9286 100644 (file)
@@ -808,6 +808,7 @@ issue.assign.assigned_to_x_click_to_change=Assigned to {0}, click to change
 issue.assign.unassigned_click_to_assign=Unassigned, click to assign issue
 issue.assign.formlink=Assign
 issue.assign.to_me=to me
+issue.quick_fix_available_with_sonarlint=Quick fix available in {link}
 issue.comment.add_comment=Add Comment
 issue.comment.formlink=Comment
 issue.comment.submit=Comment