diff --git a/CHANGELOG.md b/CHANGELOG.md index c76ade112..fef392b7a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Snyk Security - Code and Open Source Dependencies Changelog +## [2.2.0] + +### Added + +- Snyk Code: New UI section `#suggestion-details` for displaying suggestion details in snykCode. +- Snyk Code: Added a collapsible section for suggestion details. This includes a 'Read more' button to toggle the full display of suggestion details. + ## [2.1.0] ### Added diff --git a/media/views/snykCode/suggestion/suggestion.scss b/media/views/snykCode/suggestion/suggestion.scss index dfe2f0c59..25ef6d074 100644 --- a/media/views/snykCode/suggestion/suggestion.scss +++ b/media/views/snykCode/suggestion/suggestion.scss @@ -43,6 +43,43 @@ line-height: 1.6; } +.suggestion-details { + height: auto; + transition: height 400ms ease-out; +} + +.suggestion-details.collapsed { + height: 90px; + overflow: hidden; +} + +.suggestion-details.collapsed p:first-of-type { + display: -webkit-box; + -webkit-line-clamp: 3; + -webkit-box-orient: vertical; +} + +.suggestion-details.collapsed:after { + content: '...'; + float: right; + background: linear-gradient(to left, transparent, white 50%); +} + +.suggestion-details.show { + max-height: none; +} + +.no-padding-top { + padding-top: 0; +} + +.read-more-btn { + background: none; + border: 2px solid var(--vscode-textLink-foreground); + color: var(--vscode-textLink-foreground); + cursor: pointer; +} + .cwe-list { display: inline-block; margin: 0; @@ -231,4 +268,4 @@ .report-fp-actions { margin-left: auto; -} \ No newline at end of file +} diff --git a/src/snyk/snykCode/views/suggestion/codeSuggestionWebviewProvider.ts b/src/snyk/snykCode/views/suggestion/codeSuggestionWebviewProvider.ts index 616ef14f0..4264682b4 100644 --- a/src/snyk/snykCode/views/suggestion/codeSuggestionWebviewProvider.ts +++ b/src/snyk/snykCode/views/suggestion/codeSuggestionWebviewProvider.ts @@ -1,5 +1,6 @@ import he from 'he'; import _ from 'lodash'; +import { marked } from 'marked'; import * as vscode from 'vscode'; import { SNYK_IGNORE_ISSUE_COMMAND, @@ -155,12 +156,14 @@ export class CodeSuggestionWebviewProvider } private mapToModel(issue: Issue): Suggestion { + const parsedDetails = marked.parse(issue.additionalData.text) as string; return { id: issue.id, title: issue.title, uri: issue.filePath, severity: _.capitalize(issue.severity), ...issue.additionalData, + text: parsedDetails, }; } @@ -292,6 +295,14 @@ export class CodeSuggestionWebviewProvider + +
+
+
+
+ +
+
This issue was fixed by projects. Here are examples: diff --git a/src/snyk/snykCode/views/suggestion/codeSuggestionWebviewScript.ts b/src/snyk/snykCode/views/suggestion/codeSuggestionWebviewScript.ts index 843da0291..d15eb5ba1 100644 --- a/src/snyk/snykCode/views/suggestion/codeSuggestionWebviewScript.ts +++ b/src/snyk/snykCode/views/suggestion/codeSuggestionWebviewScript.ts @@ -58,6 +58,8 @@ declare const acquireVsCodeApi: any; const vscode = acquireVsCodeApi(); + let isReadMoreBtnEventBound = false; + function navigateToUrl(url: string) { sendMessage({ type: 'openBrowser', @@ -185,6 +187,8 @@ declare const acquireVsCodeApi: any; return; } + showSuggestionDetails(suggestion); + exampleCount = 0; const currentSeverity = getCurrentSeverity(); const severity = document.getElementById('severity')!; @@ -316,6 +320,35 @@ declare const acquireVsCodeApi: any; } } + function showSuggestionDetails(suggestion: Suggestion) { + const suggestionDetails = document.querySelector('#suggestion-details') as HTMLElement; + const readMoreBtn = document.querySelector('.read-more-btn') as HTMLElement; + + if (!suggestion || !suggestion.text || !suggestionDetails || !readMoreBtn) { + return; + } + + suggestionDetails.innerHTML = suggestion.text; + suggestionDetails.classList.add('collapsed'); + + readMoreBtn.style.display = 'block'; + + if (!isReadMoreBtnEventBound) { + readMoreBtn.addEventListener('click', () => { + const isCollapsed = suggestionDetails.classList.contains('collapsed'); + + if (isCollapsed) { + suggestionDetails.classList.remove('collapsed'); + readMoreBtn.textContent = 'Read less'; + } else { + suggestionDetails.classList.add('collapsed'); + readMoreBtn.textContent = 'Read more'; + } + }); + isReadMoreBtnEventBound = true; + } + } + function sendMessage(message: { type: string; args: