aboutsummaryrefslogtreecommitdiffstats
path: root/server
diff options
context:
space:
mode:
authorMathieu Suen <mathieu.suen@sonarsource.com>2020-02-18 14:26:04 +0100
committerSonarTech <sonartech@sonarsource.com>2020-02-21 20:46:20 +0100
commit5568a67a2899635e8498798118dea73daa3934f6 (patch)
tree64fed4f16be4c1d705c8a9b707e3be536e4e69b3 /server
parent9bc1ac6000521a9a64c08c69100000d1f49cd383 (diff)
downloadsonarqube-5568a67a2899635e8498798118dea73daa3934f6.tar.gz
sonarqube-5568a67a2899635e8498798118dea73daa3934f6.zip
SONAR-13059 Add delete button on comment.
Diffstat (limited to 'server')
-rw-r--r--server/sonar-web/src/main/js/api/security-hotspots.ts4
-rw-r--r--server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotReviewHistory.tsx36
-rw-r--r--server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotReviewHistoryAndComments.tsx13
-rw-r--r--server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/HotspotReviewHistory-test.tsx4
-rw-r--r--server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/HotspotReviewHistoryAndComments-test.tsx15
-rw-r--r--server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/__snapshots__/HotspotReviewHistory-test.tsx.snap58
-rw-r--r--server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/__snapshots__/HotspotReviewHistoryAndComments-test.tsx.snap2
-rw-r--r--server/sonar-web/src/main/js/apps/security-hotspots/styles.css5
-rw-r--r--server/sonar-web/src/main/js/apps/security-hotspots/utils.ts4
-rw-r--r--server/sonar-web/src/main/js/types/security-hotspots.ts2
10 files changed, 117 insertions, 26 deletions
diff --git a/server/sonar-web/src/main/js/api/security-hotspots.ts b/server/sonar-web/src/main/js/api/security-hotspots.ts
index 0a54022b6db..d9a1213caed 100644
--- a/server/sonar-web/src/main/js/api/security-hotspots.ts
+++ b/server/sonar-web/src/main/js/api/security-hotspots.ts
@@ -51,6 +51,10 @@ export function commentSecurityHotspot(hotspotKey: string, comment: string): Pro
);
}
+export function deleteCommentSecurityHotspot(comment: string): Promise<void> {
+ return post('/api/hotspots/delete_comment', { comment }).catch(throwGlobalError);
+}
+
export function getSecurityHotspots(
data: {
projectKey: string;
diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotReviewHistory.tsx b/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotReviewHistory.tsx
index 1b94b1a590e..154db9dc547 100644
--- a/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotReviewHistory.tsx
+++ b/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotReviewHistory.tsx
@@ -20,6 +20,9 @@
import * as classNames from 'classnames';
import { sanitize } from 'dompurify';
import * as React from 'react';
+import { Button, DeleteButton } from 'sonar-ui-common/components/controls/buttons';
+import Dropdown from 'sonar-ui-common/components/controls/Dropdown';
+import { PopupPlacement } from 'sonar-ui-common/components/ui/popups';
import { translate, translateWithParameters } from 'sonar-ui-common/helpers/l10n';
import DateTimeFormatter from '../../../components/intl/DateTimeFormatter';
import IssueChangelogDiff from '../../../components/issue/components/IssueChangelogDiff';
@@ -29,15 +32,17 @@ import { getHotspotReviewHistory } from '../utils';
export interface HotspotReviewHistoryProps {
hotspot: Hotspot;
+ onDeleteComment: (key: string) => void;
}
export default function HotspotReviewHistory(props: HotspotReviewHistoryProps) {
- const reviewHistory = getHotspotReviewHistory(props.hotspot);
+ const { hotspot } = props;
+ const reviewHistory = getHotspotReviewHistory(hotspot);
return (
<>
{reviewHistory.map((historyElt, historyIndex) => {
- const { user, type, diffs, date, html } = historyElt;
+ const { user, type, diffs, date, html, key, updatable } = historyElt;
return (
<div
className={classNames('padded', { 'bordered-top': historyIndex > 0 })}
@@ -78,11 +83,28 @@ export default function HotspotReviewHistory(props: HotspotReviewHistoryProps) {
</div>
)}
- {type === ReviewHistoryType.Comment && html && (
- <div
- className="spacer-top markdown"
- dangerouslySetInnerHTML={{ __html: sanitize(html) }}
- />
+ {type === ReviewHistoryType.Comment && key && html && (
+ <div className="spacer-top display-flex-space-between">
+ <div className="markdown" dangerouslySetInnerHTML={{ __html: sanitize(html) }} />
+ {updatable && (
+ <div className="dropdown">
+ <Dropdown
+ overlay={
+ <div className="padded abs-width-150">
+ <p>{translate('issue.comment.delete_confirm_message')}</p>
+ <Button
+ className="button-red big-spacer-top pull-right"
+ onClick={() => props.onDeleteComment(key)}>
+ {translate('delete')}
+ </Button>
+ </div>
+ }
+ overlayPlacement={PopupPlacement.BottomRight}>
+ <DeleteButton className="it__hotspots-comment-delete button-small" />
+ </Dropdown>
+ </div>
+ )}
+ </div>
)}
</div>
);
diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotReviewHistoryAndComments.tsx b/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotReviewHistoryAndComments.tsx
index c7d73b89a6b..a2adc0af84e 100644
--- a/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotReviewHistoryAndComments.tsx
+++ b/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotReviewHistoryAndComments.tsx
@@ -21,7 +21,10 @@ import * as classNames from 'classnames';
import * as React from 'react';
import { Button, ResetButtonLink } from 'sonar-ui-common/components/controls/buttons';
import { translate } from 'sonar-ui-common/helpers/l10n';
-import { commentSecurityHotspot } from '../../../api/security-hotspots';
+import {
+ commentSecurityHotspot,
+ deleteCommentSecurityHotspot
+} from '../../../api/security-hotspots';
import MarkdownTips from '../../../components/common/MarkdownTips';
import { isLoggedIn } from '../../../helpers/users';
import { Hotspot } from '../../../types/security-hotspots';
@@ -74,6 +77,12 @@ export default class HotspotReviewHistoryAndComments extends React.PureComponent
});
};
+ handleDeleteComment = (key: string) => {
+ return deleteCommentSecurityHotspot(key).then(() => {
+ this.props.onCommentUpdate();
+ });
+ };
+
render() {
const { currentUser, hotspot, commentTextRef, commentVisible } = this.props;
const { comment } = this.state;
@@ -81,7 +90,7 @@ export default class HotspotReviewHistoryAndComments extends React.PureComponent
<>
<h1>{translate('hotspot.section.activity')}</h1>
<div className="padded">
- <HotspotReviewHistory hotspot={hotspot} />
+ <HotspotReviewHistory hotspot={hotspot} onDeleteComment={this.handleDeleteComment} />
{isLoggedIn(currentUser) && (
<>
diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/HotspotReviewHistory-test.tsx b/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/HotspotReviewHistory-test.tsx
index 1488c45d1c9..4dfcf73f49d 100644
--- a/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/HotspotReviewHistory-test.tsx
+++ b/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/HotspotReviewHistory-test.tsx
@@ -56,7 +56,7 @@ function shallowRender(props?: Partial<HotspotReviewHistoryProps>) {
createdAt: '2018-09-11',
htmlText: '<strong>TEST</strong>',
markdown: '*TEST*',
- updatable: true,
+ updatable: false,
login: 'dude-2',
user: mockUser({ login: 'dude-2' })
};
@@ -65,5 +65,5 @@ function shallowRender(props?: Partial<HotspotReviewHistoryProps>) {
changelog: [changelogElement],
comment: [commentElement, commentElement1]
});
- return shallow(<HotspotReviewHistory hotspot={hotspot} {...props} />);
+ return shallow(<HotspotReviewHistory hotspot={hotspot} onDeleteComment={jest.fn()} {...props} />);
}
diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/HotspotReviewHistoryAndComments-test.tsx b/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/HotspotReviewHistoryAndComments-test.tsx
index f1d78b6c18a..e9f2b17b913 100644
--- a/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/HotspotReviewHistoryAndComments-test.tsx
+++ b/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/HotspotReviewHistoryAndComments-test.tsx
@@ -20,14 +20,19 @@
import { shallow } from 'enzyme';
import * as React from 'react';
import { waitAndUpdate } from 'sonar-ui-common/helpers/testUtils';
-import { commentSecurityHotspot } from '../../../../api/security-hotspots';
+import {
+ commentSecurityHotspot,
+ deleteCommentSecurityHotspot
+} from '../../../../api/security-hotspots';
import { mockHotspot } from '../../../../helpers/mocks/security-hotspots';
import { mockCurrentUser } from '../../../../helpers/testMocks';
import { isLoggedIn } from '../../../../helpers/users';
+import HotspotReviewHistory from '../HotspotReviewHistory';
import HotspotReviewHistoryAndComments from '../HotspotReviewHistoryAndComments';
jest.mock('../../../../api/security-hotspots', () => ({
- commentSecurityHotspot: jest.fn().mockResolvedValue({})
+ commentSecurityHotspot: jest.fn().mockResolvedValue({}),
+ deleteCommentSecurityHotspot: jest.fn().mockResolvedValue({})
}));
jest.mock('../../../../helpers/users', () => ({ isLoggedIn: jest.fn(() => true) }));
@@ -95,6 +100,12 @@ it('should reset on change hotspot', () => {
expect(wrapper.state().comment).toBe('');
});
+it('should delete comment', () => {
+ const wrapper = shallowRender();
+ wrapper.find(HotspotReviewHistory).simulate('deleteComment', 'me1');
+ expect(deleteCommentSecurityHotspot).toHaveBeenCalledWith('me1');
+});
+
function shallowRender(props?: Partial<HotspotReviewHistoryAndComments['props']>) {
return shallow<HotspotReviewHistoryAndComments>(
<HotspotReviewHistoryAndComments
diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/__snapshots__/HotspotReviewHistory-test.tsx.snap b/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/__snapshots__/HotspotReviewHistory-test.tsx.snap
index 395669fefb7..f1ebd04f7c4 100644
--- a/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/__snapshots__/HotspotReviewHistory-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/__snapshots__/HotspotReviewHistory-test.tsx.snap
@@ -62,13 +62,43 @@ exports[`should render correctly 1`] = `
/>
</div>
<div
- className="spacer-top markdown"
- dangerouslySetInnerHTML={
- Object {
- "__html": "<strong>TEST</strong>",
+ className="spacer-top display-flex-space-between"
+ >
+ <div
+ className="markdown"
+ dangerouslySetInnerHTML={
+ Object {
+ "__html": "<strong>TEST</strong>",
+ }
}
- }
- />
+ />
+ <div
+ className="dropdown"
+ >
+ <Dropdown
+ overlay={
+ <div
+ className="padded abs-width-150"
+ >
+ <p>
+ issue.comment.delete_confirm_message
+ </p>
+ <Button
+ className="button-red big-spacer-top pull-right"
+ onClick={[Function]}
+ >
+ delete
+ </Button>
+ </div>
+ }
+ overlayPlacement="bottom-right"
+ >
+ <DeleteButton
+ className="js-issue-comment-delete button-small"
+ />
+ </Dropdown>
+ </div>
+ </div>
</div>
<div
className="padded bordered-top"
@@ -100,13 +130,17 @@ exports[`should render correctly 1`] = `
/>
</div>
<div
- className="spacer-top markdown"
- dangerouslySetInnerHTML={
- Object {
- "__html": "<strong>TEST</strong>",
+ className="spacer-top display-flex-space-between"
+ >
+ <div
+ className="markdown"
+ dangerouslySetInnerHTML={
+ Object {
+ "__html": "<strong>TEST</strong>",
+ }
}
- }
- />
+ />
+ </div>
</div>
<div
className="padded bordered-top"
diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/__snapshots__/HotspotReviewHistoryAndComments-test.tsx.snap b/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/__snapshots__/HotspotReviewHistoryAndComments-test.tsx.snap
index e71ea8d94c3..787a71d7458 100644
--- a/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/__snapshots__/HotspotReviewHistoryAndComments-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/__snapshots__/HotspotReviewHistoryAndComments-test.tsx.snap
@@ -108,6 +108,7 @@ exports[`should render correctly 1`] = `
],
}
}
+ onDeleteComment={[Function]}
/>
<hr />
<div
@@ -271,6 +272,7 @@ exports[`should render correctly without user 1`] = `
],
}
}
+ onDeleteComment={[Function]}
/>
</div>
</Fragment>
diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/styles.css b/server/sonar-web/src/main/js/apps/security-hotspots/styles.css
index 69d689e6df0..f3fb14651d6 100644
--- a/server/sonar-web/src/main/js/apps/security-hotspots/styles.css
+++ b/server/sonar-web/src/main/js/apps/security-hotspots/styles.css
@@ -62,3 +62,8 @@
.invisible {
visibility: hidden;
}
+
+#security_hotspots .review-comment {
+ display: flex;
+ justify-content: space-between;
+}
diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/utils.ts b/server/sonar-web/src/main/js/apps/security-hotspots/utils.ts
index 06c3898631b..81f1c6a6cba 100644
--- a/server/sonar-web/src/main/js/apps/security-hotspots/utils.ts
+++ b/server/sonar-web/src/main/js/apps/security-hotspots/utils.ts
@@ -115,11 +115,13 @@ export function getHotspotReviewHistory(hotspot: Hotspot): ReviewHistoryElement[
...hotspot.comment.map(comment => ({
type: ReviewHistoryType.Comment,
date: comment.createdAt,
+ updatable: comment.updatable,
user: {
...comment.user,
name: comment.user.name || comment.user.login
},
- html: comment.htmlText
+ html: comment.htmlText,
+ key: comment.key
}))
);
}
diff --git a/server/sonar-web/src/main/js/types/security-hotspots.ts b/server/sonar-web/src/main/js/types/security-hotspots.ts
index 6ab8963e914..ad9179545e9 100644
--- a/server/sonar-web/src/main/js/types/security-hotspots.ts
+++ b/server/sonar-web/src/main/js/types/security-hotspots.ts
@@ -126,6 +126,8 @@ export interface ReviewHistoryElement {
user: Pick<T.UserBase, 'active' | 'avatar' | 'name'>;
diffs?: T.IssueChangelogDiff[];
html?: string;
+ key?: string;
+ updatable?: boolean;
}
export enum ReviewHistoryType {