@@ -59,5 +59,27 @@ export function getSecurityHotspots( | |||
} | |||
export function getSecurityHotspotDetails(securityHotspotKey: string): Promise<Hotspot> { | |||
return getJSON('/api/hotspots/show', { hotspot: securityHotspotKey }).catch(throwGlobalError); | |||
return getJSON('/api/hotspots/show', { hotspot: securityHotspotKey }) | |||
.then((response: Hotspot & { users: T.UserBase[] }) => { | |||
const { users, ...hotspot } = response; | |||
if (users) { | |||
if (hotspot.assignee) { | |||
hotspot.assigneeUser = users.find(u => u.login === hotspot.assignee) || { | |||
active: true, | |||
login: hotspot.assignee | |||
}; | |||
} | |||
hotspot.authorUser = users.find(u => u.login === hotspot.author) || { | |||
active: true, | |||
login: hotspot.author | |||
}; | |||
hotspot.comment.forEach(c => { | |||
c.user = users.find(u => u.login === c.login) || { active: true, login: c.login }; | |||
}); | |||
} | |||
return hotspot; | |||
}) | |||
.catch(throwGlobalError); | |||
} |
@@ -18,6 +18,7 @@ | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
import { mockHotspot, mockRawHotspot } from '../../../helpers/mocks/security-hotspots'; | |||
import { mockUser } from '../../../helpers/testMocks'; | |||
import { ReviewHistoryType, RiskExposure } from '../../../types/security-hotspots'; | |||
import { getHotspotReviewHistory, groupByCategory, mapRules, sortHotspots } from '../utils'; | |||
@@ -158,25 +159,56 @@ describe('getHotspotReviewHistory', () => { | |||
} | |||
] | |||
}; | |||
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] | |||
changelog: [changelogElement], | |||
comment: [commentElement, commentElement1] | |||
}); | |||
const history = getHotspotReviewHistory(hotspot); | |||
expect(history.length).toBe(2); | |||
expect(history.length).toBe(4); | |||
expect(history[0]).toEqual( | |||
expect.objectContaining({ | |||
type: ReviewHistoryType.Creation, | |||
date: hotspot.creationDate, | |||
user: { | |||
avatar: hotspot.author.avatar, | |||
name: hotspot.author.name, | |||
active: hotspot.author.active | |||
} | |||
user: hotspot.authorUser | |||
}) | |||
); | |||
expect(history[1]).toEqual( | |||
expect.objectContaining({ | |||
type: ReviewHistoryType.Comment, | |||
date: commentElement.createdAt, | |||
user: commentElement.user, | |||
html: commentElement.htmlText | |||
}) | |||
); | |||
expect(history[2]).toEqual( | |||
expect.objectContaining({ | |||
type: ReviewHistoryType.Comment, | |||
date: commentElement1.createdAt, | |||
user: commentElement1.user, | |||
html: commentElement1.htmlText | |||
}) | |||
); | |||
expect(history[3]).toEqual( | |||
expect.objectContaining({ | |||
type: ReviewHistoryType.Diff, | |||
date: changelogElement.creationDate, |
@@ -63,13 +63,13 @@ export function HotspotViewerRenderer(props: HotspotViewerRendererProps) { | |||
<span className="badge little-spacer-left"> | |||
{translate('hotspot.status', hotspot.resolution || hotspot.status)} | |||
</span> | |||
{hotspot.assignee && hotspot.assignee.name && ( | |||
{hotspot.assigneeUser && hotspot.assigneeUser.name && ( | |||
<> | |||
<span className="huge-spacer-left">{translate('assigned_to')}:</span> | |||
<strong className="little-spacer-left"> | |||
{hotspot.assignee.active | |||
? hotspot.assignee.name | |||
: translateWithParameters('user.x_deleted', hotspot.assignee.name)} | |||
{hotspot.assigneeUser.active | |||
? hotspot.assigneeUser.name | |||
: translateWithParameters('user.x_deleted', hotspot.assigneeUser.name)} | |||
</strong> | |||
</> | |||
)} |
@@ -17,6 +17,8 @@ | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
import { sanitize } from 'dompurify'; | |||
import * as React from 'react'; | |||
import { translate, translateWithParameters } from 'sonar-ui-common/helpers/l10n'; | |||
import DateTimeFormatter from '../../../components/intl/DateTimeFormatter'; | |||
@@ -34,9 +36,9 @@ export default function HotspotViewerReviewHistoryTab(props: HotspotViewerReview | |||
return ( | |||
<> | |||
{history.map((elt, i) => ( | |||
<React.Fragment key={`${elt.user.name}-${elt.date}`}> | |||
<React.Fragment key={i}> | |||
{i > 0 && <hr />} | |||
<div> | |||
<div className="padded"> | |||
<div className="display-flex-center"> | |||
{elt.user.name && ( | |||
<> | |||
@@ -56,6 +58,11 @@ export default function HotspotViewerReviewHistoryTab(props: HotspotViewerReview | |||
{translate('hotspots.tabs.review_history.created')} | |||
</span> | |||
)} | |||
{elt.type === ReviewHistoryType.Comment && ( | |||
<span className="little-spacer-left"> | |||
{translate('hotspots.tabs.review_history.comment')} | |||
</span> | |||
)} | |||
<span className="little-spacer-left little-spacer-right">-</span> | |||
</> | |||
)} | |||
@@ -64,14 +71,18 @@ export default function HotspotViewerReviewHistoryTab(props: HotspotViewerReview | |||
{elt.type === ReviewHistoryType.Diff && elt.diffs && ( | |||
<div className="spacer-top"> | |||
{elt.diffs.map(diff => ( | |||
<IssueChangelogDiff | |||
diff={diff} | |||
key={`${diff.key}-${diff.oldValue}-${diff.newValue}`} | |||
/> | |||
{elt.diffs.map((diff, i) => ( | |||
<IssueChangelogDiff diff={diff} key={i} /> | |||
))} | |||
</div> | |||
)} | |||
{elt.type === ReviewHistoryType.Comment && elt.html && ( | |||
<div | |||
className="spacer-top markdown" | |||
dangerouslySetInnerHTML={{ __html: sanitize(elt.html) }} | |||
/> | |||
)} | |||
</div> | |||
</React.Fragment> | |||
))} |
@@ -84,10 +84,10 @@ export default function HotspotViewerTabs(props: HotspotViewerTabsProps) { | |||
selected={currentTabKey} | |||
tabs={tabs} | |||
/> | |||
<div className="boxed-group big-padded"> | |||
<div className="bordered"> | |||
{typeof currentTab.content === 'string' ? ( | |||
<div | |||
className="markdown" | |||
className="markdown big-padded" | |||
dangerouslySetInnerHTML={{ __html: sanitize(currentTab.content) }} | |||
/> | |||
) : ( |
@@ -31,12 +31,12 @@ it('should render correctly', () => { | |||
'unassigned' | |||
); | |||
expect( | |||
shallowRender({ hotspot: mockHotspot({ assignee: mockUser({ active: false }) }) }) | |||
shallowRender({ hotspot: mockHotspot({ assigneeUser: mockUser({ active: false }) }) }) | |||
).toMatchSnapshot('deleted assignee'); | |||
expect( | |||
shallowRender({ | |||
hotspot: mockHotspot({ | |||
assignee: mockUser({ name: undefined, login: 'assignee_login' }) | |||
assigneeUser: mockUser({ name: undefined, login: 'assignee_login' }) | |||
}) | |||
}) | |||
).toMatchSnapshot('assignee without name'); |
@@ -44,6 +44,10 @@ function shallowRender(props?: Partial<HotspotViewerReviewHistoryTabProps>) { | |||
{ key: 'test', oldValue: 'old', newValue: 'new' }, | |||
{ key: 'test-1', oldValue: 'old-1', newValue: 'new-1' } | |||
] | |||
}), | |||
mockHotspotReviewHistoryElement({ | |||
type: ReviewHistoryType.Comment, | |||
html: '<strong>bold text</strong>' | |||
}) | |||
]} | |||
{...props} |
@@ -13,19 +13,22 @@ exports[`should render correctly 1`] = ` | |||
highlightedSymbols={Array []} | |||
hotspot={ | |||
Object { | |||
"assignee": Object { | |||
"assignee": "assignee", | |||
"assigneeUser": Object { | |||
"active": true, | |||
"local": true, | |||
"login": "john.doe", | |||
"login": "assignee", | |||
"name": "John Doe", | |||
}, | |||
"author": Object { | |||
"author": "author", | |||
"authorUser": Object { | |||
"active": true, | |||
"local": true, | |||
"login": "john.doe", | |||
"login": "author", | |||
"name": "John Doe", | |||
}, | |||
"changelog": Array [], | |||
"comment": Array [], | |||
"component": Object { | |||
"breadcrumbs": Array [], | |||
"key": "my-project", | |||
@@ -90,6 +93,20 @@ exports[`should render correctly 1`] = ` | |||
"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", | |||
}, | |||
], | |||
} | |||
} | |||
loading={true} |
@@ -137,19 +137,22 @@ exports[`should render correctly: with sourcelines 1`] = ` | |||
index={0} | |||
issue={ | |||
Object { | |||
"assignee": Object { | |||
"assignee": "assignee", | |||
"assigneeUser": Object { | |||
"active": true, | |||
"local": true, | |||
"login": "john.doe", | |||
"login": "assignee", | |||
"name": "John Doe", | |||
}, | |||
"author": Object { | |||
"author": "author", | |||
"authorUser": Object { | |||
"active": true, | |||
"local": true, | |||
"login": "john.doe", | |||
"login": "author", | |||
"name": "John Doe", | |||
}, | |||
"changelog": Array [], | |||
"comment": Array [], | |||
"component": Object { | |||
"breadcrumbs": Array [], | |||
"key": "my-project", | |||
@@ -214,6 +217,20 @@ exports[`should render correctly: with sourcelines 1`] = ` | |||
"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", | |||
}, | |||
], | |||
} | |||
} | |||
issuesByLine={Object {}} |
@@ -59,19 +59,22 @@ exports[`should render correctly 1`] = ` | |||
<HotspotSnippetContainer | |||
hotspot={ | |||
Object { | |||
"assignee": Object { | |||
"assignee": "assignee", | |||
"assigneeUser": Object { | |||
"active": true, | |||
"local": true, | |||
"login": "john.doe", | |||
"login": "assignee", | |||
"name": "John Doe", | |||
}, | |||
"author": Object { | |||
"author": "author", | |||
"authorUser": Object { | |||
"active": true, | |||
"local": true, | |||
"login": "john.doe", | |||
"login": "author", | |||
"name": "John Doe", | |||
}, | |||
"changelog": Array [], | |||
"comment": Array [], | |||
"component": Object { | |||
"breadcrumbs": Array [], | |||
"key": "my-project", | |||
@@ -136,25 +139,42 @@ exports[`should render correctly 1`] = ` | |||
"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", | |||
}, | |||
], | |||
} | |||
} | |||
/> | |||
<HotspotViewerTabs | |||
hotspot={ | |||
Object { | |||
"assignee": Object { | |||
"assignee": "assignee", | |||
"assigneeUser": Object { | |||
"active": true, | |||
"local": true, | |||
"login": "john.doe", | |||
"login": "assignee", | |||
"name": "John Doe", | |||
}, | |||
"author": Object { | |||
"author": "author", | |||
"authorUser": Object { | |||
"active": true, | |||
"local": true, | |||
"login": "john.doe", | |||
"login": "author", | |||
"name": "John Doe", | |||
}, | |||
"changelog": Array [], | |||
"comment": Array [], | |||
"component": Object { | |||
"breadcrumbs": Array [], | |||
"key": "my-project", | |||
@@ -219,6 +239,20 @@ exports[`should render correctly 1`] = ` | |||
"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", | |||
}, | |||
], | |||
} | |||
} | |||
/> | |||
@@ -285,19 +319,22 @@ exports[`should render correctly: anonymous user 1`] = ` | |||
<HotspotSnippetContainer | |||
hotspot={ | |||
Object { | |||
"assignee": Object { | |||
"assignee": "assignee", | |||
"assigneeUser": Object { | |||
"active": true, | |||
"local": true, | |||
"login": "john.doe", | |||
"login": "assignee", | |||
"name": "John Doe", | |||
}, | |||
"author": Object { | |||
"author": "author", | |||
"authorUser": Object { | |||
"active": true, | |||
"local": true, | |||
"login": "john.doe", | |||
"login": "author", | |||
"name": "John Doe", | |||
}, | |||
"changelog": Array [], | |||
"comment": Array [], | |||
"component": Object { | |||
"breadcrumbs": Array [], | |||
"key": "my-project", | |||
@@ -362,25 +399,42 @@ exports[`should render correctly: anonymous user 1`] = ` | |||
"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", | |||
}, | |||
], | |||
} | |||
} | |||
/> | |||
<HotspotViewerTabs | |||
hotspot={ | |||
Object { | |||
"assignee": Object { | |||
"assignee": "assignee", | |||
"assigneeUser": Object { | |||
"active": true, | |||
"local": true, | |||
"login": "john.doe", | |||
"login": "assignee", | |||
"name": "John Doe", | |||
}, | |||
"author": Object { | |||
"author": "author", | |||
"authorUser": Object { | |||
"active": true, | |||
"local": true, | |||
"login": "john.doe", | |||
"login": "author", | |||
"name": "John Doe", | |||
}, | |||
"changelog": Array [], | |||
"comment": Array [], | |||
"component": Object { | |||
"breadcrumbs": Array [], | |||
"key": "my-project", | |||
@@ -445,6 +499,20 @@ exports[`should render correctly: anonymous user 1`] = ` | |||
"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", | |||
}, | |||
], | |||
} | |||
} | |||
/> | |||
@@ -500,19 +568,22 @@ exports[`should render correctly: assignee without name 1`] = ` | |||
<HotspotSnippetContainer | |||
hotspot={ | |||
Object { | |||
"assignee": Object { | |||
"assignee": "assignee", | |||
"assigneeUser": Object { | |||
"active": true, | |||
"local": true, | |||
"login": "assignee_login", | |||
"name": undefined, | |||
}, | |||
"author": Object { | |||
"author": "author", | |||
"authorUser": Object { | |||
"active": true, | |||
"local": true, | |||
"login": "john.doe", | |||
"login": "author", | |||
"name": "John Doe", | |||
}, | |||
"changelog": Array [], | |||
"comment": Array [], | |||
"component": Object { | |||
"breadcrumbs": Array [], | |||
"key": "my-project", | |||
@@ -577,25 +648,42 @@ exports[`should render correctly: assignee without name 1`] = ` | |||
"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", | |||
}, | |||
], | |||
} | |||
} | |||
/> | |||
<HotspotViewerTabs | |||
hotspot={ | |||
Object { | |||
"assignee": Object { | |||
"assignee": "assignee", | |||
"assigneeUser": Object { | |||
"active": true, | |||
"local": true, | |||
"login": "assignee_login", | |||
"name": undefined, | |||
}, | |||
"author": Object { | |||
"author": "author", | |||
"authorUser": Object { | |||
"active": true, | |||
"local": true, | |||
"login": "john.doe", | |||
"login": "author", | |||
"name": "John Doe", | |||
}, | |||
"changelog": Array [], | |||
"comment": Array [], | |||
"component": Object { | |||
"breadcrumbs": Array [], | |||
"key": "my-project", | |||
@@ -660,6 +748,20 @@ exports[`should render correctly: assignee without name 1`] = ` | |||
"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", | |||
}, | |||
], | |||
} | |||
} | |||
/> | |||
@@ -726,19 +828,22 @@ exports[`should render correctly: deleted assignee 1`] = ` | |||
<HotspotSnippetContainer | |||
hotspot={ | |||
Object { | |||
"assignee": Object { | |||
"assignee": "assignee", | |||
"assigneeUser": Object { | |||
"active": false, | |||
"local": true, | |||
"login": "john.doe", | |||
"name": "John Doe", | |||
}, | |||
"author": Object { | |||
"author": "author", | |||
"authorUser": Object { | |||
"active": true, | |||
"local": true, | |||
"login": "john.doe", | |||
"login": "author", | |||
"name": "John Doe", | |||
}, | |||
"changelog": Array [], | |||
"comment": Array [], | |||
"component": Object { | |||
"breadcrumbs": Array [], | |||
"key": "my-project", | |||
@@ -803,25 +908,42 @@ exports[`should render correctly: deleted assignee 1`] = ` | |||
"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", | |||
}, | |||
], | |||
} | |||
} | |||
/> | |||
<HotspotViewerTabs | |||
hotspot={ | |||
Object { | |||
"assignee": Object { | |||
"assignee": "assignee", | |||
"assigneeUser": Object { | |||
"active": false, | |||
"local": true, | |||
"login": "john.doe", | |||
"name": "John Doe", | |||
}, | |||
"author": Object { | |||
"author": "author", | |||
"authorUser": Object { | |||
"active": true, | |||
"local": true, | |||
"login": "john.doe", | |||
"login": "author", | |||
"name": "John Doe", | |||
}, | |||
"changelog": Array [], | |||
"comment": Array [], | |||
"component": Object { | |||
"breadcrumbs": Array [], | |||
"key": "my-project", | |||
@@ -886,6 +1008,20 @@ exports[`should render correctly: deleted assignee 1`] = ` | |||
"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", | |||
}, | |||
], | |||
} | |||
} | |||
/> | |||
@@ -944,18 +1080,37 @@ exports[`should render correctly: unassigned 1`] = ` | |||
> | |||
hotspot.status.FIXED | |||
</span> | |||
<span | |||
className="huge-spacer-left" | |||
> | |||
assigned_to | |||
: | |||
</span> | |||
<strong | |||
className="little-spacer-left" | |||
> | |||
John Doe | |||
</strong> | |||
</div> | |||
<HotspotSnippetContainer | |||
hotspot={ | |||
Object { | |||
"assignee": undefined, | |||
"author": Object { | |||
"assigneeUser": Object { | |||
"active": true, | |||
"local": true, | |||
"login": "john.doe", | |||
"login": "assignee", | |||
"name": "John Doe", | |||
}, | |||
"author": "author", | |||
"authorUser": Object { | |||
"active": true, | |||
"local": true, | |||
"login": "author", | |||
"name": "John Doe", | |||
}, | |||
"changelog": Array [], | |||
"comment": Array [], | |||
"component": Object { | |||
"breadcrumbs": Array [], | |||
"key": "my-project", | |||
@@ -1020,6 +1175,20 @@ exports[`should render correctly: unassigned 1`] = ` | |||
"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", | |||
}, | |||
], | |||
} | |||
} | |||
/> | |||
@@ -1027,13 +1196,21 @@ exports[`should render correctly: unassigned 1`] = ` | |||
hotspot={ | |||
Object { | |||
"assignee": undefined, | |||
"author": Object { | |||
"assigneeUser": Object { | |||
"active": true, | |||
"local": true, | |||
"login": "john.doe", | |||
"login": "assignee", | |||
"name": "John Doe", | |||
}, | |||
"author": "author", | |||
"authorUser": Object { | |||
"active": true, | |||
"local": true, | |||
"login": "author", | |||
"name": "John Doe", | |||
}, | |||
"changelog": Array [], | |||
"comment": Array [], | |||
"component": Object { | |||
"breadcrumbs": Array [], | |||
"key": "my-project", | |||
@@ -1098,6 +1275,20 @@ exports[`should render correctly: unassigned 1`] = ` | |||
"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", | |||
}, | |||
], | |||
} | |||
} | |||
/> | |||
@@ -1125,19 +1316,22 @@ exports[`should render correctly: user logged in 1`] = ` | |||
<HotspotActions | |||
hotspot={ | |||
Object { | |||
"assignee": Object { | |||
"assignee": "assignee", | |||
"assigneeUser": Object { | |||
"active": true, | |||
"local": true, | |||
"login": "john.doe", | |||
"login": "assignee", | |||
"name": "John Doe", | |||
}, | |||
"author": Object { | |||
"author": "author", | |||
"authorUser": Object { | |||
"active": true, | |||
"local": true, | |||
"login": "john.doe", | |||
"login": "author", | |||
"name": "John Doe", | |||
}, | |||
"changelog": Array [], | |||
"comment": Array [], | |||
"component": Object { | |||
"breadcrumbs": Array [], | |||
"key": "my-project", | |||
@@ -1202,6 +1396,20 @@ exports[`should render correctly: user logged in 1`] = ` | |||
"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", | |||
}, | |||
], | |||
} | |||
} | |||
onSubmit={[MockFunction]} | |||
@@ -1248,19 +1456,22 @@ exports[`should render correctly: user logged in 1`] = ` | |||
<HotspotSnippetContainer | |||
hotspot={ | |||
Object { | |||
"assignee": Object { | |||
"assignee": "assignee", | |||
"assigneeUser": Object { | |||
"active": true, | |||
"local": true, | |||
"login": "john.doe", | |||
"login": "assignee", | |||
"name": "John Doe", | |||
}, | |||
"author": Object { | |||
"author": "author", | |||
"authorUser": Object { | |||
"active": true, | |||
"local": true, | |||
"login": "john.doe", | |||
"login": "author", | |||
"name": "John Doe", | |||
}, | |||
"changelog": Array [], | |||
"comment": Array [], | |||
"component": Object { | |||
"breadcrumbs": Array [], | |||
"key": "my-project", | |||
@@ -1325,25 +1536,42 @@ exports[`should render correctly: user logged in 1`] = ` | |||
"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", | |||
}, | |||
], | |||
} | |||
} | |||
/> | |||
<HotspotViewerTabs | |||
hotspot={ | |||
Object { | |||
"assignee": Object { | |||
"assignee": "assignee", | |||
"assigneeUser": Object { | |||
"active": true, | |||
"local": true, | |||
"login": "john.doe", | |||
"login": "assignee", | |||
"name": "John Doe", | |||
}, | |||
"author": Object { | |||
"author": "author", | |||
"authorUser": Object { | |||
"active": true, | |||
"local": true, | |||
"login": "john.doe", | |||
"login": "author", | |||
"name": "John Doe", | |||
}, | |||
"changelog": Array [], | |||
"comment": Array [], | |||
"component": Object { | |||
"breadcrumbs": Array [], | |||
"key": "my-project", | |||
@@ -1408,6 +1636,20 @@ exports[`should render correctly: user logged in 1`] = ` | |||
"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", | |||
}, | |||
], | |||
} | |||
} | |||
/> |
@@ -2,7 +2,9 @@ | |||
exports[`should render correctly 1`] = ` | |||
<Fragment> | |||
<div> | |||
<div | |||
className="padded" | |||
> | |||
<div | |||
className="display-flex-center" | |||
> | |||
@@ -31,7 +33,9 @@ exports[`should render correctly 1`] = ` | |||
</div> | |||
</div> | |||
<hr /> | |||
<div> | |||
<div | |||
className="padded" | |||
> | |||
<div | |||
className="display-flex-center" | |||
> | |||
@@ -59,7 +63,9 @@ exports[`should render correctly 1`] = ` | |||
</div> | |||
</div> | |||
<hr /> | |||
<div> | |||
<div | |||
className="padded" | |||
> | |||
<div | |||
className="display-flex-center" | |||
> | |||
@@ -69,7 +75,9 @@ exports[`should render correctly 1`] = ` | |||
</div> | |||
</div> | |||
<hr /> | |||
<div> | |||
<div | |||
className="padded" | |||
> | |||
<div | |||
className="display-flex-center" | |||
> | |||
@@ -101,7 +109,7 @@ exports[`should render correctly 1`] = ` | |||
"oldValue": "old", | |||
} | |||
} | |||
key="test-old-new" | |||
key="0" | |||
/> | |||
<IssueChangelogDiff | |||
diff={ | |||
@@ -111,9 +119,47 @@ exports[`should render correctly 1`] = ` | |||
"oldValue": "old-1", | |||
} | |||
} | |||
key="test-1-old-1-new-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 | |||
</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> | |||
</Fragment> | |||
`; |
@@ -26,7 +26,8 @@ exports[`should render correctly: empty tab 1`] = ` | |||
"type": 0, | |||
"user": Object { | |||
"active": true, | |||
"avatar": undefined, | |||
"local": true, | |||
"login": "author", | |||
"name": "John Doe", | |||
}, | |||
}, | |||
@@ -49,10 +50,10 @@ exports[`should render correctly: empty tab 1`] = ` | |||
} | |||
/> | |||
<div | |||
className="boxed-group big-padded" | |||
className="bordered" | |||
> | |||
<div | |||
className="markdown" | |||
className="markdown big-padded" | |||
dangerouslySetInnerHTML={ | |||
Object { | |||
"__html": "<p>This a <strong>strong</strong> message about vulnerability !</p>", | |||
@@ -94,7 +95,8 @@ exports[`should render correctly: fix 1`] = ` | |||
"type": 0, | |||
"user": Object { | |||
"active": true, | |||
"avatar": undefined, | |||
"local": true, | |||
"login": "author", | |||
"name": "John Doe", | |||
}, | |||
}, | |||
@@ -117,10 +119,10 @@ exports[`should render correctly: fix 1`] = ` | |||
} | |||
/> | |||
<div | |||
className="boxed-group big-padded" | |||
className="bordered" | |||
> | |||
<div | |||
className="markdown" | |||
className="markdown big-padded" | |||
dangerouslySetInnerHTML={ | |||
Object { | |||
"__html": "<p>This a <strong>strong</strong> message about fixing !</p>", | |||
@@ -164,7 +166,8 @@ exports[`should render correctly: review 1`] = ` | |||
"type": 0, | |||
"user": Object { | |||
"active": true, | |||
"avatar": undefined, | |||
"local": true, | |||
"login": "author", | |||
"name": "John Doe", | |||
}, | |||
}, | |||
@@ -187,7 +190,7 @@ exports[`should render correctly: review 1`] = ` | |||
} | |||
/> | |||
<div | |||
className="boxed-group big-padded" | |||
className="bordered" | |||
> | |||
<HotspotViewerReviewHistoryTab | |||
history={ | |||
@@ -197,7 +200,8 @@ exports[`should render correctly: review 1`] = ` | |||
"type": 0, | |||
"user": Object { | |||
"active": true, | |||
"avatar": undefined, | |||
"local": true, | |||
"login": "author", | |||
"name": "John Doe", | |||
}, | |||
}, | |||
@@ -239,7 +243,8 @@ exports[`should render correctly: risk 1`] = ` | |||
"type": 0, | |||
"user": Object { | |||
"active": true, | |||
"avatar": undefined, | |||
"local": true, | |||
"login": "author", | |||
"name": "John Doe", | |||
}, | |||
}, | |||
@@ -262,10 +267,10 @@ exports[`should render correctly: risk 1`] = ` | |||
} | |||
/> | |||
<div | |||
className="boxed-group big-padded" | |||
className="bordered" | |||
> | |||
<div | |||
className="markdown" | |||
className="markdown big-padded" | |||
dangerouslySetInnerHTML={ | |||
Object { | |||
"__html": "<p>This a <strong>strong</strong> message about risk !</p>", | |||
@@ -307,7 +312,8 @@ exports[`should render correctly: vulnerability 1`] = ` | |||
"type": 0, | |||
"user": Object { | |||
"active": true, | |||
"avatar": undefined, | |||
"local": true, | |||
"login": "author", | |||
"name": "John Doe", | |||
}, | |||
}, | |||
@@ -330,10 +336,10 @@ exports[`should render correctly: vulnerability 1`] = ` | |||
} | |||
/> | |||
<div | |||
className="boxed-group big-padded" | |||
className="bordered" | |||
> | |||
<div | |||
className="markdown" | |||
className="markdown big-padded" | |||
dangerouslySetInnerHTML={ | |||
Object { | |||
"__html": "<p>This a <strong>strong</strong> message about vulnerability !</p>", |
@@ -89,27 +89,40 @@ export function getHotspotReviewHistory(hotspot: Hotspot): ReviewHistoryElement[ | |||
type: ReviewHistoryType.Creation, | |||
date: hotspot.creationDate, | |||
user: { | |||
avatar: hotspot.author.avatar, | |||
name: hotspot.author.name || hotspot.author.login, | |||
active: hotspot.author.active | |||
...hotspot.authorUser, | |||
name: hotspot.authorUser.name || hotspot.authorUser.login | |||
} | |||
}); | |||
} | |||
if (hotspot.changelog) { | |||
if (hotspot.changelog && hotspot.changelog.length > 0) { | |||
history.push( | |||
...hotspot.changelog.map(log => ({ | |||
type: ReviewHistoryType.Diff, | |||
date: log.creationDate, | |||
user: { | |||
active: log.isUserActive, | |||
avatar: log.avatar, | |||
name: log.userName || log.user, | |||
active: log.isUserActive | |||
name: log.userName || log.user | |||
}, | |||
diffs: log.diffs | |||
})) | |||
); | |||
} | |||
if (hotspot.comment && hotspot.comment.length > 0) { | |||
history.push( | |||
...hotspot.comment.map(comment => ({ | |||
type: ReviewHistoryType.Comment, | |||
date: comment.createdAt, | |||
user: { | |||
...comment.user, | |||
name: comment.user.name || comment.user.login | |||
}, | |||
html: comment.htmlText | |||
})) | |||
); | |||
} | |||
return sortBy(history, elt => elt.date); | |||
} |
@@ -50,10 +50,15 @@ export function mockRawHotspot(overrides: Partial<RawHotspot> = {}): RawHotspot | |||
} | |||
export function mockHotspot(overrides?: Partial<Hotspot>): Hotspot { | |||
const assigneeUser = mockUser({ login: 'assignee' }); | |||
const authorUser = mockUser({ login: 'author' }); | |||
return { | |||
assignee: mockUser(), | |||
author: mockUser(), | |||
assignee: 'assignee', | |||
assigneeUser, | |||
author: 'author', | |||
authorUser, | |||
changelog: [], | |||
comment: [], | |||
component: mockComponent({ qualifier: ComponentQualifier.File }), | |||
creationDate: '2013-05-13T17:55:41+0200', | |||
key: '01fc972e-2a3c-433e-bcae-0bd7f88f5123', | |||
@@ -70,6 +75,7 @@ export function mockHotspot(overrides?: Partial<Hotspot>): Hotspot { | |||
endOffset: 83 | |||
}, | |||
updateDate: '2013-05-13T17:55:42+0200', | |||
users: [assigneeUser, authorUser], | |||
...overrides | |||
}; | |||
} |
@@ -69,9 +69,12 @@ export interface RawHotspot { | |||
} | |||
export interface Hotspot { | |||
assignee?: Pick<T.UserBase, 'active' | 'login' | 'name'>; | |||
author: Pick<T.UserBase, 'active' | 'avatar' | 'login' | 'name'>; | |||
changelog?: T.IssueChangelog[]; | |||
assignee?: string; | |||
assigneeUser?: T.UserBase; | |||
author: string; | |||
authorUser: T.UserBase; | |||
changelog: T.IssueChangelog[]; | |||
comment: HotspotComment[]; | |||
component: T.Component; | |||
creationDate: string; | |||
key: string; | |||
@@ -83,6 +86,7 @@ export interface Hotspot { | |||
status: string; | |||
textRange: T.TextRange; | |||
updateDate: string; | |||
users: T.UserBase[]; | |||
} | |||
export interface HotspotUpdateFields { | |||
@@ -104,16 +108,28 @@ export interface HotspotRule { | |||
vulnerabilityProbability: RiskExposure; | |||
} | |||
export interface HotspotComment { | |||
key: string; | |||
htmlText: string; | |||
markdown: string; | |||
updatable: boolean; | |||
createdAt: string; | |||
login: string; | |||
user: T.UserBase; | |||
} | |||
export interface ReviewHistoryElement { | |||
type: ReviewHistoryType; | |||
date: string; | |||
user: Pick<T.UserBase, 'active' | 'avatar' | 'name'>; | |||
diffs?: T.IssueChangelogDiff[]; | |||
html?: string; | |||
} | |||
export enum ReviewHistoryType { | |||
Creation, | |||
Diff | |||
Diff, | |||
Comment | |||
} | |||
export interface HotspotSearchResponse { |
@@ -661,6 +661,7 @@ hotspots.tabs.vulnerability_description=Are you vulnerable? | |||
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 a comment | |||
hotspot.change_status.REVIEWED=Change status | |||
hotspot.change_status.TO_REVIEW=Review Hotspot |