]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-22224 Add a 'Prioritized' mark to an issue
authorViktor Vorona <viktor.vorona@sonarsource.com>
Wed, 29 May 2024 12:47:32 +0000 (14:47 +0200)
committersonartech <sonartech@sonarsource.com>
Mon, 3 Jun 2024 20:02:58 +0000 (20:02 +0000)
server/sonar-web/src/main/js/apps/issues/components/IssueHeaderMeta.tsx
server/sonar-web/src/main/js/components/SourceViewer/helpers/__tests__/__snapshots__/loadIssues-test.ts.snap
server/sonar-web/src/main/js/components/issue/components/IssueMetaBar.tsx
server/sonar-web/src/main/js/components/issue/components/IssuePrioritized.tsx [new file with mode: 0644]
server/sonar-web/src/main/js/helpers/__tests__/issues-test.ts
server/sonar-web/src/main/js/helpers/testMocks.ts
server/sonar-web/src/main/js/types/issues.ts
server/sonar-web/src/main/js/types/types.ts
sonar-core/src/main/resources/org/sonar/l10n/core.properties

index f4320b01d5310caa1ec8257d3d421ac631fee29a..463872dd18c014e7305b5eac746e0aae4db3b851 100644 (file)
@@ -21,6 +21,7 @@ import { Tooltip } from '@sonarsource/echoes-react';
 import { LightLabel, Note, SeparatorCircleIcon } from 'design-system';
 import React from 'react';
 import DateFromNow from '../../../components/intl/DateFromNow';
+import IssuePrioritized from '../../../components/issue/components/IssuePrioritized';
 import IssueSeverity from '../../../components/issue/components/IssueSeverity';
 import IssueType from '../../../components/issue/components/IssueType';
 import { translate } from '../../../helpers/l10n';
@@ -80,6 +81,12 @@ export default function IssueHeaderMeta({ issue }: Readonly<Props>) {
       <IssueType issue={issue} />
       <SeparatorCircleIcon data-guiding-id="issue-4" />
       <IssueSeverity issue={issue} />
+      {issue.prioritizedRule && (
+        <>
+          <SeparatorCircleIcon />
+          <IssuePrioritized />
+        </>
+      )}
     </Note>
   );
 }
index 4bee378fdb71ea563eb554ae7795e8125daa2977..8c10c4dbf60669cfc5f52b192d2f4c3536757d11 100644 (file)
@@ -33,6 +33,7 @@ exports[`loadIssues should load issues with listIssues if re-indexing 1`] = `
     "key": "AWaqVGl3tut9VbnJvk6M",
     "line": 62,
     "message": "Make sure this file handling is safe here.",
+    "prioritizedRule": false,
     "project": "org.sonarsource.java:java",
     "projectEnabled": true,
     "projectKey": "org.sonarsource.java:java",
@@ -99,6 +100,7 @@ exports[`loadIssues should load issues with searchIssues if not re-indexing 1`]
     "key": "AWaqVGl3tut9VbnJvk6M",
     "line": 62,
     "message": "Make sure this file handling is safe here.",
+    "prioritizedRule": false,
     "project": "org.sonarsource.java:java",
     "projectEnabled": true,
     "projectKey": "org.sonarsource.java:java",
index 3d692d4f6b00dcff6c1574e17f0f4b6181b1cc08..0bdebede08d7ad1e98d842262a1fb9a88a607d13 100644 (file)
@@ -27,6 +27,7 @@ import { Issue } from '../../../types/types';
 import Tooltip from '../../controls/Tooltip';
 import DateFromNow from '../../intl/DateFromNow';
 import { WorkspaceContext } from '../../workspace/context';
+import IssuePrioritized from './IssuePrioritized';
 import IssueSeverity from './IssueSeverity';
 import IssueType from './IssueType';
 import SonarLintBadge from './SonarLintBadge';
@@ -147,6 +148,16 @@ export default function IssueMetaBar(props: Readonly<Props>) {
       <SeparatorCircleIcon data-guiding-id="issue-4" aria-hidden as="li" />
 
       <IssueSeverity issue={issue} height={12} width={12} />
+
+      {issue.prioritizedRule && (
+        <>
+          <SeparatorCircleIcon aria-hidden as="li" />
+
+          <IssueMetaListItem className={issueMetaListItemClassNames}>
+            <IssuePrioritized />
+          </IssueMetaListItem>
+        </>
+      )}
     </ul>
   );
 }
diff --git a/server/sonar-web/src/main/js/components/issue/components/IssuePrioritized.tsx b/server/sonar-web/src/main/js/components/issue/components/IssuePrioritized.tsx
new file mode 100644 (file)
index 0000000..5bdd224
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2024 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 { TextSubdued, Tooltip } from 'design-system';
+import * as React from 'react';
+import { translate } from '../../../helpers/l10n';
+
+export default function IssuePrioritized() {
+  return (
+    <Tooltip overlay={translate('issue.prioritized_rule.description')}>
+      <TextSubdued>{translate('prioritized')}</TextSubdued>
+    </Tooltip>
+  );
+}
index 9332d72605be254935557bfe61580634ee7cdb35..c7f05100c7fc22e93953959af3a7a1a5a3c19db6 100644 (file)
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+import { IssueType } from '../../types/issues';
 import { parseIssueFromResponse, sortByType } from '../issues';
 import { mockIssue } from '../testMocks';
 
 it('should sort issues correctly by type', () => {
-  const bug1 = mockIssue(false, { type: 'BUG', key: 'bug1' });
-  const bug2 = mockIssue(false, { type: 'BUG', key: 'bug2' });
-  const codeSmell = mockIssue(false, { type: 'CODE_SMELL', key: 'code_smell' });
-  const vulnerability1 = mockIssue(false, { type: 'VULNERABILITY', key: 'vulnerability1' });
-  const vulnerability2 = mockIssue(false, { type: 'VULNERABILITY', key: 'vulnerability2' });
-  const securityHotspot = mockIssue(false, { type: 'SECURITY_HOTSPOT', key: 'security_hotspot' });
+  const bug1 = mockIssue(false, { type: IssueType.Bug, key: 'bug1' });
+  const bug2 = mockIssue(false, { type: IssueType.Bug, key: 'bug2' });
+  const codeSmell = mockIssue(false, { type: IssueType.CodeSmell, key: 'code_smell' });
+  const vulnerability1 = mockIssue(false, { type: IssueType.Vulnerability, key: 'vulnerability1' });
+  const vulnerability2 = mockIssue(false, { type: IssueType.Vulnerability, key: 'vulnerability2' });
+  const securityHotspot = mockIssue(false, {
+    type: IssueType.SecurityHotspot,
+    key: 'security_hotspot',
+  });
 
   expect(
     sortByType([bug1, codeSmell, bug2, securityHotspot, vulnerability1, vulnerability2]),
index 674a54c5feea6a0b89eedb9ae2370cec361603db..d4fc042a59401c72b84386930c83c105934e777f 100644 (file)
@@ -336,6 +336,7 @@ export function mockRawIssue(withLocations = false, overrides: Partial<RawIssue>
     impacts: [
       { softwareQuality: SoftwareQuality.Maintainability, severity: SoftwareImpactSeverity.Medium },
     ],
+    prioritizedRule: false,
     ...overrides,
   };
 
@@ -384,7 +385,7 @@ export function mockIssue(withLocations = false, overrides: Partial<Issue> = {})
     issueStatus: IssueStatus.Open,
     textRange: { startLine: 25, endLine: 26, startOffset: 0, endOffset: 15 },
     transitions: [],
-    type: 'BUG',
+    type: IssueType.Bug,
     cleanCodeAttributeCategory: CleanCodeAttributeCategory.Responsible,
     cleanCodeAttribute: CleanCodeAttribute.Respectful,
     impacts: [
index 85a62387cdcd036ce1092f0f45dabd0e4fe5175f..593abc3b91562de1676d872bd3d48161e47c9648 100644 (file)
@@ -139,6 +139,7 @@ export interface RawIssue {
   key: string;
   line?: number;
   messageFormattings?: MessageFormatting[];
+  prioritizedRule?: boolean;
   project: string;
   rule: string;
   resolution?: string;
index 12374bac3decb4677d7360e6269e605818161101..ea0fe08df087fad2a0ce27d8bde55a93986bb580 100644 (file)
@@ -26,7 +26,7 @@ import {
   CleanCodeAttributeCategory,
   SoftwareImpact,
 } from './clean-code-taxonomy';
-import { IssueStatus, IssueTransition, MessageFormatting } from './issues';
+import { MessageFormatting, RawIssue } from './issues';
 import { NewCodeDefinitionType } from './new-code-definition';
 import { UserActive, UserBase } from './users';
 
@@ -226,54 +226,28 @@ export interface IdentityProvider {
   manage?: boolean;
 }
 
-export interface Issue {
-  actions: string[];
-  assignee?: string;
+export interface Issue extends Omit<RawIssue, 'flows' | 'comments'> {
   assigneeActive?: boolean;
   assigneeAvatar?: string;
   assigneeLogin?: string;
   assigneeName?: string;
-  author?: string;
   branch?: string;
-  cleanCodeAttributeCategory: CleanCodeAttributeCategory;
-  cleanCodeAttribute: CleanCodeAttribute;
-  impacts: SoftwareImpact[];
-  codeVariants?: string[];
   comments?: IssueComment[];
-  component: string;
   componentEnabled?: boolean;
   componentLongName: string;
   componentQualifier: string;
   componentUuid: string;
-  creationDate: string;
   effort?: string;
   externalRuleEngine?: string;
   fromExternalRule?: boolean;
-  quickFixAvailable?: boolean;
-  key: string;
   flows: FlowLocation[][];
   flowsWithType: Flow[];
-  line?: number;
   message: string;
-  messageFormattings?: MessageFormatting[];
-  project: string;
   projectName: string;
   projectKey: string;
   pullRequest?: string;
-  resolution?: string;
-  rule: string;
-  ruleDescriptionContextKey?: string;
   ruleName: string;
-  ruleStatus?: string;
-  scope: string;
   secondaryLocations: FlowLocation[];
-  severity: string;
-  status: string;
-  issueStatus: IssueStatus;
-  tags?: string[];
-  textRange?: TextRange;
-  transitions: IssueTransition[];
-  type: IssueType;
 }
 
 export interface IssueChangelog {
index 8d2ee9d172f0d47a7f896cdcf90f4bf7f2dafd8e..28ff53ba35c3d09cea09dd69883faf0fb459cd7b 100644 (file)
@@ -178,6 +178,7 @@ plugin=Plugin
 previous=Previous
 previous_=previous
 previous_month_x=previous month {month}
+prioritized=Prioritized
 profile_name=Profile name
 project=Project
 project_x=Project: {0}
@@ -976,6 +977,7 @@ issue.location_x=Location {0}
 issue.closed.file_level=This issue is {status}. It was detected in the file below and is no longer being detected.
 issue.closed.project_level=This issue is {status}. It was detected in the project below and is no longer being detected.
 issues.assignee.change_user=Click to change assignee
+issue.prioritized_rule.description=The associated rule has been designated as a priority in the Quality Profile, indicating that all corresponding issues in Overall Code should be fixed.
 
 issues.action_select=Select issue
 issues.action_select.label=Select issue {0}