Skip to content

Commit

Permalink
feat: display up to 70 chars of file path in tree view for file nodes
Browse files Browse the repository at this point in the history
  • Loading branch information
bastiandoetsch committed Sep 22, 2023
1 parent 97aeb0c commit 35a1965
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package io.snyk.plugin.ui.toolwindow

import ai.deepcode.javaclient.core.SuggestionForFile
import com.intellij.icons.AllIcons
import com.intellij.ide.util.gotoByName.GotoFileCellRenderer
import com.intellij.openapi.util.Iconable
import com.intellij.ui.ColoredTreeCellRenderer
import com.intellij.ui.SimpleTextAttributes
Expand All @@ -18,14 +19,11 @@ import io.snyk.plugin.ui.getDisabledIcon
import io.snyk.plugin.ui.snykCodeAvailabilityPostfix
import io.snyk.plugin.ui.toolwindow.nodes.leaf.SuggestionTreeNode
import io.snyk.plugin.ui.toolwindow.nodes.leaf.VulnerabilityTreeNode
import io.snyk.plugin.ui.toolwindow.nodes.root.RootContainerIssuesTreeNode
import io.snyk.plugin.ui.toolwindow.nodes.root.RootIacIssuesTreeNode
import io.snyk.plugin.ui.toolwindow.nodes.root.RootOssTreeNode
import io.snyk.plugin.ui.toolwindow.nodes.root.RootQualityIssuesTreeNode
import io.snyk.plugin.ui.toolwindow.nodes.root.RootSecurityIssuesTreeNode
import io.snyk.plugin.ui.toolwindow.nodes.root.*
import io.snyk.plugin.ui.toolwindow.nodes.secondlevel.ErrorTreeNode
import io.snyk.plugin.ui.toolwindow.nodes.secondlevel.FileTreeNode
import io.snyk.plugin.ui.toolwindow.nodes.secondlevel.SnykCodeFileTreeNode
import org.jetbrains.kotlin.idea.base.util.letIf
import snyk.common.ProductType
import snyk.common.SnykError
import snyk.container.ContainerIssue
Expand All @@ -38,11 +36,14 @@ import snyk.iac.ui.toolwindow.IacFileTreeNode
import snyk.iac.ui.toolwindow.IacIssueTreeNode
import snyk.oss.OssVulnerabilitiesForFile
import snyk.oss.Vulnerability
import java.util.Locale
import java.util.*
import javax.swing.Icon
import javax.swing.JTree

private const val MAX_FILE_TREE_NODE_LENGTH = 70

class SnykTreeCellRenderer : ColoredTreeCellRenderer() {
@Suppress("UNCHECKED_CAST")
override fun customizeCellRenderer(
tree: JTree,
value: Any,
Expand All @@ -68,10 +69,19 @@ class SnykTreeCellRenderer : ColoredTreeCellRenderer() {
nodeIcon = getDisabledIcon(nodeIcon)
}
}

is FileTreeNode -> {
val fileVulns = value.userObject as OssVulnerabilitiesForFile
nodeIcon = PackageManagerIconProvider.getIcon(fileVulns.packageManager.lowercase(Locale.getDefault()))
text = fileVulns.sanitizedTargetFile + ProductType.OSS.getCountText(value.childCount)
toolTipText = GotoFileCellRenderer.getRelativePath(fileVulns.virtualFile, value.project) +
fileVulns.sanitizedTargetFile + ProductType.OSS.getCountText(value.childCount)

text = toolTipText.letIf(toolTipText.length > MAX_FILE_TREE_NODE_LENGTH) {
"..." + it.substring(
it.length - 47,
it.length
)
}

val snykCachedResults = getSnykCachedResults(value.project)
if (snykCachedResults?.currentOssResults == null) {
Expand All @@ -80,6 +90,7 @@ class SnykTreeCellRenderer : ColoredTreeCellRenderer() {
nodeIcon = getDisabledIcon(nodeIcon)
}
}

is SuggestionTreeNode -> {
val (suggestion, index) = value.userObject as Pair<SuggestionForFile, Int>
nodeIcon = SnykIcons.getSeverityIcon(suggestion.getSeverityAsEnum())
Expand All @@ -94,9 +105,21 @@ class SnykTreeCellRenderer : ColoredTreeCellRenderer() {
nodeIcon = getDisabledIcon(nodeIcon)
}
}

is SnykCodeFileTreeNode -> {
val (file, productType) = value.userObject as Pair<SnykCodeFile, ProductType>
text = PDU.toSnykCodeFile(file).virtualFile.name + productType.getCountText(value.childCount)
toolTipText =
GotoFileCellRenderer.getRelativePath(file.virtualFile, file.project) + productType.getCountText(
value.childCount
)

text = toolTipText.letIf(toolTipText.length > MAX_FILE_TREE_NODE_LENGTH) {
"..." + it.substring(
it.length - 47,
it.length
)
}

val psiFile = PDU.toPsiFile(file)
nodeIcon = psiFile?.getIcon(Iconable.ICON_FLAG_READ_STATUS)
if (!AnalysisData.instance.isFileInCache(file)) {
Expand All @@ -105,12 +128,24 @@ class SnykTreeCellRenderer : ColoredTreeCellRenderer() {
nodeIcon = getDisabledIcon(nodeIcon)
}
}

is IacFileTreeNode -> {
val iacVulnerabilitiesForFile = value.userObject as IacIssuesForFile
nodeIcon = PackageManagerIconProvider.getIcon(
iacVulnerabilitiesForFile.packageManager.lowercase(Locale.getDefault())
)
text = iacVulnerabilitiesForFile.targetFile + ProductType.IAC.getCountText(value.childCount)
toolTipText = GotoFileCellRenderer.getRelativePath(
iacVulnerabilitiesForFile.virtualFile,
value.project
) + ProductType.IAC.getCountText(value.childCount)

text = toolTipText.letIf(toolTipText.length > MAX_FILE_TREE_NODE_LENGTH) {
"..." + it.substring(
it.length - 47,
it.length
)
}


val snykCachedResults = getSnykCachedResults(value.project)
if (snykCachedResults?.currentIacResult == null || iacVulnerabilitiesForFile.obsolete) {
Expand All @@ -119,6 +154,7 @@ class SnykTreeCellRenderer : ColoredTreeCellRenderer() {
text += obsoleteSuffix
}
}

is ContainerImageTreeNode -> {
val issuesForImage = value.userObject as ContainerIssuesForImage
nodeIcon = SnykIcons.CONTAINER_IMAGE
Expand All @@ -131,11 +167,13 @@ class SnykTreeCellRenderer : ColoredTreeCellRenderer() {
text += obsoleteSuffix
}
}

is ErrorTreeNode -> {
val snykError = value.userObject as SnykError
text = snykError.path + " - " + snykError.message
nodeIcon = AllIcons.General.Error
}

is IacIssueTreeNode -> {
val issue = (value.userObject as IacIssue)
val snykCachedResults = getSnykCachedResults(value.project)
Expand All @@ -151,6 +189,7 @@ class SnykTreeCellRenderer : ColoredTreeCellRenderer() {
nodeIcon = getDisabledIcon(nodeIcon)
}
}

is ContainerIssueTreeNode -> {
val issue = value.userObject as ContainerIssue
val snykCachedResults = getSnykCachedResults(value.project)
Expand All @@ -165,6 +204,7 @@ class SnykTreeCellRenderer : ColoredTreeCellRenderer() {
nodeIcon = getDisabledIcon(nodeIcon)
}
}

is RootOssTreeNode -> {
val settings = pluginSettings()
if (settings.ossScanEnable && settings.treeFiltering.ossResults) {
Expand All @@ -180,6 +220,7 @@ class SnykTreeCellRenderer : ColoredTreeCellRenderer() {
SnykToolWindowPanel.OSS_ROOT_TEXT + disabledSuffix
}
}

is RootSecurityIssuesTreeNode -> {
val settings = pluginSettings()
if (settings.snykCodeSecurityIssuesScanEnable && settings.treeFiltering.codeSecurityResults) {
Expand All @@ -193,9 +234,10 @@ class SnykTreeCellRenderer : ColoredTreeCellRenderer() {
value.userObject.toString()
} else {
SnykToolWindowPanel.CODE_SECURITY_ROOT_TEXT +
snykCodeAvailabilityPostfix().ifEmpty { disabledSuffix }
snykCodeAvailabilityPostfix().ifEmpty { disabledSuffix }
}
}

is RootQualityIssuesTreeNode -> {
val settings = pluginSettings()
if (settings.snykCodeQualityIssuesScanEnable && settings.treeFiltering.codeQualityResults) {
Expand All @@ -209,9 +251,10 @@ class SnykTreeCellRenderer : ColoredTreeCellRenderer() {
value.userObject.toString()
} else {
SnykToolWindowPanel.CODE_QUALITY_ROOT_TEXT +
snykCodeAvailabilityPostfix().ifEmpty { disabledSuffix }
snykCodeAvailabilityPostfix().ifEmpty { disabledSuffix }
}
}

is RootIacIssuesTreeNode -> {
val settings = pluginSettings()
if (settings.iacScanEnabled && settings.treeFiltering.iacResults) {
Expand All @@ -227,6 +270,7 @@ class SnykTreeCellRenderer : ColoredTreeCellRenderer() {
SnykToolWindowPanel.IAC_ROOT_TEXT + disabledSuffix
}
}

is RootContainerIssuesTreeNode -> {
val settings = pluginSettings()
if (settings.containerScanEnabled && settings.treeFiltering.containerResults) {
Expand Down
5 changes: 5 additions & 0 deletions src/main/kotlin/snyk/iac/IacIssuesForFile.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package snyk.iac

import com.intellij.openapi.vfs.LocalFileSystem
import com.intellij.openapi.vfs.VirtualFile

data class IacIssuesForFile(
val infrastructureAsCodeIssues: List<IacIssue>,
val targetFile: String,
Expand All @@ -9,6 +12,8 @@ data class IacIssuesForFile(
val obsolete: Boolean get() = infrastructureAsCodeIssues.any { it.obsolete }
val ignored: Boolean get() = infrastructureAsCodeIssues.all { it.ignored }
val uniqueCount: Int get() = infrastructureAsCodeIssues.groupBy { it.id }.size

val virtualFile: VirtualFile = LocalFileSystem.getInstance().findFileByPath(this.targetFilePath)!!
}

/* Real json Example: src/integTest/resources/iac-test-results/infrastructure-as-code-goof.json */
5 changes: 5 additions & 0 deletions src/main/kotlin/snyk/oss/OssVulnerabilitiesForFile.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package snyk.oss

import com.intellij.openapi.vfs.LocalFileSystem
import com.intellij.openapi.vfs.VirtualFile

data class OssVulnerabilitiesForFile(
val vulnerabilities: List<Vulnerability>,
private val displayTargetFile: String,
Expand All @@ -11,6 +14,8 @@ data class OssVulnerabilitiesForFile(

val sanitizedTargetFile: String get() = displayTargetFile.replace("-lock", "")

val virtualFile: VirtualFile = LocalFileSystem.getInstance().findFileByPath(this.path)!!

fun toGroupedResult(): OssGroupedResult {
val id2vulnerabilities = vulnerabilities.groupBy({ it.id }, { it })
val uniqueCount = id2vulnerabilities.keys.size
Expand Down

0 comments on commit 35a1965

Please sign in to comment.