aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMathieu Suen <mathieu.suen@sonarsource.com>2020-02-12 13:32:32 +0100
committerSonarTech <sonartech@sonarsource.com>2020-02-21 20:46:19 +0100
commit9bc1ac6000521a9a64c08c69100000d1f49cd383 (patch)
tree77ca6e62520727fbc7ac8258e6176d9e02c4c17e
parentb381bc38fdf5c082ac0c0f12b45926b10c34ddb1 (diff)
downloadsonarqube-9bc1ac6000521a9a64c08c69100000d1f49cd383.tar.gz
sonarqube-9bc1ac6000521a9a64c08c69100000d1f49cd383.zip
SONAR-12720 Put comment on bottom of hotspot review page and add a link from top.
-rw-r--r--server/sonar-web/src/main/js/apps/security-hotspots/__tests__/utils-test.ts11
-rw-r--r--server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotReviewHistory.tsx (renamed from server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotViewerReviewHistoryTab.tsx)65
-rw-r--r--server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotReviewHistoryAndComments.tsx131
-rw-r--r--server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotViewer.tsx43
-rw-r--r--server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotViewerRenderer.tsx56
-rw-r--r--server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotViewerReviewHistoryTabCommentBox.tsx89
-rw-r--r--server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotViewerTabs.tsx41
-rw-r--r--server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/HotspotReviewHistory-test.tsx69
-rw-r--r--server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/HotspotReviewHistoryAndComments-test.tsx111
-rw-r--r--server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/HotspotViewer-test.tsx55
-rw-r--r--server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/HotspotViewerRenderer-test.tsx12
-rw-r--r--server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/HotspotViewerReviewHistoryTab-test.tsx73
-rw-r--r--server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/HotspotViewerReviewHistoryTabCommentBox-test.tsx72
-rw-r--r--server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/HotspotViewerTabs-test.tsx25
-rw-r--r--server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/__snapshots__/HotspotReviewHistory-test.tsx.snap151
-rw-r--r--server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/__snapshots__/HotspotReviewHistoryAndComments-test.tsx.snap277
-rw-r--r--server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/__snapshots__/HotspotViewer-test.tsx.snap30
-rw-r--r--server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/__snapshots__/HotspotViewerRenderer-test.tsx.snap750
-rw-r--r--server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/__snapshots__/HotspotViewerReviewHistoryTab-test.tsx.snap270
-rw-r--r--server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/__snapshots__/HotspotViewerReviewHistoryTabCommentBox-test.tsx.snap78
-rw-r--r--server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/__snapshots__/HotspotViewerTabs-test.tsx.snap799
-rw-r--r--server/sonar-web/src/main/js/apps/security-hotspots/styles.css13
-rw-r--r--server/sonar-web/src/main/js/apps/security-hotspots/utils.ts15
-rw-r--r--sonar-core/src/main/resources/org/sonar/l10n/core.properties12
24 files changed, 1678 insertions, 1570 deletions
diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/__tests__/utils-test.ts b/server/sonar-web/src/main/js/apps/security-hotspots/__tests__/utils-test.ts
index 174d4dbe7e2..8df41e695eb 100644
--- a/server/sonar-web/src/main/js/apps/security-hotspots/__tests__/utils-test.ts
+++ b/server/sonar-web/src/main/js/apps/security-hotspots/__tests__/utils-test.ts
@@ -188,16 +188,15 @@ describe('getHotspotReviewHistory', () => {
});
const reviewHistory = getHotspotReviewHistory(hotspot);
- expect(reviewHistory.history.length).toBe(4);
- expect(reviewHistory.functionalCount).toBe(3);
- expect(reviewHistory.history[0]).toEqual(
+ expect(reviewHistory.length).toBe(4);
+ expect(reviewHistory[0]).toEqual(
expect.objectContaining({
type: ReviewHistoryType.Creation,
date: hotspot.creationDate,
user: hotspot.authorUser
})
);
- expect(reviewHistory.history[1]).toEqual(
+ expect(reviewHistory[1]).toEqual(
expect.objectContaining({
type: ReviewHistoryType.Comment,
date: commentElement.createdAt,
@@ -205,7 +204,7 @@ describe('getHotspotReviewHistory', () => {
html: commentElement.htmlText
})
);
- expect(reviewHistory.history[2]).toEqual(
+ expect(reviewHistory[2]).toEqual(
expect.objectContaining({
type: ReviewHistoryType.Comment,
date: commentElement1.createdAt,
@@ -213,7 +212,7 @@ describe('getHotspotReviewHistory', () => {
html: commentElement1.htmlText
})
);
- expect(reviewHistory.history[3]).toEqual(
+ expect(reviewHistory[3]).toEqual(
expect.objectContaining({
type: ReviewHistoryType.Diff,
date: changelogElement.creationDate,
diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotViewerReviewHistoryTab.tsx b/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotReviewHistory.tsx
index 07989ed42f7..1b94b1a590e 100644
--- a/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotViewerReviewHistoryTab.tsx
+++ b/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotReviewHistory.tsx
@@ -17,83 +17,76 @@
* 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 classNames from 'classnames';
import { sanitize } from 'dompurify';
import * as React from 'react';
import { translate, translateWithParameters } from 'sonar-ui-common/helpers/l10n';
import DateTimeFormatter from '../../../components/intl/DateTimeFormatter';
import IssueChangelogDiff from '../../../components/issue/components/IssueChangelogDiff';
import Avatar from '../../../components/ui/Avatar';
-import { Hotspot, ReviewHistoryElement, ReviewHistoryType } from '../../../types/security-hotspots';
-import HotspotViewerReviewHistoryTabCommentBox from './HotspotViewerReviewHistoryTabCommentBox';
+import { Hotspot, ReviewHistoryType } from '../../../types/security-hotspots';
+import { getHotspotReviewHistory } from '../utils';
-export interface HotspotViewerReviewHistoryTabProps {
- history: ReviewHistoryElement[];
+export interface HotspotReviewHistoryProps {
hotspot: Hotspot;
- onUpdateHotspot: () => void;
}
-export default function HotspotViewerReviewHistoryTab(props: HotspotViewerReviewHistoryTabProps) {
- const { history, hotspot } = props;
+export default function HotspotReviewHistory(props: HotspotReviewHistoryProps) {
+ const reviewHistory = getHotspotReviewHistory(props.hotspot);
return (
- <div className="padded">
- {history.map((elt, historyIndex) => (
- <React.Fragment key={historyIndex}>
- {historyIndex > 0 && <hr />}
- <div className="padded">
+ <>
+ {reviewHistory.map((historyElt, historyIndex) => {
+ const { user, type, diffs, date, html } = historyElt;
+ return (
+ <div
+ className={classNames('padded', { 'bordered-top': historyIndex > 0 })}
+ key={historyIndex}>
<div className="display-flex-center">
- {elt.user.name && (
+ {user.name && (
<>
<Avatar
className="little-spacer-right"
- hash={elt.user.avatar}
- name={elt.user.name}
+ hash={user.avatar}
+ name={user.name}
size={20}
/>
<strong>
- {elt.user.active
- ? elt.user.name
- : translateWithParameters('user.x_deleted', elt.user.name)}
+ {user.active ? user.name : translateWithParameters('user.x_deleted', user.name)}
</strong>
- {elt.type === ReviewHistoryType.Creation && (
+ {type === ReviewHistoryType.Creation && (
<span className="little-spacer-left">
- {translate('hotspots.tabs.review_history.created')}
+ {translate('hotspots.review_history.created')}
</span>
)}
- {elt.type === ReviewHistoryType.Comment && (
+ {type === ReviewHistoryType.Comment && (
<span className="little-spacer-left">
- {translate('hotspots.tabs.review_history.comment.added')}
+ {translate('hotspots.review_history.comment_added')}
</span>
)}
<span className="little-spacer-left little-spacer-right">-</span>
</>
)}
- <DateTimeFormatter date={elt.date} />
+ <DateTimeFormatter date={date} />
</div>
- {elt.type === ReviewHistoryType.Diff && elt.diffs && (
+ {type === ReviewHistoryType.Diff && diffs && (
<div className="spacer-top">
- {elt.diffs.map((diff, diffIndex) => (
+ {diffs.map((diff, diffIndex) => (
<IssueChangelogDiff diff={diff} key={diffIndex} />
))}
</div>
)}
- {elt.type === ReviewHistoryType.Comment && elt.html && (
+ {type === ReviewHistoryType.Comment && html && (
<div
className="spacer-top markdown"
- dangerouslySetInnerHTML={{ __html: sanitize(elt.html) }}
+ dangerouslySetInnerHTML={{ __html: sanitize(html) }}
/>
)}
</div>
- </React.Fragment>
- ))}
- <hr />
- <HotspotViewerReviewHistoryTabCommentBox
- hotspot={hotspot}
- onUpdateHotspot={props.onUpdateHotspot}
- />
- </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
new file mode 100644
index 00000000000..c7d73b89a6b
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotReviewHistoryAndComments.tsx
@@ -0,0 +1,131 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2020 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 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 MarkdownTips from '../../../components/common/MarkdownTips';
+import { isLoggedIn } from '../../../helpers/users';
+import { Hotspot } from '../../../types/security-hotspots';
+import HotspotReviewHistory from './HotspotReviewHistory';
+
+interface Props {
+ currentUser: T.CurrentUser;
+ hotspot: Hotspot;
+ commentTextRef: React.RefObject<HTMLTextAreaElement>;
+ commentVisible: boolean;
+ onCommentUpdate: () => void;
+ onOpenComment: () => void;
+ onCloseComment: () => void;
+}
+
+interface State {
+ comment: string;
+}
+
+export default class HotspotReviewHistoryAndComments extends React.PureComponent<Props, State> {
+ constructor(props: Props) {
+ super(props);
+ this.state = {
+ comment: ''
+ };
+ }
+
+ componentDidUpdate(prevProps: Props) {
+ if (prevProps.hotspot !== this.props.hotspot) {
+ this.setState({
+ comment: ''
+ });
+ }
+ }
+
+ handleCommentChange = (event: React.ChangeEvent<HTMLTextAreaElement>) => {
+ this.setState({ comment: event.target.value });
+ };
+
+ handleCloseComment = () => {
+ this.setState({ comment: '' });
+ this.props.onCloseComment();
+ };
+
+ handleSubmitComment = () => {
+ return commentSecurityHotspot(this.props.hotspot.key, this.state.comment).then(() => {
+ this.setState({ comment: '' });
+ this.props.onCloseComment();
+ this.props.onCommentUpdate();
+ });
+ };
+
+ render() {
+ const { currentUser, hotspot, commentTextRef, commentVisible } = this.props;
+ const { comment } = this.state;
+ return (
+ <>
+ <h1>{translate('hotspot.section.activity')}</h1>
+ <div className="padded">
+ <HotspotReviewHistory hotspot={hotspot} />
+
+ {isLoggedIn(currentUser) && (
+ <>
+ <hr />
+ <div className="big-spacer-top">
+ <Button
+ className={classNames({ invisible: commentVisible })}
+ id="hotspot-comment-box-display"
+ onClick={this.props.onOpenComment}>
+ {translate('hotspots.comment.open')}
+ </Button>
+
+ <div className={classNames({ invisible: !commentVisible })}>
+ <div className="little-spacer-bottom">{translate('hotspots.comment.field')}</div>
+ <textarea
+ className="form-field fixed-width width-100 spacer-bottom"
+ onChange={this.handleCommentChange}
+ ref={commentTextRef}
+ rows={2}
+ value={comment}
+ />
+ <div className="display-flex-space-between display-flex-center ">
+ <MarkdownTips className="huge-spacer-bottom" />
+ <div>
+ <Button
+ className="huge-spacer-bottom"
+ id="hotspot-comment-box-submit"
+ onClick={this.handleSubmitComment}>
+ {translate('hotspots.comment.submit')}
+ </Button>
+ <ResetButtonLink
+ className="spacer-left huge-spacer-bottom"
+ id="hotspot-comment-box-cancel"
+ onClick={this.handleCloseComment}>
+ {translate('cancel')}
+ </ResetButtonLink>
+ </div>
+ </div>
+ </div>
+ </div>
+ </>
+ )}
+ </div>
+ </>
+ );
+ }
+}
diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotViewer.tsx b/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotViewer.tsx
index 2a23816f1ba..58a2789fdef 100644
--- a/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotViewer.tsx
+++ b/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotViewer.tsx
@@ -19,6 +19,7 @@
*/
import * as React from 'react';
+import { scrollToElement } from 'sonar-ui-common/helpers/scrolling';
import { getSecurityHotspotDetails } from '../../../api/security-hotspots';
import { BranchLike } from '../../../types/branch-like';
import { Hotspot } from '../../../types/security-hotspots';
@@ -35,21 +36,34 @@ interface Props {
interface State {
hotspot?: Hotspot;
loading: boolean;
+ commentVisible: boolean;
}
export default class HotspotViewer extends React.PureComponent<Props, State> {
mounted = false;
- state: State = { loading: false };
+ state: State;
+ commentTextRef: React.RefObject<HTMLTextAreaElement>;
+ parentScrollRef: React.RefObject<HTMLDivElement>;
+
+ constructor(props: Props) {
+ super(props);
+ this.commentTextRef = React.createRef<HTMLTextAreaElement>();
+ this.parentScrollRef = React.createRef<HTMLDivElement>();
+ this.state = { loading: false, commentVisible: false };
+ }
componentDidMount() {
this.mounted = true;
this.fetchHotspot();
}
- componentDidUpdate(prevProps: Props) {
+ componentDidUpdate(prevProps: Props, prevState: State) {
if (prevProps.hotspotKey !== this.props.hotspotKey) {
this.fetchHotspot();
}
+ if (this.commentTextRef.current && !prevState.commentVisible && this.state.commentVisible) {
+ this.commentTextRef.current.focus({ preventScroll: true });
+ }
}
componentWillUnmount() {
@@ -76,17 +90,40 @@ export default class HotspotViewer extends React.PureComponent<Props, State> {
});
};
+ handleOpenComment = () => {
+ this.setState({ commentVisible: true });
+ if (this.commentTextRef.current) {
+ // Edge case when the comment is already open and unfocus.
+ this.commentTextRef.current.focus({ preventScroll: true });
+ }
+ if (this.commentTextRef.current && this.parentScrollRef.current) {
+ scrollToElement(this.commentTextRef.current, {
+ parent: this.parentScrollRef.current,
+ bottomOffset: 100
+ });
+ }
+ };
+
+ handleCloseComment = () => {
+ this.setState({ commentVisible: false });
+ };
+
render() {
const { branchLike, component, securityCategories } = this.props;
- const { hotspot, loading } = this.state;
+ const { hotspot, loading, commentVisible } = this.state;
return (
<HotspotViewerRenderer
branchLike={branchLike}
component={component}
+ commentTextRef={this.commentTextRef}
+ commentVisible={commentVisible}
hotspot={hotspot}
loading={loading}
+ onCloseComment={this.handleCloseComment}
+ onOpenComment={this.handleOpenComment}
onUpdateHotspot={this.handleHotspotUpdate}
+ parentScrollRef={this.parentScrollRef}
securityCategories={securityCategories}
/>
);
diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotViewerRenderer.tsx b/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotViewerRenderer.tsx
index 0730dd96b48..db0db20080f 100644
--- a/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotViewerRenderer.tsx
+++ b/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotViewerRenderer.tsx
@@ -19,16 +19,20 @@
*/
import * as classNames from 'classnames';
import * as React from 'react';
+import { Button } from 'sonar-ui-common/components/controls/buttons';
import { ClipboardButton } from 'sonar-ui-common/components/controls/clipboard';
import LinkIcon from 'sonar-ui-common/components/icons/LinkIcon';
import DeferredSpinner from 'sonar-ui-common/components/ui/DeferredSpinner';
import { translate } from 'sonar-ui-common/helpers/l10n';
import { getPathUrlAsString } from 'sonar-ui-common/helpers/urls';
+import { withCurrentUser } from '../../../components/hoc/withCurrentUser';
import { getBranchLikeQuery } from '../../../helpers/branch-like';
import { getComponentSecurityHotspotsUrl } from '../../../helpers/urls';
+import { isLoggedIn } from '../../../helpers/users';
import { BranchLike } from '../../../types/branch-like';
import { Hotspot } from '../../../types/security-hotspots';
import Assignee from './assignee/Assignee';
+import HotspotReviewHistoryAndComments from './HotspotReviewHistoryAndComments';
import HotspotSnippetContainer from './HotspotSnippetContainer';
import './HotspotViewer.css';
import HotspotViewerTabs from './HotspotViewerTabs';
@@ -37,14 +41,30 @@ import Status from './status/Status';
export interface HotspotViewerRendererProps {
branchLike?: BranchLike;
component: T.Component;
+ currentUser: T.CurrentUser;
hotspot?: Hotspot;
loading: boolean;
+ commentVisible: boolean;
+ commentTextRef: React.RefObject<HTMLTextAreaElement>;
+ onOpenComment: () => void;
+ onCloseComment: () => void;
onUpdateHotspot: () => Promise<void>;
+ parentScrollRef: React.RefObject<HTMLDivElement>;
securityCategories: T.StandardSecurityCategories;
}
-export default function HotspotViewerRenderer(props: HotspotViewerRendererProps) {
- const { branchLike, component, hotspot, loading, securityCategories } = props;
+export function HotspotViewerRenderer(props: HotspotViewerRendererProps) {
+ const {
+ branchLike,
+ component,
+ currentUser,
+ hotspot,
+ loading,
+ securityCategories,
+ commentTextRef,
+ commentVisible,
+ parentScrollRef
+ } = props;
const permalink = getPathUrlAsString(
getComponentSecurityHotspotsUrl(component.key, {
@@ -57,13 +77,22 @@ export default function HotspotViewerRenderer(props: HotspotViewerRendererProps)
return (
<DeferredSpinner loading={loading}>
{hotspot && (
- <div className="big-padded">
+ <div className="big-padded hotspot-content" ref={parentScrollRef}>
<div className="huge-spacer-bottom display-flex-space-between">
<strong className="big big-spacer-right">{hotspot.message}</strong>
- <ClipboardButton copyValue={permalink}>
- <LinkIcon className="spacer-right" />
- <span>{translate('hotspots.get_permalink')}</span>
- </ClipboardButton>
+ <div className="display-flex-row flex-0">
+ {isLoggedIn(currentUser) && (
+ <div className="dropdown spacer-right flex-1-0-auto">
+ <Button onClick={props.onOpenComment}>
+ {translate('hotspots.comment.open')}
+ </Button>
+ </div>
+ )}
+ <ClipboardButton className="flex-1-0-auto" copyValue={permalink}>
+ <LinkIcon className="spacer-right" />
+ <span>{translate('hotspots.get_permalink')}</span>
+ </ClipboardButton>
+ </div>
</div>
<div className="huge-spacer-bottom display-flex-row">
@@ -97,9 +126,20 @@ export default function HotspotViewerRenderer(props: HotspotViewerRendererProps)
</div>
<HotspotSnippetContainer branchLike={branchLike} hotspot={hotspot} />
- <HotspotViewerTabs hotspot={hotspot} onUpdateHotspot={props.onUpdateHotspot} />
+ <HotspotViewerTabs hotspot={hotspot} />
+ <HotspotReviewHistoryAndComments
+ commentTextRef={commentTextRef}
+ commentVisible={commentVisible}
+ currentUser={currentUser}
+ hotspot={hotspot}
+ onCloseComment={props.onCloseComment}
+ onCommentUpdate={props.onUpdateHotspot}
+ onOpenComment={props.onOpenComment}
+ />
</div>
)}
</DeferredSpinner>
);
}
+
+export default withCurrentUser(HotspotViewerRenderer);
diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotViewerReviewHistoryTabCommentBox.tsx b/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotViewerReviewHistoryTabCommentBox.tsx
deleted file mode 100644
index df8afcfff29..00000000000
--- a/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotViewerReviewHistoryTabCommentBox.tsx
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 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 { Button, ResetButtonLink } from 'sonar-ui-common/components/controls/buttons';
-import { translate } from 'sonar-ui-common/helpers/l10n';
-import { commentSecurityHotspot } from '../../../api/security-hotspots';
-import MarkdownTips from '../../../components/common/MarkdownTips';
-import { Hotspot } from '../../../types/security-hotspots';
-
-export interface HotspotViewerReviewHistoryTabCommentBoxProps {
- hotspot: Hotspot;
- onUpdateHotspot: () => void;
-}
-
-export default function HotspotViewerReviewHistoryTabCommentBox(
- props: HotspotViewerReviewHistoryTabCommentBoxProps
-) {
- const { hotspot } = props;
- const [comment, setComment] = React.useState();
- const [isCommentBoxVisible, setCommentBoxVisibility] = React.useState(false);
-
- const onCancel = () => {
- setComment(null);
- setCommentBoxVisibility(false);
- };
-
- const onComment = () => {
- return commentSecurityHotspot(hotspot.key, comment).then(() => {
- onCancel();
- props.onUpdateHotspot();
- });
- };
-
- return (
- <div className="big-spacer-top">
- {!isCommentBoxVisible ? (
- <Button id="hotspot-comment-box-display" onClick={() => setCommentBoxVisibility(true)}>
- {translate('hotspots.tabs.review_history.comment.add')}
- </Button>
- ) : (
- <>
- <div className="little-spacer-bottom">
- {translate('hotspots.tabs.review_history.comment.field')}
- </div>
- <textarea
- autoFocus={true}
- className="form-field fixed-width width-100 spacer-bottom"
- onChange={(event: React.ChangeEvent<HTMLTextAreaElement>) =>
- setComment(event.target.value)
- }
- rows={2}
- />
- <div className="display-flex-space-between display-flex-center">
- <MarkdownTips />
- <div>
- <Button id="hotspot-comment-box-submit" onClick={onComment}>
- {translate('hotspots.tabs.review_history.comment.submit')}
- </Button>
- <ResetButtonLink
- className="spacer-left"
- id="hotspot-comment-box-cancel"
- onClick={onCancel}>
- {translate('cancel')}
- </ResetButtonLink>
- </div>
- </div>
- </>
- )}
- </div>
- );
-}
diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotViewerTabs.tsx b/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotViewerTabs.tsx
index 961c8829c64..69297641ea7 100644
--- a/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotViewerTabs.tsx
+++ b/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotViewerTabs.tsx
@@ -23,12 +23,9 @@ import BoxedTabs from 'sonar-ui-common/components/controls/BoxedTabs';
import Tab from 'sonar-ui-common/components/controls/Tabs';
import { translate } from 'sonar-ui-common/helpers/l10n';
import { Hotspot } from '../../../types/security-hotspots';
-import { getHotspotReviewHistory } from '../utils';
-import HotspotViewerReviewHistoryTab from './HotspotViewerReviewHistoryTab';
interface Props {
hotspot: Hotspot;
- onUpdateHotspot: () => void;
}
interface State {
@@ -39,14 +36,13 @@ interface State {
interface Tab {
key: TabKeys;
label: React.ReactNode;
- content: React.ReactNode;
+ content: string;
}
export enum TabKeys {
RiskDescription = 'risk',
VulnerabilityDescription = 'vulnerability',
- FixRecommendation = 'fix',
- ReviewHistory = 'review'
+ FixRecommendation = 'fix'
}
export default class HotspotViewerTabs extends React.PureComponent<Props, State> {
@@ -77,7 +73,6 @@ export default class HotspotViewerTabs extends React.PureComponent<Props, State>
computeTabs() {
const { hotspot } = this.props;
- const hotspotReviewHistory = getHotspotReviewHistory(hotspot);
return [
{
key: TabKeys.RiskDescription,
@@ -93,26 +88,6 @@ export default class HotspotViewerTabs extends React.PureComponent<Props, State>
key: TabKeys.FixRecommendation,
label: translate('hotspots.tabs.fix_recommendations'),
content: hotspot.rule.fixRecommendations || ''
- },
- {
- key: TabKeys.ReviewHistory,
- label: (
- <>
- <span>{translate('hotspots.tabs.review_history')}</span>
- {hotspotReviewHistory.functionalCount > 0 && (
- <span className="counter-badge spacer-left">
- {hotspotReviewHistory.functionalCount}
- </span>
- )}
- </>
- ),
- content: hotspotReviewHistory.history.length > 0 && (
- <HotspotViewerReviewHistoryTab
- history={hotspotReviewHistory.history}
- hotspot={hotspot}
- onUpdateHotspot={this.props.onUpdateHotspot}
- />
- )
}
].filter(tab => Boolean(tab.content));
}
@@ -127,14 +102,10 @@ export default class HotspotViewerTabs extends React.PureComponent<Props, State>
<>
<BoxedTabs onSelect={this.handleSelectTabs} selected={currentTab.key} tabs={tabs} />
<div className="bordered huge-spacer-bottom">
- {typeof currentTab.content === 'string' ? (
- <div
- className="markdown big-padded"
- dangerouslySetInnerHTML={{ __html: sanitize(currentTab.content) }}
- />
- ) : (
- <>{currentTab.content}</>
- )}
+ <div
+ className="markdown big-padded"
+ dangerouslySetInnerHTML={{ __html: sanitize(currentTab.content) }}
+ />
</div>
</>
);
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
new file mode 100644
index 00000000000..1488c45d1c9
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/HotspotReviewHistory-test.tsx
@@ -0,0 +1,69 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2020 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 { shallow } from 'enzyme';
+import * as React from 'react';
+import { mockHotspot } from '../../../../helpers/mocks/security-hotspots';
+import { mockUser } from '../../../../helpers/testMocks';
+import HotspotReviewHistory, { HotspotReviewHistoryProps } from '../HotspotReviewHistory';
+
+it('should render correctly', () => {
+ const wrapper = shallowRender();
+ expect(wrapper).toMatchSnapshot();
+});
+
+function shallowRender(props?: Partial<HotspotReviewHistoryProps>) {
+ const changelogElement: T.IssueChangelog = {
+ creationDate: '2018-10-01',
+ isUserActive: true,
+ user: 'me',
+ userName: 'me-name',
+ diffs: [
+ {
+ key: 'assign',
+ newValue: 'me',
+ oldValue: 'him'
+ }
+ ]
+ };
+ const commentElement = {
+ key: 'comment-1',
+ createdAt: '2018-09-10',
+ htmlText: '<strong>TEST</strong>',
+ markdown: '*TEST*',
+ updatable: true,
+ login: 'dude-1',
+ user: mockUser({ login: 'dude-1' })
+ };
+ const commentElement1 = {
+ key: 'comment-2',
+ createdAt: '2018-09-11',
+ htmlText: '<strong>TEST</strong>',
+ markdown: '*TEST*',
+ updatable: true,
+ login: 'dude-2',
+ user: mockUser({ login: 'dude-2' })
+ };
+ const hotspot = mockHotspot({
+ creationDate: '2018-09-01',
+ changelog: [changelogElement],
+ comment: [commentElement, commentElement1]
+ });
+ return shallow(<HotspotReviewHistory hotspot={hotspot} {...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
new file mode 100644
index 00000000000..f1d78b6c18a
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/HotspotReviewHistoryAndComments-test.tsx
@@ -0,0 +1,111 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2020 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 { shallow } from 'enzyme';
+import * as React from 'react';
+import { waitAndUpdate } from 'sonar-ui-common/helpers/testUtils';
+import { commentSecurityHotspot } from '../../../../api/security-hotspots';
+import { mockHotspot } from '../../../../helpers/mocks/security-hotspots';
+import { mockCurrentUser } from '../../../../helpers/testMocks';
+import { isLoggedIn } from '../../../../helpers/users';
+import HotspotReviewHistoryAndComments from '../HotspotReviewHistoryAndComments';
+
+jest.mock('../../../../api/security-hotspots', () => ({
+ commentSecurityHotspot: jest.fn().mockResolvedValue({})
+}));
+
+jest.mock('../../../../helpers/users', () => ({ isLoggedIn: jest.fn(() => true) }));
+
+it('should render correctly', () => {
+ const wrapper = shallowRender();
+ expect(wrapper).toMatchSnapshot();
+});
+
+it('should render correctly without user', () => {
+ ((isLoggedIn as any) as jest.Mock<boolean, [boolean]>).mockReturnValueOnce(false);
+ const wrapper = shallowRender();
+ expect(wrapper).toMatchSnapshot();
+});
+
+it('should open comment form', () => {
+ const wrapper = shallowRender();
+ wrapper.find('#hotspot-comment-box-display').simulate('click');
+ expect(wrapper.instance().props.onOpenComment).toHaveBeenCalled();
+});
+
+it('should submit comment', async () => {
+ const mockApi = commentSecurityHotspot as jest.Mock;
+ const hotspot = mockHotspot();
+ const wrapper = shallowRender({ hotspot, commentVisible: true });
+ mockApi.mockClear();
+ wrapper.instance().setState({ comment: 'Comment' });
+
+ wrapper.find('#hotspot-comment-box-submit').simulate('click');
+ await waitAndUpdate(wrapper);
+
+ expect(mockApi).toHaveBeenCalledWith(hotspot.key, 'Comment');
+ expect(wrapper.state().comment).toBe('');
+ expect(wrapper.instance().props.onCloseComment).toHaveBeenCalledTimes(1);
+ expect(wrapper.instance().props.onCommentUpdate).toHaveBeenCalledTimes(1);
+});
+
+it('should cancel comment', () => {
+ const mockApi = commentSecurityHotspot as jest.Mock;
+ const hotspot = mockHotspot();
+ const wrapper = shallowRender({ hotspot, commentVisible: true });
+ wrapper.instance().setState({ comment: 'Comment' });
+ mockApi.mockClear();
+
+ wrapper.find('#hotspot-comment-box-cancel').simulate('click');
+
+ expect(mockApi).not.toHaveBeenCalled();
+ expect(wrapper.state().comment).toBe('');
+ expect(wrapper.instance().props.onCloseComment).toHaveBeenCalledTimes(1);
+});
+
+it('should change comment', () => {
+ const wrapper = shallowRender({ commentVisible: true });
+ wrapper.instance().setState({ comment: 'Comment' });
+ wrapper.find('textarea').simulate('change', { target: { value: 'Foo' } });
+
+ expect(wrapper.state().comment).toBe('Foo');
+});
+
+it('should reset on change hotspot', () => {
+ const wrapper = shallowRender();
+ wrapper.setState({ comment: 'NOP' });
+ wrapper.setProps({ hotspot: mockHotspot() });
+
+ expect(wrapper.state().comment).toBe('');
+});
+
+function shallowRender(props?: Partial<HotspotReviewHistoryAndComments['props']>) {
+ return shallow<HotspotReviewHistoryAndComments>(
+ <HotspotReviewHistoryAndComments
+ commentTextRef={React.createRef()}
+ commentVisible={false}
+ currentUser={mockCurrentUser()}
+ hotspot={mockHotspot()}
+ onCloseComment={jest.fn()}
+ onCommentUpdate={jest.fn()}
+ onOpenComment={jest.fn()}
+ {...props}
+ />
+ );
+}
diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/HotspotViewer-test.tsx b/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/HotspotViewer-test.tsx
index 65efeea8fca..5fce1d9f64b 100644
--- a/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/HotspotViewer-test.tsx
+++ b/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/HotspotViewer-test.tsx
@@ -18,11 +18,14 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import { shallow } from 'enzyme';
+import { clone } from 'lodash';
import * as React from 'react';
+import { scrollToElement } from 'sonar-ui-common/helpers/scrolling';
import { waitAndUpdate } from 'sonar-ui-common/helpers/testUtils';
import { getSecurityHotspotDetails } from '../../../../api/security-hotspots';
import { mockComponent } from '../../../../helpers/testMocks';
import HotspotViewer from '../HotspotViewer';
+import HotspotViewerRenderer from '../HotspotViewerRenderer';
const hotspotKey = 'hotspot-key';
@@ -30,6 +33,8 @@ jest.mock('../../../../api/security-hotspots', () => ({
getSecurityHotspotDetails: jest.fn().mockResolvedValue({ id: `I am a detailled hotspot` })
}));
+jest.mock('sonar-ui-common/helpers/scrolling', () => ({ scrollToElement: jest.fn() }));
+
it('should render correctly', async () => {
const wrapper = shallowRender();
expect(wrapper).toMatchSnapshot();
@@ -46,6 +51,56 @@ it('should render correctly', async () => {
expect(getSecurityHotspotDetails).toHaveBeenCalledWith(newHotspotKey);
});
+it('should update refresh hotspot on update', () => {
+ const wrapper = shallowRender();
+ const mockGetHostpot = getSecurityHotspotDetails as jest.Mock;
+ mockGetHostpot.mockClear();
+ wrapper.find(HotspotViewerRenderer).simulate('updateHotspot');
+ expect(mockGetHostpot).toHaveBeenCalledTimes(1);
+});
+
+it('should open comment form when scroll to comment', () => {
+ const wrapper = shallowRender();
+ const mockTextRef = ({ current: { focus: jest.fn() } } as any) as React.RefObject<
+ HTMLTextAreaElement
+ >;
+ const mockParentRef = ({ current: {} } as any) as React.RefObject<HTMLDivElement>;
+ wrapper.instance().parentScrollRef = mockParentRef;
+ wrapper.instance().commentTextRef = mockTextRef;
+
+ wrapper.find(HotspotViewerRenderer).simulate('openComment');
+
+ expect(wrapper.state().commentVisible).toBe(true);
+ expect(mockTextRef.current?.focus).toHaveBeenCalled();
+ expect(scrollToElement).toHaveBeenCalledWith(mockTextRef.current, expect.anything());
+});
+
+it('should close comment', () => {
+ const wrapper = shallowRender();
+ wrapper.setState({ commentVisible: true });
+ wrapper.find(HotspotViewerRenderer).simulate('closeComment');
+ expect(wrapper.state().commentVisible).toBe(false);
+});
+
+it('should reset loading even on fetch error', async () => {
+ const mockGetHostpot = getSecurityHotspotDetails as jest.Mock;
+ mockGetHostpot.mockRejectedValueOnce({});
+
+ const wrapper = shallowRender();
+ await waitAndUpdate(wrapper);
+
+ expect(wrapper.state().loading).toBe(false);
+});
+
+it('should keep state on unmoint', () => {
+ const wrapper = shallowRender();
+ wrapper.instance().componentWillUnmount();
+ const prevState = clone(wrapper.state());
+
+ wrapper.find(HotspotViewerRenderer).simulate('updateHotspot');
+ expect(wrapper.state()).toStrictEqual(prevState);
+});
+
function shallowRender(props?: Partial<HotspotViewer['props']>) {
return shallow<HotspotViewer>(
<HotspotViewer
diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/HotspotViewerRenderer-test.tsx b/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/HotspotViewerRenderer-test.tsx
index 5fb5a19fc4d..f9207838319 100644
--- a/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/HotspotViewerRenderer-test.tsx
+++ b/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/HotspotViewerRenderer-test.tsx
@@ -21,8 +21,10 @@ import { shallow } from 'enzyme';
import * as React from 'react';
import { mockBranch } from '../../../../helpers/mocks/branch-like';
import { mockHotspot } from '../../../../helpers/mocks/security-hotspots';
-import { mockComponent, mockUser } from '../../../../helpers/testMocks';
-import HotspotViewerRenderer, { HotspotViewerRendererProps } from '../HotspotViewerRenderer';
+import { mockComponent, mockCurrentUser, mockUser } from '../../../../helpers/testMocks';
+import { HotspotViewerRenderer, HotspotViewerRendererProps } from '../HotspotViewerRenderer';
+
+jest.mock('../../../../helpers/users', () => ({ isLoggedIn: jest.fn(() => true) }));
it('should render correctly', () => {
const wrapper = shallowRender();
@@ -49,9 +51,15 @@ function shallowRender(props?: Partial<HotspotViewerRendererProps>) {
<HotspotViewerRenderer
branchLike={mockBranch()}
component={mockComponent()}
+ commentTextRef={React.createRef()}
+ commentVisible={false}
+ currentUser={mockCurrentUser()}
hotspot={mockHotspot()}
loading={false}
+ onCloseComment={jest.fn()}
+ onOpenComment={jest.fn()}
onUpdateHotspot={jest.fn()}
+ parentScrollRef={React.createRef()}
securityCategories={{ 'sql-injection': { title: 'SQL injection' } }}
{...props}
/>
diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/HotspotViewerReviewHistoryTab-test.tsx b/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/HotspotViewerReviewHistoryTab-test.tsx
deleted file mode 100644
index 48e790c2e44..00000000000
--- a/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/HotspotViewerReviewHistoryTab-test.tsx
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 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 { shallow } from 'enzyme';
-import * as React from 'react';
-import {
- mockHotspot,
- mockHotspotReviewHistoryElement
-} from '../../../../helpers/mocks/security-hotspots';
-import { mockUser } from '../../../../helpers/testMocks';
-import { ReviewHistoryType } from '../../../../types/security-hotspots';
-import HotspotViewerReviewHistoryTab, {
- HotspotViewerReviewHistoryTabProps
-} from '../HotspotViewerReviewHistoryTab';
-import HotspotViewerReviewHistoryTabCommentBox from '../HotspotViewerReviewHistoryTabCommentBox';
-
-it('should render correctly', () => {
- const wrapper = shallowRender();
- expect(wrapper).toMatchSnapshot();
-});
-
-it('should propagate onHotspotUpdate correctly', () => {
- const onUpdateHotspot = jest.fn();
- const wrapper = shallowRender({ onUpdateHotspot });
-
- wrapper
- .find(HotspotViewerReviewHistoryTabCommentBox)
- .props()
- .onUpdateHotspot();
- expect(onUpdateHotspot).toHaveBeenCalled();
-});
-
-function shallowRender(props?: Partial<HotspotViewerReviewHistoryTabProps>) {
- return shallow<HotspotViewerReviewHistoryTabProps>(
- <HotspotViewerReviewHistoryTab
- history={[
- mockHotspotReviewHistoryElement({ user: mockUser({ avatar: 'with-avatar' }) }),
- mockHotspotReviewHistoryElement({ user: mockUser({ active: false }) }),
- mockHotspotReviewHistoryElement({ user: mockUser({ login: undefined, name: undefined }) }),
- mockHotspotReviewHistoryElement({
- type: ReviewHistoryType.Diff,
- diffs: [
- { key: 'test', oldValue: 'old', newValue: 'new' },
- { key: 'test-1', oldValue: 'old-1', newValue: 'new-1' }
- ]
- }),
- mockHotspotReviewHistoryElement({
- type: ReviewHistoryType.Comment,
- html: '<strong>bold text</strong>'
- })
- ]}
- hotspot={mockHotspot()}
- onUpdateHotspot={jest.fn()}
- {...props}
- />
- );
-}
diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/HotspotViewerReviewHistoryTabCommentBox-test.tsx b/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/HotspotViewerReviewHistoryTabCommentBox-test.tsx
deleted file mode 100644
index febd2a6a017..00000000000
--- a/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/HotspotViewerReviewHistoryTabCommentBox-test.tsx
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 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 { shallow } from 'enzyme';
-import * as React from 'react';
-import { waitAndUpdate } from 'sonar-ui-common/helpers/testUtils';
-import { commentSecurityHotspot } from '../../../../api/security-hotspots';
-import { mockHotspot } from '../../../../helpers/mocks/security-hotspots';
-import HotspotViewerReviewHistoryTabCommentBox, {
- HotspotViewerReviewHistoryTabCommentBoxProps
-} from '../HotspotViewerReviewHistoryTabCommentBox';
-
-jest.mock('../../../../api/security-hotspots', () => ({
- commentSecurityHotspot: jest.fn().mockResolvedValue(null)
-}));
-
-it('should render correctly', () => {
- const wrapper = shallowRender();
- expect(wrapper).toMatchSnapshot();
-
- // Show the comment box
- wrapper.find('#hotspot-comment-box-display').simulate('click');
- expect(wrapper).toMatchSnapshot('with comment box');
-
- // Cancel comment
- wrapper.find('#hotspot-comment-box-cancel').simulate('click');
- expect(wrapper).toMatchSnapshot('without comment box');
-});
-
-it('should properly submit a comment', async () => {
- const hotspot = mockHotspot();
- const onUpdateHotspot = jest.fn();
- const wrapper = shallowRender({ hotspot, onUpdateHotspot });
-
- wrapper.find('#hotspot-comment-box-display').simulate('click');
- wrapper.find('textarea').simulate('change', { target: { value: 'tata' } });
- wrapper.find('#hotspot-comment-box-submit').simulate('click');
-
- await waitAndUpdate(wrapper);
-
- expect(commentSecurityHotspot).toHaveBeenCalledWith(hotspot.key, 'tata');
- expect(onUpdateHotspot).toHaveBeenCalled();
-
- expect(wrapper).toMatchSnapshot('without comment box');
-});
-
-function shallowRender(props?: Partial<HotspotViewerReviewHistoryTabCommentBoxProps>) {
- return shallow<HotspotViewerReviewHistoryTabCommentBoxProps>(
- <HotspotViewerReviewHistoryTabCommentBox
- hotspot={mockHotspot()}
- onUpdateHotspot={jest.fn()}
- {...props}
- />
- );
-}
diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/HotspotViewerTabs-test.tsx b/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/HotspotViewerTabs-test.tsx
index 24a09807b6e..aae1722a0ef 100644
--- a/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/HotspotViewerTabs-test.tsx
+++ b/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/HotspotViewerTabs-test.tsx
@@ -22,7 +22,6 @@ import * as React from 'react';
import BoxedTabs from 'sonar-ui-common/components/controls/BoxedTabs';
import { mockHotspot, mockHotspotRule } from '../../../../helpers/mocks/security-hotspots';
import { mockUser } from '../../../../helpers/testMocks';
-import HotspotViewerReviewHistoryTab from '../HotspotViewerReviewHistoryTab';
import HotspotViewerTabs, { TabKeys } from '../HotspotViewerTabs';
it('should render correctly', () => {
@@ -37,9 +36,6 @@ it('should render correctly', () => {
onSelect(TabKeys.FixRecommendation);
expect(wrapper).toMatchSnapshot('fix');
- onSelect(TabKeys.ReviewHistory);
- expect(wrapper).toMatchSnapshot('review');
-
expect(
shallowRender({
hotspot: mockHotspot({
@@ -88,31 +84,16 @@ it('should filter empty tab', () => {
).toBe(count - 1);
});
-it('should propagate onHotspotUpdate correctly', () => {
- const onUpdateHotspot = jest.fn();
- const wrapper = shallowRender({ onUpdateHotspot });
- const onSelect = wrapper.find(BoxedTabs).prop('onSelect') as (tab: TabKeys) => void;
-
- onSelect(TabKeys.ReviewHistory);
- wrapper
- .find(HotspotViewerReviewHistoryTab)
- .props()
- .onUpdateHotspot();
- expect(onUpdateHotspot).toHaveBeenCalled();
-});
-
it('should select first tab on hotspot update', () => {
const wrapper = shallowRender();
const onSelect = wrapper.find(BoxedTabs).prop('onSelect') as (tab: TabKeys) => void;
- onSelect(TabKeys.ReviewHistory);
- expect(wrapper.state().currentTab.key).toBe(TabKeys.ReviewHistory);
+ onSelect(TabKeys.VulnerabilityDescription);
+ expect(wrapper.state().currentTab.key).toBe(TabKeys.VulnerabilityDescription);
wrapper.setProps({ hotspot: mockHotspot({ key: 'new_key' }) });
expect(wrapper.state().currentTab.key).toBe(TabKeys.RiskDescription);
});
function shallowRender(props?: Partial<HotspotViewerTabs['props']>) {
- return shallow<HotspotViewerTabs>(
- <HotspotViewerTabs hotspot={mockHotspot()} onUpdateHotspot={jest.fn()} {...props} />
- );
+ return shallow<HotspotViewerTabs>(<HotspotViewerTabs hotspot={mockHotspot()} {...props} />);
}
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
new file mode 100644
index 00000000000..395669fefb7
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/__snapshots__/HotspotReviewHistory-test.tsx.snap
@@ -0,0 +1,151 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should render correctly 1`] = `
+<Fragment>
+ <div
+ className="padded"
+ key="0"
+ >
+ <div
+ className="display-flex-center"
+ >
+ <Connect(Avatar)
+ className="little-spacer-right"
+ name="John Doe"
+ size={20}
+ />
+ <strong>
+ John Doe
+ </strong>
+ <span
+ className="little-spacer-left"
+ >
+ hotspots.review_history.created
+ </span>
+ <span
+ className="little-spacer-left little-spacer-right"
+ >
+ -
+ </span>
+ <DateTimeFormatter
+ date="2018-09-01"
+ />
+ </div>
+ </div>
+ <div
+ className="padded bordered-top"
+ key="1"
+ >
+ <div
+ className="display-flex-center"
+ >
+ <Connect(Avatar)
+ className="little-spacer-right"
+ name="John Doe"
+ size={20}
+ />
+ <strong>
+ John Doe
+ </strong>
+ <span
+ className="little-spacer-left"
+ >
+ hotspots.review_history.comment_added
+ </span>
+ <span
+ className="little-spacer-left little-spacer-right"
+ >
+ -
+ </span>
+ <DateTimeFormatter
+ date="2018-09-10"
+ />
+ </div>
+ <div
+ className="spacer-top markdown"
+ dangerouslySetInnerHTML={
+ Object {
+ "__html": "<strong>TEST</strong>",
+ }
+ }
+ />
+ </div>
+ <div
+ className="padded bordered-top"
+ key="2"
+ >
+ <div
+ className="display-flex-center"
+ >
+ <Connect(Avatar)
+ className="little-spacer-right"
+ name="John Doe"
+ size={20}
+ />
+ <strong>
+ John Doe
+ </strong>
+ <span
+ className="little-spacer-left"
+ >
+ hotspots.review_history.comment_added
+ </span>
+ <span
+ className="little-spacer-left little-spacer-right"
+ >
+ -
+ </span>
+ <DateTimeFormatter
+ date="2018-09-11"
+ />
+ </div>
+ <div
+ className="spacer-top markdown"
+ dangerouslySetInnerHTML={
+ Object {
+ "__html": "<strong>TEST</strong>",
+ }
+ }
+ />
+ </div>
+ <div
+ className="padded bordered-top"
+ key="3"
+ >
+ <div
+ className="display-flex-center"
+ >
+ <Connect(Avatar)
+ className="little-spacer-right"
+ name="me-name"
+ size={20}
+ />
+ <strong>
+ me-name
+ </strong>
+ <span
+ className="little-spacer-left little-spacer-right"
+ >
+ -
+ </span>
+ <DateTimeFormatter
+ date="2018-10-01"
+ />
+ </div>
+ <div
+ className="spacer-top"
+ >
+ <IssueChangelogDiff
+ diff={
+ Object {
+ "key": "assign",
+ "newValue": "me",
+ "oldValue": "him",
+ }
+ }
+ key="0"
+ />
+ </div>
+ </div>
+</Fragment>
+`;
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
new file mode 100644
index 00000000000..e71ea8d94c3
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/__snapshots__/HotspotReviewHistoryAndComments-test.tsx.snap
@@ -0,0 +1,277 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should render correctly 1`] = `
+<Fragment>
+ <h1>
+ hotspot.section.activity
+ </h1>
+ <div
+ className="padded"
+ >
+ <HotspotReviewHistory
+ hotspot={
+ Object {
+ "assignee": "assignee",
+ "assigneeUser": Object {
+ "active": true,
+ "local": true,
+ "login": "assignee",
+ "name": "John Doe",
+ },
+ "author": "author",
+ "authorUser": Object {
+ "active": true,
+ "local": true,
+ "login": "author",
+ "name": "John Doe",
+ },
+ "canChangeStatus": true,
+ "changelog": Array [],
+ "comment": Array [],
+ "component": Object {
+ "breadcrumbs": Array [],
+ "key": "my-project",
+ "name": "MyProject",
+ "organization": "foo",
+ "qualifier": "FIL",
+ "qualityGate": Object {
+ "isDefault": true,
+ "key": "30",
+ "name": "Sonar way",
+ },
+ "qualityProfiles": Array [
+ Object {
+ "deleted": false,
+ "key": "my-qp",
+ "language": "ts",
+ "name": "Sonar way",
+ },
+ ],
+ "tags": Array [],
+ },
+ "creationDate": "2013-05-13T17:55:41+0200",
+ "key": "01fc972e-2a3c-433e-bcae-0bd7f88f5123",
+ "line": 142,
+ "message": "'3' is a magic number.",
+ "project": Object {
+ "breadcrumbs": Array [],
+ "key": "my-project",
+ "name": "MyProject",
+ "organization": "foo",
+ "qualifier": "TRK",
+ "qualityGate": Object {
+ "isDefault": true,
+ "key": "30",
+ "name": "Sonar way",
+ },
+ "qualityProfiles": Array [
+ Object {
+ "deleted": false,
+ "key": "my-qp",
+ "language": "ts",
+ "name": "Sonar way",
+ },
+ ],
+ "tags": Array [],
+ },
+ "resolution": "FIXED",
+ "rule": Object {
+ "fixRecommendations": "<p>This a <strong>strong</strong> message about fixing !</p>",
+ "key": "squid:S2077",
+ "name": "That rule",
+ "riskDescription": "<p>This a <strong>strong</strong> message about risk !</p>",
+ "securityCategory": "sql-injection",
+ "vulnerabilityDescription": "<p>This a <strong>strong</strong> message about vulnerability !</p>",
+ "vulnerabilityProbability": "HIGH",
+ },
+ "status": "REVIEWED",
+ "textRange": Object {
+ "endLine": 142,
+ "endOffset": 83,
+ "startLine": 142,
+ "startOffset": 26,
+ },
+ "updateDate": "2013-05-13T17:55:42+0200",
+ "users": Array [
+ Object {
+ "active": true,
+ "local": true,
+ "login": "assignee",
+ "name": "John Doe",
+ },
+ Object {
+ "active": true,
+ "local": true,
+ "login": "author",
+ "name": "John Doe",
+ },
+ ],
+ }
+ }
+ />
+ <hr />
+ <div
+ className="big-spacer-top"
+ >
+ <Button
+ className=""
+ id="hotspot-comment-box-display"
+ onClick={[MockFunction]}
+ >
+ hotspots.comment.open
+ </Button>
+ <div
+ className="invisible"
+ >
+ <div
+ className="little-spacer-bottom"
+ >
+ hotspots.comment.field
+ </div>
+ <textarea
+ className="form-field fixed-width width-100 spacer-bottom"
+ onChange={[Function]}
+ rows={2}
+ value=""
+ />
+ <div
+ className="display-flex-space-between display-flex-center "
+ >
+ <MarkdownTips
+ className="huge-spacer-bottom"
+ />
+ <div>
+ <Button
+ className="huge-spacer-bottom"
+ id="hotspot-comment-box-submit"
+ onClick={[Function]}
+ >
+ hotspots.comment.submit
+ </Button>
+ <ResetButtonLink
+ className="spacer-left huge-spacer-bottom"
+ id="hotspot-comment-box-cancel"
+ onClick={[Function]}
+ >
+ cancel
+ </ResetButtonLink>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+</Fragment>
+`;
+
+exports[`should render correctly without user 1`] = `
+<Fragment>
+ <h1>
+ hotspot.section.activity
+ </h1>
+ <div
+ className="padded"
+ >
+ <HotspotReviewHistory
+ hotspot={
+ Object {
+ "assignee": "assignee",
+ "assigneeUser": Object {
+ "active": true,
+ "local": true,
+ "login": "assignee",
+ "name": "John Doe",
+ },
+ "author": "author",
+ "authorUser": Object {
+ "active": true,
+ "local": true,
+ "login": "author",
+ "name": "John Doe",
+ },
+ "canChangeStatus": true,
+ "changelog": Array [],
+ "comment": Array [],
+ "component": Object {
+ "breadcrumbs": Array [],
+ "key": "my-project",
+ "name": "MyProject",
+ "organization": "foo",
+ "qualifier": "FIL",
+ "qualityGate": Object {
+ "isDefault": true,
+ "key": "30",
+ "name": "Sonar way",
+ },
+ "qualityProfiles": Array [
+ Object {
+ "deleted": false,
+ "key": "my-qp",
+ "language": "ts",
+ "name": "Sonar way",
+ },
+ ],
+ "tags": Array [],
+ },
+ "creationDate": "2013-05-13T17:55:41+0200",
+ "key": "01fc972e-2a3c-433e-bcae-0bd7f88f5123",
+ "line": 142,
+ "message": "'3' is a magic number.",
+ "project": Object {
+ "breadcrumbs": Array [],
+ "key": "my-project",
+ "name": "MyProject",
+ "organization": "foo",
+ "qualifier": "TRK",
+ "qualityGate": Object {
+ "isDefault": true,
+ "key": "30",
+ "name": "Sonar way",
+ },
+ "qualityProfiles": Array [
+ Object {
+ "deleted": false,
+ "key": "my-qp",
+ "language": "ts",
+ "name": "Sonar way",
+ },
+ ],
+ "tags": Array [],
+ },
+ "resolution": "FIXED",
+ "rule": Object {
+ "fixRecommendations": "<p>This a <strong>strong</strong> message about fixing !</p>",
+ "key": "squid:S2077",
+ "name": "That rule",
+ "riskDescription": "<p>This a <strong>strong</strong> message about risk !</p>",
+ "securityCategory": "sql-injection",
+ "vulnerabilityDescription": "<p>This a <strong>strong</strong> message about vulnerability !</p>",
+ "vulnerabilityProbability": "HIGH",
+ },
+ "status": "REVIEWED",
+ "textRange": Object {
+ "endLine": 142,
+ "endOffset": 83,
+ "startLine": 142,
+ "startOffset": 26,
+ },
+ "updateDate": "2013-05-13T17:55:42+0200",
+ "users": Array [
+ Object {
+ "active": true,
+ "local": true,
+ "login": "assignee",
+ "name": "John Doe",
+ },
+ Object {
+ "active": true,
+ "local": true,
+ "login": "author",
+ "name": "John Doe",
+ },
+ ],
+ }
+ }
+ />
+ </div>
+</Fragment>
+`;
diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/__snapshots__/HotspotViewer-test.tsx.snap b/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/__snapshots__/HotspotViewer-test.tsx.snap
index 5168e89398f..40d870f0e77 100644
--- a/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/__snapshots__/HotspotViewer-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/__snapshots__/HotspotViewer-test.tsx.snap
@@ -1,7 +1,13 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`should render correctly 1`] = `
-<HotspotViewerRenderer
+<Connect(withCurrentUser(HotspotViewerRenderer))
+ commentTextRef={
+ Object {
+ "current": null,
+ }
+ }
+ commentVisible={false}
component={
Object {
"breadcrumbs": Array [],
@@ -26,7 +32,14 @@ exports[`should render correctly 1`] = `
}
}
loading={true}
+ onCloseComment={[Function]}
+ onOpenComment={[Function]}
onUpdateHotspot={[Function]}
+ parentScrollRef={
+ Object {
+ "current": null,
+ }
+ }
securityCategories={
Object {
"cat1": Object {
@@ -38,7 +51,13 @@ exports[`should render correctly 1`] = `
`;
exports[`should render correctly 2`] = `
-<HotspotViewerRenderer
+<Connect(withCurrentUser(HotspotViewerRenderer))
+ commentTextRef={
+ Object {
+ "current": null,
+ }
+ }
+ commentVisible={false}
component={
Object {
"breadcrumbs": Array [],
@@ -68,7 +87,14 @@ exports[`should render correctly 2`] = `
}
}
loading={false}
+ onCloseComment={[Function]}
+ onOpenComment={[Function]}
onUpdateHotspot={[Function]}
+ parentScrollRef={
+ Object {
+ "current": null,
+ }
+ }
securityCategories={
Object {
"cat1": Object {
diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/__snapshots__/HotspotViewerRenderer-test.tsx.snap b/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/__snapshots__/HotspotViewerRenderer-test.tsx.snap
index 7ab41bd333d..cf361d6a27f 100644
--- a/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/__snapshots__/HotspotViewerRenderer-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/__snapshots__/HotspotViewerRenderer-test.tsx.snap
@@ -6,7 +6,7 @@ exports[`should render correctly 1`] = `
timeout={100}
>
<div
- className="big-padded"
+ className="big-padded hotspot-content"
>
<div
className="huge-spacer-bottom display-flex-space-between"
@@ -16,16 +16,30 @@ exports[`should render correctly 1`] = `
>
'3' is a magic number.
</strong>
- <ClipboardButton
- copyValue="http://localhost/security_hotspots?id=my-project&branch=branch-6.7&hotspots=01fc972e-2a3c-433e-bcae-0bd7f88f5123"
+ <div
+ className="display-flex-row flex-0"
>
- <LinkIcon
- className="spacer-right"
- />
- <span>
- hotspots.get_permalink
- </span>
- </ClipboardButton>
+ <div
+ className="dropdown spacer-right flex-1-0-auto"
+ >
+ <Button
+ onClick={[MockFunction]}
+ >
+ hotspots.comment.open
+ </Button>
+ </div>
+ <ClipboardButton
+ className="flex-1-0-auto"
+ copyValue="http://localhost/security_hotspots?id=my-project&branch=branch-6.7&hotspots=01fc972e-2a3c-433e-bcae-0bd7f88f5123"
+ >
+ <LinkIcon
+ className="spacer-right"
+ />
+ <span>
+ hotspots.get_permalink
+ </span>
+ </ClipboardButton>
+ </div>
</div>
<div
className="huge-spacer-bottom display-flex-row"
@@ -491,7 +505,121 @@ exports[`should render correctly 1`] = `
],
}
}
- onUpdateHotspot={[MockFunction]}
+ />
+ <HotspotReviewHistoryAndComments
+ commentTextRef={
+ Object {
+ "current": null,
+ }
+ }
+ commentVisible={false}
+ currentUser={
+ Object {
+ "isLoggedIn": false,
+ }
+ }
+ hotspot={
+ Object {
+ "assignee": "assignee",
+ "assigneeUser": Object {
+ "active": true,
+ "local": true,
+ "login": "assignee",
+ "name": "John Doe",
+ },
+ "author": "author",
+ "authorUser": Object {
+ "active": true,
+ "local": true,
+ "login": "author",
+ "name": "John Doe",
+ },
+ "canChangeStatus": true,
+ "changelog": Array [],
+ "comment": Array [],
+ "component": Object {
+ "breadcrumbs": Array [],
+ "key": "my-project",
+ "name": "MyProject",
+ "organization": "foo",
+ "qualifier": "FIL",
+ "qualityGate": Object {
+ "isDefault": true,
+ "key": "30",
+ "name": "Sonar way",
+ },
+ "qualityProfiles": Array [
+ Object {
+ "deleted": false,
+ "key": "my-qp",
+ "language": "ts",
+ "name": "Sonar way",
+ },
+ ],
+ "tags": Array [],
+ },
+ "creationDate": "2013-05-13T17:55:41+0200",
+ "key": "01fc972e-2a3c-433e-bcae-0bd7f88f5123",
+ "line": 142,
+ "message": "'3' is a magic number.",
+ "project": Object {
+ "breadcrumbs": Array [],
+ "key": "my-project",
+ "name": "MyProject",
+ "organization": "foo",
+ "qualifier": "TRK",
+ "qualityGate": Object {
+ "isDefault": true,
+ "key": "30",
+ "name": "Sonar way",
+ },
+ "qualityProfiles": Array [
+ Object {
+ "deleted": false,
+ "key": "my-qp",
+ "language": "ts",
+ "name": "Sonar way",
+ },
+ ],
+ "tags": Array [],
+ },
+ "resolution": "FIXED",
+ "rule": Object {
+ "fixRecommendations": "<p>This a <strong>strong</strong> message about fixing !</p>",
+ "key": "squid:S2077",
+ "name": "That rule",
+ "riskDescription": "<p>This a <strong>strong</strong> message about risk !</p>",
+ "securityCategory": "sql-injection",
+ "vulnerabilityDescription": "<p>This a <strong>strong</strong> message about vulnerability !</p>",
+ "vulnerabilityProbability": "HIGH",
+ },
+ "status": "REVIEWED",
+ "textRange": Object {
+ "endLine": 142,
+ "endOffset": 83,
+ "startLine": 142,
+ "startOffset": 26,
+ },
+ "updateDate": "2013-05-13T17:55:42+0200",
+ "users": Array [
+ Object {
+ "active": true,
+ "local": true,
+ "login": "assignee",
+ "name": "John Doe",
+ },
+ Object {
+ "active": true,
+ "local": true,
+ "login": "author",
+ "name": "John Doe",
+ },
+ ],
+ }
+ }
+ onCloseComment={[MockFunction]}
+ onCommentUpdate={[MockFunction]}
+ onOpenComment={[MockFunction]}
/>
</div>
</DeferredSpinner>
@@ -503,7 +631,7 @@ exports[`should render correctly: anonymous user 1`] = `
timeout={100}
>
<div
- className="big-padded"
+ className="big-padded hotspot-content"
>
<div
className="huge-spacer-bottom display-flex-space-between"
@@ -513,16 +641,30 @@ exports[`should render correctly: anonymous user 1`] = `
>
'3' is a magic number.
</strong>
- <ClipboardButton
- copyValue="http://localhost/security_hotspots?id=my-project&branch=branch-6.7&hotspots=01fc972e-2a3c-433e-bcae-0bd7f88f5123"
+ <div
+ className="display-flex-row flex-0"
>
- <LinkIcon
- className="spacer-right"
- />
- <span>
- hotspots.get_permalink
- </span>
- </ClipboardButton>
+ <div
+ className="dropdown spacer-right flex-1-0-auto"
+ >
+ <Button
+ onClick={[MockFunction]}
+ >
+ hotspots.comment.open
+ </Button>
+ </div>
+ <ClipboardButton
+ className="flex-1-0-auto"
+ copyValue="http://localhost/security_hotspots?id=my-project&branch=branch-6.7&hotspots=01fc972e-2a3c-433e-bcae-0bd7f88f5123"
+ >
+ <LinkIcon
+ className="spacer-right"
+ />
+ <span>
+ hotspots.get_permalink
+ </span>
+ </ClipboardButton>
+ </div>
</div>
<div
className="huge-spacer-bottom display-flex-row"
@@ -988,7 +1130,121 @@ exports[`should render correctly: anonymous user 1`] = `
],
}
}
- onUpdateHotspot={[MockFunction]}
+ />
+ <HotspotReviewHistoryAndComments
+ commentTextRef={
+ Object {
+ "current": null,
+ }
+ }
+ commentVisible={false}
+ currentUser={
+ Object {
+ "isLoggedIn": false,
+ }
+ }
+ hotspot={
+ Object {
+ "assignee": "assignee",
+ "assigneeUser": Object {
+ "active": true,
+ "local": true,
+ "login": "assignee",
+ "name": "John Doe",
+ },
+ "author": "author",
+ "authorUser": Object {
+ "active": true,
+ "local": true,
+ "login": "author",
+ "name": "John Doe",
+ },
+ "canChangeStatus": true,
+ "changelog": Array [],
+ "comment": Array [],
+ "component": Object {
+ "breadcrumbs": Array [],
+ "key": "my-project",
+ "name": "MyProject",
+ "organization": "foo",
+ "qualifier": "FIL",
+ "qualityGate": Object {
+ "isDefault": true,
+ "key": "30",
+ "name": "Sonar way",
+ },
+ "qualityProfiles": Array [
+ Object {
+ "deleted": false,
+ "key": "my-qp",
+ "language": "ts",
+ "name": "Sonar way",
+ },
+ ],
+ "tags": Array [],
+ },
+ "creationDate": "2013-05-13T17:55:41+0200",
+ "key": "01fc972e-2a3c-433e-bcae-0bd7f88f5123",
+ "line": 142,
+ "message": "'3' is a magic number.",
+ "project": Object {
+ "breadcrumbs": Array [],
+ "key": "my-project",
+ "name": "MyProject",
+ "organization": "foo",
+ "qualifier": "TRK",
+ "qualityGate": Object {
+ "isDefault": true,
+ "key": "30",
+ "name": "Sonar way",
+ },
+ "qualityProfiles": Array [
+ Object {
+ "deleted": false,
+ "key": "my-qp",
+ "language": "ts",
+ "name": "Sonar way",
+ },
+ ],
+ "tags": Array [],
+ },
+ "resolution": "FIXED",
+ "rule": Object {
+ "fixRecommendations": "<p>This a <strong>strong</strong> message about fixing !</p>",
+ "key": "squid:S2077",
+ "name": "That rule",
+ "riskDescription": "<p>This a <strong>strong</strong> message about risk !</p>",
+ "securityCategory": "sql-injection",
+ "vulnerabilityDescription": "<p>This a <strong>strong</strong> message about vulnerability !</p>",
+ "vulnerabilityProbability": "HIGH",
+ },
+ "status": "REVIEWED",
+ "textRange": Object {
+ "endLine": 142,
+ "endOffset": 83,
+ "startLine": 142,
+ "startOffset": 26,
+ },
+ "updateDate": "2013-05-13T17:55:42+0200",
+ "users": Array [
+ Object {
+ "active": true,
+ "local": true,
+ "login": "assignee",
+ "name": "John Doe",
+ },
+ Object {
+ "active": true,
+ "local": true,
+ "login": "author",
+ "name": "John Doe",
+ },
+ ],
+ }
+ }
+ onCloseComment={[MockFunction]}
+ onCommentUpdate={[MockFunction]}
+ onOpenComment={[MockFunction]}
/>
</div>
</DeferredSpinner>
@@ -1000,7 +1256,7 @@ exports[`should render correctly: assignee without name 1`] = `
timeout={100}
>
<div
- className="big-padded"
+ className="big-padded hotspot-content"
>
<div
className="huge-spacer-bottom display-flex-space-between"
@@ -1010,16 +1266,30 @@ exports[`should render correctly: assignee without name 1`] = `
>
'3' is a magic number.
</strong>
- <ClipboardButton
- copyValue="http://localhost/security_hotspots?id=my-project&branch=branch-6.7&hotspots=01fc972e-2a3c-433e-bcae-0bd7f88f5123"
+ <div
+ className="display-flex-row flex-0"
>
- <LinkIcon
- className="spacer-right"
- />
- <span>
- hotspots.get_permalink
- </span>
- </ClipboardButton>
+ <div
+ className="dropdown spacer-right flex-1-0-auto"
+ >
+ <Button
+ onClick={[MockFunction]}
+ >
+ hotspots.comment.open
+ </Button>
+ </div>
+ <ClipboardButton
+ className="flex-1-0-auto"
+ copyValue="http://localhost/security_hotspots?id=my-project&branch=branch-6.7&hotspots=01fc972e-2a3c-433e-bcae-0bd7f88f5123"
+ >
+ <LinkIcon
+ className="spacer-right"
+ />
+ <span>
+ hotspots.get_permalink
+ </span>
+ </ClipboardButton>
+ </div>
</div>
<div
className="huge-spacer-bottom display-flex-row"
@@ -1485,7 +1755,121 @@ exports[`should render correctly: assignee without name 1`] = `
],
}
}
- onUpdateHotspot={[MockFunction]}
+ />
+ <HotspotReviewHistoryAndComments
+ commentTextRef={
+ Object {
+ "current": null,
+ }
+ }
+ commentVisible={false}
+ currentUser={
+ Object {
+ "isLoggedIn": false,
+ }
+ }
+ hotspot={
+ Object {
+ "assignee": "assignee",
+ "assigneeUser": Object {
+ "active": true,
+ "local": true,
+ "login": "assignee_login",
+ "name": undefined,
+ },
+ "author": "author",
+ "authorUser": Object {
+ "active": true,
+ "local": true,
+ "login": "author",
+ "name": "John Doe",
+ },
+ "canChangeStatus": true,
+ "changelog": Array [],
+ "comment": Array [],
+ "component": Object {
+ "breadcrumbs": Array [],
+ "key": "my-project",
+ "name": "MyProject",
+ "organization": "foo",
+ "qualifier": "FIL",
+ "qualityGate": Object {
+ "isDefault": true,
+ "key": "30",
+ "name": "Sonar way",
+ },
+ "qualityProfiles": Array [
+ Object {
+ "deleted": false,
+ "key": "my-qp",
+ "language": "ts",
+ "name": "Sonar way",
+ },
+ ],
+ "tags": Array [],
+ },
+ "creationDate": "2013-05-13T17:55:41+0200",
+ "key": "01fc972e-2a3c-433e-bcae-0bd7f88f5123",
+ "line": 142,
+ "message": "'3' is a magic number.",
+ "project": Object {
+ "breadcrumbs": Array [],
+ "key": "my-project",
+ "name": "MyProject",
+ "organization": "foo",
+ "qualifier": "TRK",
+ "qualityGate": Object {
+ "isDefault": true,
+ "key": "30",
+ "name": "Sonar way",
+ },
+ "qualityProfiles": Array [
+ Object {
+ "deleted": false,
+ "key": "my-qp",
+ "language": "ts",
+ "name": "Sonar way",
+ },
+ ],
+ "tags": Array [],
+ },
+ "resolution": "FIXED",
+ "rule": Object {
+ "fixRecommendations": "<p>This a <strong>strong</strong> message about fixing !</p>",
+ "key": "squid:S2077",
+ "name": "That rule",
+ "riskDescription": "<p>This a <strong>strong</strong> message about risk !</p>",
+ "securityCategory": "sql-injection",
+ "vulnerabilityDescription": "<p>This a <strong>strong</strong> message about vulnerability !</p>",
+ "vulnerabilityProbability": "HIGH",
+ },
+ "status": "REVIEWED",
+ "textRange": Object {
+ "endLine": 142,
+ "endOffset": 83,
+ "startLine": 142,
+ "startOffset": 26,
+ },
+ "updateDate": "2013-05-13T17:55:42+0200",
+ "users": Array [
+ Object {
+ "active": true,
+ "local": true,
+ "login": "assignee",
+ "name": "John Doe",
+ },
+ Object {
+ "active": true,
+ "local": true,
+ "login": "author",
+ "name": "John Doe",
+ },
+ ],
+ }
+ }
+ onCloseComment={[MockFunction]}
+ onCommentUpdate={[MockFunction]}
+ onOpenComment={[MockFunction]}
/>
</div>
</DeferredSpinner>
@@ -1497,7 +1881,7 @@ exports[`should render correctly: deleted assignee 1`] = `
timeout={100}
>
<div
- className="big-padded"
+ className="big-padded hotspot-content"
>
<div
className="huge-spacer-bottom display-flex-space-between"
@@ -1507,16 +1891,30 @@ exports[`should render correctly: deleted assignee 1`] = `
>
'3' is a magic number.
</strong>
- <ClipboardButton
- copyValue="http://localhost/security_hotspots?id=my-project&branch=branch-6.7&hotspots=01fc972e-2a3c-433e-bcae-0bd7f88f5123"
+ <div
+ className="display-flex-row flex-0"
>
- <LinkIcon
- className="spacer-right"
- />
- <span>
- hotspots.get_permalink
- </span>
- </ClipboardButton>
+ <div
+ className="dropdown spacer-right flex-1-0-auto"
+ >
+ <Button
+ onClick={[MockFunction]}
+ >
+ hotspots.comment.open
+ </Button>
+ </div>
+ <ClipboardButton
+ className="flex-1-0-auto"
+ copyValue="http://localhost/security_hotspots?id=my-project&branch=branch-6.7&hotspots=01fc972e-2a3c-433e-bcae-0bd7f88f5123"
+ >
+ <LinkIcon
+ className="spacer-right"
+ />
+ <span>
+ hotspots.get_permalink
+ </span>
+ </ClipboardButton>
+ </div>
</div>
<div
className="huge-spacer-bottom display-flex-row"
@@ -1982,7 +2380,121 @@ exports[`should render correctly: deleted assignee 1`] = `
],
}
}
- onUpdateHotspot={[MockFunction]}
+ />
+ <HotspotReviewHistoryAndComments
+ commentTextRef={
+ Object {
+ "current": null,
+ }
+ }
+ commentVisible={false}
+ currentUser={
+ Object {
+ "isLoggedIn": false,
+ }
+ }
+ hotspot={
+ Object {
+ "assignee": "assignee",
+ "assigneeUser": Object {
+ "active": false,
+ "local": true,
+ "login": "john.doe",
+ "name": "John Doe",
+ },
+ "author": "author",
+ "authorUser": Object {
+ "active": true,
+ "local": true,
+ "login": "author",
+ "name": "John Doe",
+ },
+ "canChangeStatus": true,
+ "changelog": Array [],
+ "comment": Array [],
+ "component": Object {
+ "breadcrumbs": Array [],
+ "key": "my-project",
+ "name": "MyProject",
+ "organization": "foo",
+ "qualifier": "FIL",
+ "qualityGate": Object {
+ "isDefault": true,
+ "key": "30",
+ "name": "Sonar way",
+ },
+ "qualityProfiles": Array [
+ Object {
+ "deleted": false,
+ "key": "my-qp",
+ "language": "ts",
+ "name": "Sonar way",
+ },
+ ],
+ "tags": Array [],
+ },
+ "creationDate": "2013-05-13T17:55:41+0200",
+ "key": "01fc972e-2a3c-433e-bcae-0bd7f88f5123",
+ "line": 142,
+ "message": "'3' is a magic number.",
+ "project": Object {
+ "breadcrumbs": Array [],
+ "key": "my-project",
+ "name": "MyProject",
+ "organization": "foo",
+ "qualifier": "TRK",
+ "qualityGate": Object {
+ "isDefault": true,
+ "key": "30",
+ "name": "Sonar way",
+ },
+ "qualityProfiles": Array [
+ Object {
+ "deleted": false,
+ "key": "my-qp",
+ "language": "ts",
+ "name": "Sonar way",
+ },
+ ],
+ "tags": Array [],
+ },
+ "resolution": "FIXED",
+ "rule": Object {
+ "fixRecommendations": "<p>This a <strong>strong</strong> message about fixing !</p>",
+ "key": "squid:S2077",
+ "name": "That rule",
+ "riskDescription": "<p>This a <strong>strong</strong> message about risk !</p>",
+ "securityCategory": "sql-injection",
+ "vulnerabilityDescription": "<p>This a <strong>strong</strong> message about vulnerability !</p>",
+ "vulnerabilityProbability": "HIGH",
+ },
+ "status": "REVIEWED",
+ "textRange": Object {
+ "endLine": 142,
+ "endOffset": 83,
+ "startLine": 142,
+ "startOffset": 26,
+ },
+ "updateDate": "2013-05-13T17:55:42+0200",
+ "users": Array [
+ Object {
+ "active": true,
+ "local": true,
+ "login": "assignee",
+ "name": "John Doe",
+ },
+ Object {
+ "active": true,
+ "local": true,
+ "login": "author",
+ "name": "John Doe",
+ },
+ ],
+ }
+ }
+ onCloseComment={[MockFunction]}
+ onCommentUpdate={[MockFunction]}
+ onOpenComment={[MockFunction]}
/>
</div>
</DeferredSpinner>
@@ -2001,7 +2513,7 @@ exports[`should render correctly: unassigned 1`] = `
timeout={100}
>
<div
- className="big-padded"
+ className="big-padded hotspot-content"
>
<div
className="huge-spacer-bottom display-flex-space-between"
@@ -2011,16 +2523,30 @@ exports[`should render correctly: unassigned 1`] = `
>
'3' is a magic number.
</strong>
- <ClipboardButton
- copyValue="http://localhost/security_hotspots?id=my-project&branch=branch-6.7&hotspots=01fc972e-2a3c-433e-bcae-0bd7f88f5123"
+ <div
+ className="display-flex-row flex-0"
>
- <LinkIcon
- className="spacer-right"
- />
- <span>
- hotspots.get_permalink
- </span>
- </ClipboardButton>
+ <div
+ className="dropdown spacer-right flex-1-0-auto"
+ >
+ <Button
+ onClick={[MockFunction]}
+ >
+ hotspots.comment.open
+ </Button>
+ </div>
+ <ClipboardButton
+ className="flex-1-0-auto"
+ copyValue="http://localhost/security_hotspots?id=my-project&branch=branch-6.7&hotspots=01fc972e-2a3c-433e-bcae-0bd7f88f5123"
+ >
+ <LinkIcon
+ className="spacer-right"
+ />
+ <span>
+ hotspots.get_permalink
+ </span>
+ </ClipboardButton>
+ </div>
</div>
<div
className="huge-spacer-bottom display-flex-row"
@@ -2486,7 +3012,121 @@ exports[`should render correctly: unassigned 1`] = `
],
}
}
- onUpdateHotspot={[MockFunction]}
+ />
+ <HotspotReviewHistoryAndComments
+ commentTextRef={
+ Object {
+ "current": null,
+ }
+ }
+ commentVisible={false}
+ currentUser={
+ Object {
+ "isLoggedIn": false,
+ }
+ }
+ hotspot={
+ Object {
+ "assignee": undefined,
+ "assigneeUser": Object {
+ "active": true,
+ "local": true,
+ "login": "assignee",
+ "name": "John Doe",
+ },
+ "author": "author",
+ "authorUser": Object {
+ "active": true,
+ "local": true,
+ "login": "author",
+ "name": "John Doe",
+ },
+ "canChangeStatus": true,
+ "changelog": Array [],
+ "comment": Array [],
+ "component": Object {
+ "breadcrumbs": Array [],
+ "key": "my-project",
+ "name": "MyProject",
+ "organization": "foo",
+ "qualifier": "FIL",
+ "qualityGate": Object {
+ "isDefault": true,
+ "key": "30",
+ "name": "Sonar way",
+ },
+ "qualityProfiles": Array [
+ Object {
+ "deleted": false,
+ "key": "my-qp",
+ "language": "ts",
+ "name": "Sonar way",
+ },
+ ],
+ "tags": Array [],
+ },
+ "creationDate": "2013-05-13T17:55:41+0200",
+ "key": "01fc972e-2a3c-433e-bcae-0bd7f88f5123",
+ "line": 142,
+ "message": "'3' is a magic number.",
+ "project": Object {
+ "breadcrumbs": Array [],
+ "key": "my-project",
+ "name": "MyProject",
+ "organization": "foo",
+ "qualifier": "TRK",
+ "qualityGate": Object {
+ "isDefault": true,
+ "key": "30",
+ "name": "Sonar way",
+ },
+ "qualityProfiles": Array [
+ Object {
+ "deleted": false,
+ "key": "my-qp",
+ "language": "ts",
+ "name": "Sonar way",
+ },
+ ],
+ "tags": Array [],
+ },
+ "resolution": "FIXED",
+ "rule": Object {
+ "fixRecommendations": "<p>This a <strong>strong</strong> message about fixing !</p>",
+ "key": "squid:S2077",
+ "name": "That rule",
+ "riskDescription": "<p>This a <strong>strong</strong> message about risk !</p>",
+ "securityCategory": "sql-injection",
+ "vulnerabilityDescription": "<p>This a <strong>strong</strong> message about vulnerability !</p>",
+ "vulnerabilityProbability": "HIGH",
+ },
+ "status": "REVIEWED",
+ "textRange": Object {
+ "endLine": 142,
+ "endOffset": 83,
+ "startLine": 142,
+ "startOffset": 26,
+ },
+ "updateDate": "2013-05-13T17:55:42+0200",
+ "users": Array [
+ Object {
+ "active": true,
+ "local": true,
+ "login": "assignee",
+ "name": "John Doe",
+ },
+ Object {
+ "active": true,
+ "local": true,
+ "login": "author",
+ "name": "John Doe",
+ },
+ ],
+ }
+ }
+ onCloseComment={[MockFunction]}
+ onCommentUpdate={[MockFunction]}
+ onOpenComment={[MockFunction]}
/>
</div>
</DeferredSpinner>
diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/__snapshots__/HotspotViewerReviewHistoryTab-test.tsx.snap b/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/__snapshots__/HotspotViewerReviewHistoryTab-test.tsx.snap
deleted file mode 100644
index 3aee5ee3160..00000000000
--- a/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/__snapshots__/HotspotViewerReviewHistoryTab-test.tsx.snap
+++ /dev/null
@@ -1,270 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render correctly 1`] = `
-<div
- className="padded"
->
- <div
- className="padded"
- >
- <div
- className="display-flex-center"
- >
- <Connect(Avatar)
- className="little-spacer-right"
- hash="with-avatar"
- name="John Doe"
- size={20}
- />
- <strong>
- John Doe
- </strong>
- <span
- className="little-spacer-left"
- >
- hotspots.tabs.review_history.created
- </span>
- <span
- className="little-spacer-left little-spacer-right"
- >
- -
- </span>
- <DateTimeFormatter
- date="2019-09-13T17:55:42+0200"
- />
- </div>
- </div>
- <hr />
- <div
- className="padded"
- >
- <div
- className="display-flex-center"
- >
- <Connect(Avatar)
- className="little-spacer-right"
- name="John Doe"
- size={20}
- />
- <strong>
- user.x_deleted.John Doe
- </strong>
- <span
- className="little-spacer-left"
- >
- hotspots.tabs.review_history.created
- </span>
- <span
- className="little-spacer-left little-spacer-right"
- >
- -
- </span>
- <DateTimeFormatter
- date="2019-09-13T17:55:42+0200"
- />
- </div>
- </div>
- <hr />
- <div
- className="padded"
- >
- <div
- className="display-flex-center"
- >
- <DateTimeFormatter
- date="2019-09-13T17:55:42+0200"
- />
- </div>
- </div>
- <hr />
- <div
- className="padded"
- >
- <div
- className="display-flex-center"
- >
- <Connect(Avatar)
- className="little-spacer-right"
- name="John Doe"
- size={20}
- />
- <strong>
- John Doe
- </strong>
- <span
- className="little-spacer-left little-spacer-right"
- >
- -
- </span>
- <DateTimeFormatter
- date="2019-09-13T17:55:42+0200"
- />
- </div>
- <div
- className="spacer-top"
- >
- <IssueChangelogDiff
- diff={
- Object {
- "key": "test",
- "newValue": "new",
- "oldValue": "old",
- }
- }
- key="0"
- />
- <IssueChangelogDiff
- diff={
- Object {
- "key": "test-1",
- "newValue": "new-1",
- "oldValue": "old-1",
- }
- }
- key="1"
- />
- </div>
- </div>
- <hr />
- <div
- className="padded"
- >
- <div
- className="display-flex-center"
- >
- <Connect(Avatar)
- className="little-spacer-right"
- name="John Doe"
- size={20}
- />
- <strong>
- John Doe
- </strong>
- <span
- className="little-spacer-left"
- >
- hotspots.tabs.review_history.comment.added
- </span>
- <span
- className="little-spacer-left little-spacer-right"
- >
- -
- </span>
- <DateTimeFormatter
- date="2019-09-13T17:55:42+0200"
- />
- </div>
- <div
- className="spacer-top markdown"
- dangerouslySetInnerHTML={
- Object {
- "__html": "<strong>bold text</strong>",
- }
- }
- />
- </div>
- <hr />
- <HotspotViewerReviewHistoryTabCommentBox
- hotspot={
- Object {
- "assignee": "assignee",
- "assigneeUser": Object {
- "active": true,
- "local": true,
- "login": "assignee",
- "name": "John Doe",
- },
- "author": "author",
- "authorUser": Object {
- "active": true,
- "local": true,
- "login": "author",
- "name": "John Doe",
- },
- "canChangeStatus": true,
- "changelog": Array [],
- "comment": Array [],
- "component": Object {
- "breadcrumbs": Array [],
- "key": "my-project",
- "name": "MyProject",
- "organization": "foo",
- "qualifier": "FIL",
- "qualityGate": Object {
- "isDefault": true,
- "key": "30",
- "name": "Sonar way",
- },
- "qualityProfiles": Array [
- Object {
- "deleted": false,
- "key": "my-qp",
- "language": "ts",
- "name": "Sonar way",
- },
- ],
- "tags": Array [],
- },
- "creationDate": "2013-05-13T17:55:41+0200",
- "key": "01fc972e-2a3c-433e-bcae-0bd7f88f5123",
- "line": 142,
- "message": "'3' is a magic number.",
- "project": Object {
- "breadcrumbs": Array [],
- "key": "my-project",
- "name": "MyProject",
- "organization": "foo",
- "qualifier": "TRK",
- "qualityGate": Object {
- "isDefault": true,
- "key": "30",
- "name": "Sonar way",
- },
- "qualityProfiles": Array [
- Object {
- "deleted": false,
- "key": "my-qp",
- "language": "ts",
- "name": "Sonar way",
- },
- ],
- "tags": Array [],
- },
- "resolution": "FIXED",
- "rule": Object {
- "fixRecommendations": "<p>This a <strong>strong</strong> message about fixing !</p>",
- "key": "squid:S2077",
- "name": "That rule",
- "riskDescription": "<p>This a <strong>strong</strong> message about risk !</p>",
- "securityCategory": "sql-injection",
- "vulnerabilityDescription": "<p>This a <strong>strong</strong> message about vulnerability !</p>",
- "vulnerabilityProbability": "HIGH",
- },
- "status": "REVIEWED",
- "textRange": Object {
- "endLine": 142,
- "endOffset": 83,
- "startLine": 142,
- "startOffset": 26,
- },
- "updateDate": "2013-05-13T17:55:42+0200",
- "users": Array [
- Object {
- "active": true,
- "local": true,
- "login": "assignee",
- "name": "John Doe",
- },
- Object {
- "active": true,
- "local": true,
- "login": "author",
- "name": "John Doe",
- },
- ],
- }
- }
- onUpdateHotspot={[MockFunction]}
- />
-</div>
-`;
diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/__snapshots__/HotspotViewerReviewHistoryTabCommentBox-test.tsx.snap b/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/__snapshots__/HotspotViewerReviewHistoryTabCommentBox-test.tsx.snap
deleted file mode 100644
index 951a828e1b2..00000000000
--- a/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/__snapshots__/HotspotViewerReviewHistoryTabCommentBox-test.tsx.snap
+++ /dev/null
@@ -1,78 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should properly submit a comment: without comment box 1`] = `
-<div
- className="big-spacer-top"
->
- <Button
- id="hotspot-comment-box-display"
- onClick={[Function]}
- >
- hotspots.tabs.review_history.comment.add
- </Button>
-</div>
-`;
-
-exports[`should render correctly 1`] = `
-<div
- className="big-spacer-top"
->
- <Button
- id="hotspot-comment-box-display"
- onClick={[Function]}
- >
- hotspots.tabs.review_history.comment.add
- </Button>
-</div>
-`;
-
-exports[`should render correctly: with comment box 1`] = `
-<div
- className="big-spacer-top"
->
- <div
- className="little-spacer-bottom"
- >
- hotspots.tabs.review_history.comment.field
- </div>
- <textarea
- autoFocus={true}
- className="form-field fixed-width width-100 spacer-bottom"
- onChange={[Function]}
- rows={2}
- />
- <div
- className="display-flex-space-between display-flex-center"
- >
- <MarkdownTips />
- <div>
- <Button
- id="hotspot-comment-box-submit"
- onClick={[Function]}
- >
- hotspots.tabs.review_history.comment.submit
- </Button>
- <ResetButtonLink
- className="spacer-left"
- id="hotspot-comment-box-cancel"
- onClick={[Function]}
- >
- cancel
- </ResetButtonLink>
- </div>
- </div>
-</div>
-`;
-
-exports[`should render correctly: without comment box 1`] = `
-<div
- className="big-spacer-top"
->
- <Button
- id="hotspot-comment-box-display"
- onClick={[Function]}
- >
- hotspots.tabs.review_history.comment.add
- </Button>
-</div>
-`;
diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/__snapshots__/HotspotViewerTabs-test.tsx.snap b/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/__snapshots__/HotspotViewerTabs-test.tsx.snap
index 76d3667a4ff..e6aa9f51182 100644
--- a/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/__snapshots__/HotspotViewerTabs-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/__snapshots__/HotspotViewerTabs-test.tsx.snap
@@ -22,130 +22,6 @@ exports[`should render correctly: fix 1`] = `
"key": "fix",
"label": "hotspots.tabs.fix_recommendations",
},
- Object {
- "content": <HotspotViewerReviewHistoryTab
- history={
- Array [
- Object {
- "date": "2013-05-13T17:55:41+0200",
- "type": 0,
- "user": Object {
- "active": true,
- "local": true,
- "login": "author",
- "name": "John Doe",
- },
- },
- ]
- }
- hotspot={
- Object {
- "assignee": "assignee",
- "assigneeUser": Object {
- "active": true,
- "local": true,
- "login": "assignee",
- "name": "John Doe",
- },
- "author": "author",
- "authorUser": Object {
- "active": true,
- "local": true,
- "login": "author",
- "name": "John Doe",
- },
- "canChangeStatus": true,
- "changelog": Array [],
- "comment": Array [],
- "component": Object {
- "breadcrumbs": Array [],
- "key": "my-project",
- "name": "MyProject",
- "organization": "foo",
- "qualifier": "FIL",
- "qualityGate": Object {
- "isDefault": true,
- "key": "30",
- "name": "Sonar way",
- },
- "qualityProfiles": Array [
- Object {
- "deleted": false,
- "key": "my-qp",
- "language": "ts",
- "name": "Sonar way",
- },
- ],
- "tags": Array [],
- },
- "creationDate": "2013-05-13T17:55:41+0200",
- "key": "01fc972e-2a3c-433e-bcae-0bd7f88f5123",
- "line": 142,
- "message": "'3' is a magic number.",
- "project": Object {
- "breadcrumbs": Array [],
- "key": "my-project",
- "name": "MyProject",
- "organization": "foo",
- "qualifier": "TRK",
- "qualityGate": Object {
- "isDefault": true,
- "key": "30",
- "name": "Sonar way",
- },
- "qualityProfiles": Array [
- Object {
- "deleted": false,
- "key": "my-qp",
- "language": "ts",
- "name": "Sonar way",
- },
- ],
- "tags": Array [],
- },
- "resolution": "FIXED",
- "rule": Object {
- "fixRecommendations": "<p>This a <strong>strong</strong> message about fixing !</p>",
- "key": "squid:S2077",
- "name": "That rule",
- "riskDescription": "<p>This a <strong>strong</strong> message about risk !</p>",
- "securityCategory": "sql-injection",
- "vulnerabilityDescription": "<p>This a <strong>strong</strong> message about vulnerability !</p>",
- "vulnerabilityProbability": "HIGH",
- },
- "status": "REVIEWED",
- "textRange": Object {
- "endLine": 142,
- "endOffset": 83,
- "startLine": 142,
- "startOffset": 26,
- },
- "updateDate": "2013-05-13T17:55:42+0200",
- "users": Array [
- Object {
- "active": true,
- "local": true,
- "login": "assignee",
- "name": "John Doe",
- },
- Object {
- "active": true,
- "local": true,
- "login": "author",
- "name": "John Doe",
- },
- ],
- }
- }
- onUpdateHotspot={[MockFunction]}
- />,
- "key": "review",
- "label": <React.Fragment>
- <span>
- hotspots.tabs.review_history
- </span>
- </React.Fragment>,
- },
]
}
/>
@@ -164,278 +40,6 @@ exports[`should render correctly: fix 1`] = `
</Fragment>
`;
-exports[`should render correctly: review 1`] = `
-<Fragment>
- <BoxedTabs
- onSelect={[Function]}
- selected="review"
- tabs={
- Array [
- Object {
- "content": "<p>This a <strong>strong</strong> message about risk !</p>",
- "key": "risk",
- "label": "hotspots.tabs.risk_description",
- },
- Object {
- "content": "<p>This a <strong>strong</strong> message about vulnerability !</p>",
- "key": "vulnerability",
- "label": "hotspots.tabs.vulnerability_description",
- },
- Object {
- "content": "<p>This a <strong>strong</strong> message about fixing !</p>",
- "key": "fix",
- "label": "hotspots.tabs.fix_recommendations",
- },
- Object {
- "content": <HotspotViewerReviewHistoryTab
- history={
- Array [
- Object {
- "date": "2013-05-13T17:55:41+0200",
- "type": 0,
- "user": Object {
- "active": true,
- "local": true,
- "login": "author",
- "name": "John Doe",
- },
- },
- ]
- }
- hotspot={
- Object {
- "assignee": "assignee",
- "assigneeUser": Object {
- "active": true,
- "local": true,
- "login": "assignee",
- "name": "John Doe",
- },
- "author": "author",
- "authorUser": Object {
- "active": true,
- "local": true,
- "login": "author",
- "name": "John Doe",
- },
- "canChangeStatus": true,
- "changelog": Array [],
- "comment": Array [],
- "component": Object {
- "breadcrumbs": Array [],
- "key": "my-project",
- "name": "MyProject",
- "organization": "foo",
- "qualifier": "FIL",
- "qualityGate": Object {
- "isDefault": true,
- "key": "30",
- "name": "Sonar way",
- },
- "qualityProfiles": Array [
- Object {
- "deleted": false,
- "key": "my-qp",
- "language": "ts",
- "name": "Sonar way",
- },
- ],
- "tags": Array [],
- },
- "creationDate": "2013-05-13T17:55:41+0200",
- "key": "01fc972e-2a3c-433e-bcae-0bd7f88f5123",
- "line": 142,
- "message": "'3' is a magic number.",
- "project": Object {
- "breadcrumbs": Array [],
- "key": "my-project",
- "name": "MyProject",
- "organization": "foo",
- "qualifier": "TRK",
- "qualityGate": Object {
- "isDefault": true,
- "key": "30",
- "name": "Sonar way",
- },
- "qualityProfiles": Array [
- Object {
- "deleted": false,
- "key": "my-qp",
- "language": "ts",
- "name": "Sonar way",
- },
- ],
- "tags": Array [],
- },
- "resolution": "FIXED",
- "rule": Object {
- "fixRecommendations": "<p>This a <strong>strong</strong> message about fixing !</p>",
- "key": "squid:S2077",
- "name": "That rule",
- "riskDescription": "<p>This a <strong>strong</strong> message about risk !</p>",
- "securityCategory": "sql-injection",
- "vulnerabilityDescription": "<p>This a <strong>strong</strong> message about vulnerability !</p>",
- "vulnerabilityProbability": "HIGH",
- },
- "status": "REVIEWED",
- "textRange": Object {
- "endLine": 142,
- "endOffset": 83,
- "startLine": 142,
- "startOffset": 26,
- },
- "updateDate": "2013-05-13T17:55:42+0200",
- "users": Array [
- Object {
- "active": true,
- "local": true,
- "login": "assignee",
- "name": "John Doe",
- },
- Object {
- "active": true,
- "local": true,
- "login": "author",
- "name": "John Doe",
- },
- ],
- }
- }
- onUpdateHotspot={[MockFunction]}
- />,
- "key": "review",
- "label": <React.Fragment>
- <span>
- hotspots.tabs.review_history
- </span>
- </React.Fragment>,
- },
- ]
- }
- />
- <div
- className="bordered huge-spacer-bottom"
- >
- <HotspotViewerReviewHistoryTab
- history={
- Array [
- Object {
- "date": "2013-05-13T17:55:41+0200",
- "type": 0,
- "user": Object {
- "active": true,
- "local": true,
- "login": "author",
- "name": "John Doe",
- },
- },
- ]
- }
- hotspot={
- Object {
- "assignee": "assignee",
- "assigneeUser": Object {
- "active": true,
- "local": true,
- "login": "assignee",
- "name": "John Doe",
- },
- "author": "author",
- "authorUser": Object {
- "active": true,
- "local": true,
- "login": "author",
- "name": "John Doe",
- },
- "canChangeStatus": true,
- "changelog": Array [],
- "comment": Array [],
- "component": Object {
- "breadcrumbs": Array [],
- "key": "my-project",
- "name": "MyProject",
- "organization": "foo",
- "qualifier": "FIL",
- "qualityGate": Object {
- "isDefault": true,
- "key": "30",
- "name": "Sonar way",
- },
- "qualityProfiles": Array [
- Object {
- "deleted": false,
- "key": "my-qp",
- "language": "ts",
- "name": "Sonar way",
- },
- ],
- "tags": Array [],
- },
- "creationDate": "2013-05-13T17:55:41+0200",
- "key": "01fc972e-2a3c-433e-bcae-0bd7f88f5123",
- "line": 142,
- "message": "'3' is a magic number.",
- "project": Object {
- "breadcrumbs": Array [],
- "key": "my-project",
- "name": "MyProject",
- "organization": "foo",
- "qualifier": "TRK",
- "qualityGate": Object {
- "isDefault": true,
- "key": "30",
- "name": "Sonar way",
- },
- "qualityProfiles": Array [
- Object {
- "deleted": false,
- "key": "my-qp",
- "language": "ts",
- "name": "Sonar way",
- },
- ],
- "tags": Array [],
- },
- "resolution": "FIXED",
- "rule": Object {
- "fixRecommendations": "<p>This a <strong>strong</strong> message about fixing !</p>",
- "key": "squid:S2077",
- "name": "That rule",
- "riskDescription": "<p>This a <strong>strong</strong> message about risk !</p>",
- "securityCategory": "sql-injection",
- "vulnerabilityDescription": "<p>This a <strong>strong</strong> message about vulnerability !</p>",
- "vulnerabilityProbability": "HIGH",
- },
- "status": "REVIEWED",
- "textRange": Object {
- "endLine": 142,
- "endOffset": 83,
- "startLine": 142,
- "startOffset": 26,
- },
- "updateDate": "2013-05-13T17:55:42+0200",
- "users": Array [
- Object {
- "active": true,
- "local": true,
- "login": "assignee",
- "name": "John Doe",
- },
- Object {
- "active": true,
- "local": true,
- "login": "author",
- "name": "John Doe",
- },
- ],
- }
- }
- onUpdateHotspot={[MockFunction]}
- />
- </div>
-</Fragment>
-`;
-
exports[`should render correctly: risk 1`] = `
<Fragment>
<BoxedTabs
@@ -458,130 +62,6 @@ exports[`should render correctly: risk 1`] = `
"key": "fix",
"label": "hotspots.tabs.fix_recommendations",
},
- Object {
- "content": <HotspotViewerReviewHistoryTab
- history={
- Array [
- Object {
- "date": "2013-05-13T17:55:41+0200",
- "type": 0,
- "user": Object {
- "active": true,
- "local": true,
- "login": "author",
- "name": "John Doe",
- },
- },
- ]
- }
- hotspot={
- Object {
- "assignee": "assignee",
- "assigneeUser": Object {
- "active": true,
- "local": true,
- "login": "assignee",
- "name": "John Doe",
- },
- "author": "author",
- "authorUser": Object {
- "active": true,
- "local": true,
- "login": "author",
- "name": "John Doe",
- },
- "canChangeStatus": true,
- "changelog": Array [],
- "comment": Array [],
- "component": Object {
- "breadcrumbs": Array [],
- "key": "my-project",
- "name": "MyProject",
- "organization": "foo",
- "qualifier": "FIL",
- "qualityGate": Object {
- "isDefault": true,
- "key": "30",
- "name": "Sonar way",
- },
- "qualityProfiles": Array [
- Object {
- "deleted": false,
- "key": "my-qp",
- "language": "ts",
- "name": "Sonar way",
- },
- ],
- "tags": Array [],
- },
- "creationDate": "2013-05-13T17:55:41+0200",
- "key": "01fc972e-2a3c-433e-bcae-0bd7f88f5123",
- "line": 142,
- "message": "'3' is a magic number.",
- "project": Object {
- "breadcrumbs": Array [],
- "key": "my-project",
- "name": "MyProject",
- "organization": "foo",
- "qualifier": "TRK",
- "qualityGate": Object {
- "isDefault": true,
- "key": "30",
- "name": "Sonar way",
- },
- "qualityProfiles": Array [
- Object {
- "deleted": false,
- "key": "my-qp",
- "language": "ts",
- "name": "Sonar way",
- },
- ],
- "tags": Array [],
- },
- "resolution": "FIXED",
- "rule": Object {
- "fixRecommendations": "<p>This a <strong>strong</strong> message about fixing !</p>",
- "key": "squid:S2077",
- "name": "That rule",
- "riskDescription": "<p>This a <strong>strong</strong> message about risk !</p>",
- "securityCategory": "sql-injection",
- "vulnerabilityDescription": "<p>This a <strong>strong</strong> message about vulnerability !</p>",
- "vulnerabilityProbability": "HIGH",
- },
- "status": "REVIEWED",
- "textRange": Object {
- "endLine": 142,
- "endOffset": 83,
- "startLine": 142,
- "startOffset": 26,
- },
- "updateDate": "2013-05-13T17:55:42+0200",
- "users": Array [
- Object {
- "active": true,
- "local": true,
- "login": "assignee",
- "name": "John Doe",
- },
- Object {
- "active": true,
- "local": true,
- "login": "author",
- "name": "John Doe",
- },
- ],
- }
- }
- onUpdateHotspot={[MockFunction]}
- />,
- "key": "review",
- "label": <React.Fragment>
- <span>
- hotspots.tabs.review_history
- </span>
- </React.Fragment>,
- },
]
}
/>
@@ -622,130 +102,6 @@ exports[`should render correctly: vulnerability 1`] = `
"key": "fix",
"label": "hotspots.tabs.fix_recommendations",
},
- Object {
- "content": <HotspotViewerReviewHistoryTab
- history={
- Array [
- Object {
- "date": "2013-05-13T17:55:41+0200",
- "type": 0,
- "user": Object {
- "active": true,
- "local": true,
- "login": "author",
- "name": "John Doe",
- },
- },
- ]
- }
- hotspot={
- Object {
- "assignee": "assignee",
- "assigneeUser": Object {
- "active": true,
- "local": true,
- "login": "assignee",
- "name": "John Doe",
- },
- "author": "author",
- "authorUser": Object {
- "active": true,
- "local": true,
- "login": "author",
- "name": "John Doe",
- },
- "canChangeStatus": true,
- "changelog": Array [],
- "comment": Array [],
- "component": Object {
- "breadcrumbs": Array [],
- "key": "my-project",
- "name": "MyProject",
- "organization": "foo",
- "qualifier": "FIL",
- "qualityGate": Object {
- "isDefault": true,
- "key": "30",
- "name": "Sonar way",
- },
- "qualityProfiles": Array [
- Object {
- "deleted": false,
- "key": "my-qp",
- "language": "ts",
- "name": "Sonar way",
- },
- ],
- "tags": Array [],
- },
- "creationDate": "2013-05-13T17:55:41+0200",
- "key": "01fc972e-2a3c-433e-bcae-0bd7f88f5123",
- "line": 142,
- "message": "'3' is a magic number.",
- "project": Object {
- "breadcrumbs": Array [],
- "key": "my-project",
- "name": "MyProject",
- "organization": "foo",
- "qualifier": "TRK",
- "qualityGate": Object {
- "isDefault": true,
- "key": "30",
- "name": "Sonar way",
- },
- "qualityProfiles": Array [
- Object {
- "deleted": false,
- "key": "my-qp",
- "language": "ts",
- "name": "Sonar way",
- },
- ],
- "tags": Array [],
- },
- "resolution": "FIXED",
- "rule": Object {
- "fixRecommendations": "<p>This a <strong>strong</strong> message about fixing !</p>",
- "key": "squid:S2077",
- "name": "That rule",
- "riskDescription": "<p>This a <strong>strong</strong> message about risk !</p>",
- "securityCategory": "sql-injection",
- "vulnerabilityDescription": "<p>This a <strong>strong</strong> message about vulnerability !</p>",
- "vulnerabilityProbability": "HIGH",
- },
- "status": "REVIEWED",
- "textRange": Object {
- "endLine": 142,
- "endOffset": 83,
- "startLine": 142,
- "startOffset": 26,
- },
- "updateDate": "2013-05-13T17:55:42+0200",
- "users": Array [
- Object {
- "active": true,
- "local": true,
- "login": "assignee",
- "name": "John Doe",
- },
- Object {
- "active": true,
- "local": true,
- "login": "author",
- "name": "John Doe",
- },
- ],
- }
- }
- onUpdateHotspot={[MockFunction]}
- />,
- "key": "review",
- "label": <React.Fragment>
- <span>
- hotspots.tabs.review_history
- </span>
- </React.Fragment>,
- },
]
}
/>
@@ -786,161 +142,6 @@ exports[`should render correctly: with comments or changelog element 1`] = `
"key": "fix",
"label": "hotspots.tabs.fix_recommendations",
},
- Object {
- "content": <HotspotViewerReviewHistoryTab
- history={
- Array [
- Object {
- "date": "2013-05-13T17:55:41+0200",
- "type": 0,
- "user": Object {
- "active": true,
- "local": true,
- "login": "author",
- "name": "John Doe",
- },
- },
- Object {
- "date": "2019-01-01",
- "html": "<strong>test</strong>",
- "type": 2,
- "user": Object {
- "active": true,
- "local": true,
- "login": "john.doe",
- "name": "John Doe",
- },
- },
- ]
- }
- hotspot={
- Object {
- "assignee": "assignee",
- "assigneeUser": Object {
- "active": true,
- "local": true,
- "login": "assignee",
- "name": "John Doe",
- },
- "author": "author",
- "authorUser": Object {
- "active": true,
- "local": true,
- "login": "author",
- "name": "John Doe",
- },
- "canChangeStatus": true,
- "changelog": Array [],
- "comment": Array [
- Object {
- "createdAt": "2019-01-01",
- "htmlText": "<strong>test</strong>",
- "key": "comment-key",
- "login": "me",
- "markdown": "*test*",
- "updatable": false,
- "user": Object {
- "active": true,
- "local": true,
- "login": "john.doe",
- "name": "John Doe",
- },
- },
- ],
- "component": Object {
- "breadcrumbs": Array [],
- "key": "my-project",
- "name": "MyProject",
- "organization": "foo",
- "qualifier": "FIL",
- "qualityGate": Object {
- "isDefault": true,
- "key": "30",
- "name": "Sonar way",
- },
- "qualityProfiles": Array [
- Object {
- "deleted": false,
- "key": "my-qp",
- "language": "ts",
- "name": "Sonar way",
- },
- ],
- "tags": Array [],
- },
- "creationDate": "2013-05-13T17:55:41+0200",
- "key": "01fc972e-2a3c-433e-bcae-0bd7f88f5123",
- "line": 142,
- "message": "'3' is a magic number.",
- "project": Object {
- "breadcrumbs": Array [],
- "key": "my-project",
- "name": "MyProject",
- "organization": "foo",
- "qualifier": "TRK",
- "qualityGate": Object {
- "isDefault": true,
- "key": "30",
- "name": "Sonar way",
- },
- "qualityProfiles": Array [
- Object {
- "deleted": false,
- "key": "my-qp",
- "language": "ts",
- "name": "Sonar way",
- },
- ],
- "tags": Array [],
- },
- "resolution": "FIXED",
- "rule": Object {
- "fixRecommendations": "<p>This a <strong>strong</strong> message about fixing !</p>",
- "key": "squid:S2077",
- "name": "That rule",
- "riskDescription": "<p>This a <strong>strong</strong> message about risk !</p>",
- "securityCategory": "sql-injection",
- "vulnerabilityDescription": "<p>This a <strong>strong</strong> message about vulnerability !</p>",
- "vulnerabilityProbability": "HIGH",
- },
- "status": "REVIEWED",
- "textRange": Object {
- "endLine": 142,
- "endOffset": 83,
- "startLine": 142,
- "startOffset": 26,
- },
- "updateDate": "2013-05-13T17:55:42+0200",
- "users": Array [
- Object {
- "active": true,
- "local": true,
- "login": "assignee",
- "name": "John Doe",
- },
- Object {
- "active": true,
- "local": true,
- "login": "author",
- "name": "John Doe",
- },
- ],
- }
- }
- onUpdateHotspot={[MockFunction]}
- />,
- "key": "review",
- "label": <React.Fragment>
- <span>
- hotspots.tabs.review_history
- </span>
- <span
- className="counter-badge spacer-left"
- >
- 1
- </span>
- </React.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 f95c95b6331..69d689e6df0 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
@@ -48,6 +48,17 @@
#security_hotspots .main {
flex: 1 1 auto;
- overflow-y: auto;
background-color: white;
+ /* Force flex to take parent width. */
+ overflow-x: auto;
+}
+
+#security_hotspots .main .hotspot-content {
+ overflow-y: auto;
+ height: 100%;
+ box-sizing: border-box;
+}
+
+.invisible {
+ visibility: hidden;
}
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 c0fe1efc968..06c3898631b 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
@@ -81,14 +81,8 @@ export function constructSourceViewerFile(
};
}
-export function getHotspotReviewHistory(
- hotspot: Hotspot
-): {
- history: ReviewHistoryElement[];
- functionalCount: number;
-} {
+export function getHotspotReviewHistory(hotspot: Hotspot): ReviewHistoryElement[] {
const history: ReviewHistoryElement[] = [];
- let functionalCount = 0;
if (hotspot.creationDate) {
history.push({
@@ -102,7 +96,6 @@ export function getHotspotReviewHistory(
}
if (hotspot.changelog && hotspot.changelog.length > 0) {
- functionalCount += hotspot.changelog.length;
history.push(
...hotspot.changelog.map(log => ({
type: ReviewHistoryType.Diff,
@@ -118,7 +111,6 @@ export function getHotspotReviewHistory(
}
if (hotspot.comment && hotspot.comment.length > 0) {
- functionalCount += hotspot.comment.length;
history.push(
...hotspot.comment.map(comment => ({
type: ReviewHistoryType.Comment,
@@ -132,10 +124,7 @@ export function getHotspotReviewHistory(
);
}
- return {
- history: sortBy(history, elt => elt.date),
- functionalCount
- };
+ return sortBy(history, elt => elt.date);
}
const STATUS_AND_RESOLUTION_TO_STATUS_OPTION = {
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 880fabbf057..aa865428be5 100644
--- a/sonar-core/src/main/resources/org/sonar/l10n/core.properties
+++ b/sonar-core/src/main/resources/org/sonar/l10n/core.properties
@@ -667,12 +667,11 @@ hotspots.risk_exposure=Review priority
hotspots.tabs.risk_description=What's the risk?
hotspots.tabs.vulnerability_description=Are you at risk?
hotspots.tabs.fix_recommendations=How can you fix it?
-hotspots.tabs.review_history=Review history
-hotspots.tabs.review_history.created=created Security Hotspot
-hotspots.tabs.review_history.comment.added=added a comment
-hotspots.tabs.review_history.comment.add=Add a comment
-hotspots.tabs.review_history.comment.field=Comment:
-hotspots.tabs.review_history.comment.submit=Comment
+hotspots.review_history.created=created Security Hotspot
+hotspots.review_history.comment_added=added a comment
+hotspots.comment.field=Comment:
+hotspots.comment.open=Add Comment
+hotspots.comment.submit=Comment
hotspots.assignee.select_user=Select a user...
hotspots.status.cannot_change_status=Changing a hotspot's status requires permission.
@@ -696,6 +695,7 @@ hotspot.filters.period.since_leak_period=New code
hotspot.filters.period.overall=Overall code
hotspot.filters.status.safe=Reviewed as safe
hotspot.filters.show_all=Show all hotspots
+hotspot.section.activity=Activity:
hotspots.reviewed.tooltip=Percentage of Security Hotspots reviewed (fixed or safe) among all non-closed Security Hotspots.
hotspots.review_hotspot=Review Hotspot