aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorstanislavh <stanislav.honcharov@sonarsource.com>2023-12-20 12:11:16 +0100
committersonartech <sonartech@sonarsource.com>2024-01-17 20:02:44 +0000
commit90ad2c4384f1d9a55af1b28efcd9886efbce98db (patch)
tree02e89f7ebea4592a9a7f8a400b7db0b72edc5a19
parenta8336afac1068fdc4f79f65284f52511ca471964 (diff)
downloadsonarqube-90ad2c4384f1d9a55af1b28efcd9886efbce98db.tar.gz
sonarqube-90ad2c4384f1d9a55af1b28efcd9886efbce98db.zip
SONAR-21259 Show fixed issues in issues list of the target branch
-rw-r--r--server/sonar-web/src/main/js/apps/issues/__tests__/IssuesApp-it.tsx6
-rw-r--r--server/sonar-web/src/main/js/apps/issues/__tests__/utils-test.ts2
-rw-r--r--server/sonar-web/src/main/js/apps/issues/components/IssuesApp.tsx19
-rw-r--r--server/sonar-web/src/main/js/apps/issues/components/IssuesListTitle.tsx66
-rw-r--r--server/sonar-web/src/main/js/apps/issues/test-utils.tsx5
-rw-r--r--server/sonar-web/src/main/js/apps/issues/utils.ts3
-rw-r--r--server/sonar-web/src/main/js/apps/overview/pullRequests/IssueMeasuresCard.tsx2
-rw-r--r--server/sonar-web/src/main/js/helpers/mocks/issues.ts1
-rw-r--r--server/sonar-web/src/main/js/queries/branch.tsx1
-rw-r--r--sonar-core/src/main/resources/org/sonar/l10n/core.properties2
10 files changed, 101 insertions, 6 deletions
diff --git a/server/sonar-web/src/main/js/apps/issues/__tests__/IssuesApp-it.tsx b/server/sonar-web/src/main/js/apps/issues/__tests__/IssuesApp-it.tsx
index 18bd744d866..5ebcbd4d4e6 100644
--- a/server/sonar-web/src/main/js/apps/issues/__tests__/IssuesApp-it.tsx
+++ b/server/sonar-web/src/main/js/apps/issues/__tests__/IssuesApp-it.tsx
@@ -66,6 +66,12 @@ describe('issues app', () => {
expect(screen.getByText('issues.not_all_issue_show')).toBeInTheDocument();
});
+
+ it('should show fixed issues message', async () => {
+ renderProjectIssuesApp('project/issues?id=my-project&fixedInPullRequest=01');
+
+ expect(await ui.fixedIssuesHeading.find()).toBeInTheDocument();
+ });
});
describe('navigation', () => {
diff --git a/server/sonar-web/src/main/js/apps/issues/__tests__/utils-test.ts b/server/sonar-web/src/main/js/apps/issues/__tests__/utils-test.ts
index 28a2fbb9737..7f580d8fe53 100644
--- a/server/sonar-web/src/main/js/apps/issues/__tests__/utils-test.ts
+++ b/server/sonar-web/src/main/js/apps/issues/__tests__/utils-test.ts
@@ -72,6 +72,7 @@ describe('serialize/deserialize', () => {
issueStatuses: [IssueStatus.Accepted, IssueStatus.Confirmed],
tags: ['a', 'b'],
types: ['a', 'b'],
+ fixedInPullRequest: '',
}),
).toStrictEqual({
assignees: 'a,b',
@@ -152,6 +153,7 @@ describe('serialize/deserialize', () => {
issueStatuses: [],
tags: [],
types: [],
+ fixedInPullRequest: '',
});
});
diff --git a/server/sonar-web/src/main/js/apps/issues/components/IssuesApp.tsx b/server/sonar-web/src/main/js/apps/issues/components/IssuesApp.tsx
index 29509e3b0e3..60362397ded 100644
--- a/server/sonar-web/src/main/js/apps/issues/components/IssuesApp.tsx
+++ b/server/sonar-web/src/main/js/apps/issues/components/IssuesApp.tsx
@@ -52,7 +52,12 @@ import IssueTabViewer from '../../../components/rules/IssueTabViewer';
import '../../../components/search-navigator.css';
import { DEFAULT_ISSUES_QUERY } from '../../../components/shared/utils';
import Spinner from '../../../components/ui/Spinner';
-import { fillBranchLike, getBranchLikeQuery, isSameBranchLike } from '../../../helpers/branch-like';
+import {
+ fillBranchLike,
+ getBranchLikeQuery,
+ isPullRequest,
+ isSameBranchLike,
+} from '../../../helpers/branch-like';
import handleRequiredAuthentication from '../../../helpers/handleRequiredAuthentication';
import { parseIssueFromResponse } from '../../../helpers/issues';
import { isInput, isShortcut } from '../../../helpers/keyboardEventHelpers';
@@ -104,6 +109,7 @@ import IssueGuide from './IssueGuide';
import IssueNewStatusAndTransitionGuide from './IssueNewStatusAndTransitionGuide';
import IssueReviewHistoryAndComments from './IssueReviewHistoryAndComments';
import IssuesList from './IssuesList';
+import IssuesListTitle from './IssuesListTitle';
import IssuesSourceViewer from './IssuesSourceViewer';
import NoIssues from './NoIssues';
import NoMyIssues from './NoMyIssues';
@@ -112,6 +118,7 @@ import { PSEUDO_SHADOW_HEIGHT } from './StyledHeader';
interface Props extends WithIndexationContextProps {
branchLike?: BranchLike;
+ branchLikes?: BranchLike[];
component?: Component;
currentUser: CurrentUser;
isFetchingBranch?: boolean;
@@ -1128,8 +1135,8 @@ export class App extends React.PureComponent<Props, State> {
}
renderList() {
- const { branchLike, component, currentUser } = this.props;
- const { issues, loading, loadingMore, openIssue, paging } = this.state;
+ const { branchLike, component, currentUser, branchLikes } = this.props;
+ const { issues, loading, loadingMore, openIssue, paging, query } = this.state;
const selectedIndex = this.getSelectedIndex();
const selectedIssue = selectedIndex !== undefined ? issues[selectedIndex] : undefined;
@@ -1151,7 +1158,11 @@ export class App extends React.PureComponent<Props, State> {
return (
<div>
- <h2 className="sw-sr-only">{translate('list_of_issues')}</h2>
+ <IssuesListTitle
+ fixedInPullRequest={query.fixedInPullRequest}
+ pullRequests={branchLikes?.filter(isPullRequest) ?? []}
+ component={component}
+ />
{issues.length > 0 && (
<IssuesList
diff --git a/server/sonar-web/src/main/js/apps/issues/components/IssuesListTitle.tsx b/server/sonar-web/src/main/js/apps/issues/components/IssuesListTitle.tsx
new file mode 100644
index 00000000000..6214d26e4a9
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/issues/components/IssuesListTitle.tsx
@@ -0,0 +1,66 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 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 { DiscreetLink, LightPrimary, PullRequestIcon, SubTitle } from 'design-system';
+import React from 'react';
+import { useIntl } from 'react-intl';
+import { getPullRequestUrl } from '../../../helpers/urls';
+import { PullRequest } from '../../../types/branch-like';
+import { Component } from '../../../types/types';
+
+interface IssuesListTitleProps {
+ component?: Component;
+ fixedInPullRequest: string;
+ pullRequests: PullRequest[];
+}
+
+export default function IssuesListTitle({
+ fixedInPullRequest,
+ pullRequests,
+ component,
+}: Readonly<IssuesListTitleProps>) {
+ const intl = useIntl();
+ const pullRequest = pullRequests.find((pr) => pr.key === fixedInPullRequest);
+ const prSummaryUrl = getPullRequestUrl(component?.key ?? '', fixedInPullRequest);
+
+ return pullRequest && !component?.needIssueSync ? (
+ <>
+ <SubTitle className="sw-mt-6 sw-mb-2">
+ {intl.formatMessage({ id: 'issues.fixed_issues' })}
+ </SubTitle>
+ <LightPrimary className="sw-flex sw-items-center sw-gap-1 sw-mb-2">
+ {intl.formatMessage(
+ { id: 'issues.fixed_issues.description' },
+ {
+ pullRequest: (
+ <>
+ <PullRequestIcon />
+ <DiscreetLink to={prSummaryUrl} className="sw-mt-[3px]">
+ {pullRequest.title}
+ </DiscreetLink>
+ </>
+ ),
+ },
+ )}
+ </LightPrimary>
+ </>
+ ) : (
+ <h2 className="sw-sr-only">{intl.formatMessage({ id: 'list_of_issues' })}</h2>
+ );
+}
diff --git a/server/sonar-web/src/main/js/apps/issues/test-utils.tsx b/server/sonar-web/src/main/js/apps/issues/test-utils.tsx
index 9db0654d83b..0c3ed20a595 100644
--- a/server/sonar-web/src/main/js/apps/issues/test-utils.tsx
+++ b/server/sonar-web/src/main/js/apps/issues/test-utils.tsx
@@ -32,6 +32,7 @@ import {
SoftwareImpactSeverity,
SoftwareQuality,
} from '../../types/clean-code-taxonomy';
+import { Feature } from '../../types/features';
import { Component } from '../../types/types';
import { NoticeType } from '../../types/users';
import IssuesApp from './components/IssuesApp';
@@ -55,6 +56,8 @@ export const ui = {
issueItems: byRole('region'),
+ fixedIssuesHeading: byRole('heading', { level: 2, name: 'issues.fixed_issues' }),
+
issueItem1: byRole('region', { name: 'Issue with no location message' }),
issueItem2: byRole('region', { name: 'FlowIssue' }),
issueItem3: byRole('region', { name: 'Issue on file' }),
@@ -186,7 +189,7 @@ export function renderProjectIssuesApp(
{projectIssuesRoutes()}
</Route>
),
- { navigateTo, currentUser },
+ { navigateTo, currentUser, featureList: [Feature.BranchSupport] },
{ component: mockComponent(overrides) },
);
}
diff --git a/server/sonar-web/src/main/js/apps/issues/utils.ts b/server/sonar-web/src/main/js/apps/issues/utils.ts
index a002c3ffb22..a2e303bfb5a 100644
--- a/server/sonar-web/src/main/js/apps/issues/utils.ts
+++ b/server/sonar-web/src/main/js/apps/issues/utils.ts
@@ -66,6 +66,7 @@ export interface Query {
cwe: string[];
directories: string[];
files: string[];
+ fixedInPullRequest: string;
impactSeverities: SoftwareImpactSeverity[];
impactSoftwareQualities: SoftwareQuality[];
issues: string[];
@@ -134,6 +135,7 @@ export function parseQuery(query: RawQuery): Query {
tags: parseAsArray(query.tags, parseAsString),
types: parseAsArray(query.types, parseAsString),
codeVariants: parseAsArray(query.codeVariants, parseAsString),
+ fixedInPullRequest: parseAsString(query.fixedInPullRequest),
};
}
@@ -222,6 +224,7 @@ export function serializeQuery(query: Query): RawQuery {
cwe: serializeStringArray(query.cwe),
directories: serializeStringArray(query.directories),
files: serializeStringArray(query.files),
+ fixedInPullRequest: serializeString(query.fixedInPullRequest),
issues: serializeStringArray(query.issues),
languages: serializeStringArray(query.languages),
owaspTop10: serializeStringArray(query.owaspTop10),
diff --git a/server/sonar-web/src/main/js/apps/overview/pullRequests/IssueMeasuresCard.tsx b/server/sonar-web/src/main/js/apps/overview/pullRequests/IssueMeasuresCard.tsx
index 12efb13cf87..434b05076ee 100644
--- a/server/sonar-web/src/main/js/apps/overview/pullRequests/IssueMeasuresCard.tsx
+++ b/server/sonar-web/src/main/js/apps/overview/pullRequests/IssueMeasuresCard.tsx
@@ -71,7 +71,7 @@ export default function IssueMeasuresCard(
});
const fixedUrl = getComponentIssuesUrl(component.key, {
branch: pullRequest.target,
- fixedInPR: pullRequest.key,
+ fixedInPullRequest: pullRequest.key,
});
const acceptedUrl = getComponentIssuesUrl(component.key, {
...getBranchLikeQuery(pullRequest),
diff --git a/server/sonar-web/src/main/js/helpers/mocks/issues.ts b/server/sonar-web/src/main/js/helpers/mocks/issues.ts
index 7d7cf3460f7..0379800351b 100644
--- a/server/sonar-web/src/main/js/helpers/mocks/issues.ts
+++ b/server/sonar-web/src/main/js/helpers/mocks/issues.ts
@@ -66,6 +66,7 @@ export function mockQuery(overrides: Partial<Query> = {}): Query {
cwe: [],
directories: [],
files: [],
+ fixedInPullRequest: '',
issues: [],
languages: [],
owaspTop10: [],
diff --git a/server/sonar-web/src/main/js/queries/branch.tsx b/server/sonar-web/src/main/js/queries/branch.tsx
index 918f0801fa8..a58ac2ceef6 100644
--- a/server/sonar-web/src/main/js/queries/branch.tsx
+++ b/server/sonar-web/src/main/js/queries/branch.tsx
@@ -109,6 +109,7 @@ function getContext(key: ReturnType<typeof useBranchesQueryKey>) {
export function useBranchesQuery(component?: LightComponent, refetchInterval?: number) {
const features = useContext(AvailableFeaturesContext);
const key = useBranchesQueryKey(InnerState.Details, component?.key);
+
return useQuery({
queryKey: key,
queryFn: async ({ queryKey: [, key, prOrBranch, name] }) => {
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 cbd79aa6161..6651b1035ac 100644
--- a/sonar-core/src/main/resources/org/sonar/l10n/core.properties
+++ b/sonar-core/src/main/resources/org/sonar/l10n/core.properties
@@ -1111,6 +1111,8 @@ issues.max_new_code_period=Max New Code Period
issues.my_issues=My Issues
issues.no_my_issues=There are no issues assigned to you.
issues.no_issues=No Issues. Hooray!
+issues.fixed_issues=Fixed issues
+issues.fixed_issues.description=List of issues that will be fixed by {pullRequest}
issues.x_more_locations=+ {0} more locations
issues.not_all_issue_show=Not all issues are included
issues.not_all_issue_show_why=You do not have access to all projects in this portfolio