Skip to content

Commit d465e37

Browse files
committed
improve UI
1 parent 4a1a2b9 commit d465e37

File tree

3 files changed

+107
-34
lines changed

3 files changed

+107
-34
lines changed

src/main/kotlin/com/github/adrienpessu/sarifviewer/models/Leaf.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,6 @@ data class Leaf(
2222
else -> ""
2323
}
2424

25-
return "$icon $address"
25+
return "$icon ${address.split("/").last()} $ruleDescription"
2626
}
2727
}

src/main/kotlin/com/github/adrienpessu/sarifviewer/toolWindow/SarifViewerWindowFactory.kt

Lines changed: 51 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ import com.github.adrienpessu.sarifviewer.models.Leaf
1313
import com.github.adrienpessu.sarifviewer.models.View
1414
import com.github.adrienpessu.sarifviewer.services.SarifService
1515
import com.github.adrienpessu.sarifviewer.utils.GitHubInstance
16-
import com.intellij.icons.AllIcons
1716
import com.intellij.notification.NotificationGroupManager
1817
import com.intellij.notification.NotificationType
1918
import com.intellij.openapi.actionSystem.ActionManager
@@ -38,16 +37,15 @@ import com.intellij.ui.awt.RelativePoint
3837
import com.intellij.ui.components.JBPanel
3938
import com.intellij.ui.components.JBTabbedPane
4039
import com.intellij.ui.content.ContentFactory
40+
import com.intellij.ui.table.JBTable
4141
import git4idea.GitLocalBranch
4242
import git4idea.repo.GitRepository
4343
import git4idea.repo.GitRepositoryChangeListener
4444
import git4idea.repo.GitRepositoryManager
4545
import java.awt.Component
46-
import java.awt.Desktop
4746
import java.awt.Dimension
4847
import java.awt.event.ActionListener
4948
import java.io.File
50-
import java.net.URI
5149
import java.nio.charset.Charset
5250
import java.nio.file.Files
5351
import java.nio.file.Path
@@ -57,6 +55,7 @@ import javax.swing.event.HyperlinkListener
5755
import javax.swing.event.TreeSelectionEvent
5856
import javax.swing.event.TreeSelectionListener
5957
import javax.swing.filechooser.FileNameExtensionFilter
58+
import javax.swing.table.DefaultTableModel
6059
import javax.swing.text.html.HTMLEditorKit
6160
import javax.swing.tree.DefaultMutableTreeNode
6261
import javax.swing.tree.DefaultTreeModel
@@ -86,37 +85,33 @@ class SarifViewerWindowFactory : ToolWindowFactory {
8685
(openLocalFileAction as OpenLocalAction).myToolWindow = this
8786
val refreshAction = actionManager.getAction("RefreshAction")
8887
(refreshAction as RefreshAction).myToolWindow = this
89-
val actions = ArrayList<AnAction>();
88+
val actions = ArrayList<AnAction>()
9089
actions.add(openLocalFileAction)
9190
actions.add(refreshAction)
9291

9392
toolWindow.setTitleActions(actions)
9493
}
9594

9695
internal var github: GitHubInstance? = null
97-
get() = field
9896
internal var repositoryFullName: String? = null
99-
get() = field
10097
internal var currentBranch: GitLocalBranch? = null
101-
get() = field
10298

10399
private var localMode = false
104100
private val service = toolWindow.project.service<SarifService>()
105101
private val project = toolWindow.project
106102
private var main = ScrollPaneFactory.createScrollPane()
107103
private val details = JBTabbedPane()
108104
private val splitPane = JSplitPane(JSplitPane.VERTICAL_SPLIT, false, main, details)
109-
private var myList = JTree()
105+
private var myList = com.intellij.ui.treeStructure.Tree()
110106
private var comboBranchPR = ComboBox(arrayOf(BranchItemComboBox(0, "main", "", "")))
111-
private val infos = JEditorPane()
107+
private val tableInfos = JBTable(DefaultTableModel(arrayOf<Any>("Property", "Value"), 0))
112108
private val steps = JEditorPane()
113109
private val errorField = JLabel("Error message here ")
114110
private val errorToolbar = JToolBar("", JToolBar.HORIZONTAL)
115111
private val loadingPanel = JPanel()
116112
private var sarifGitHubRef = ""
117113
private var loading = false
118114
private var disableComboBoxEvent = false
119-
private val views = View.views
120115
private var currentView = View.RULE
121116
private var cacheSarif: SarifSchema210? = null
122117

@@ -263,14 +258,14 @@ class SarifViewerWindowFactory : ToolWindowFactory {
263258
}
264259

265260
private fun JBPanel<JBPanel<*>>.buildSkeleton() {
266-
infos.isEditable = false
267-
infos.addHyperlinkListener(object : HyperlinkListener {
268-
override fun hyperlinkUpdate(hle: HyperlinkEvent?) {
269-
if (HyperlinkEvent.EventType.ACTIVATED == hle?.eventType && hle?.description != null) {
270-
Desktop.getDesktop().browse(URI(hle.description))
271-
}
272-
}
273-
})
261+
262+
// infos.addHyperlinkListener(object : HyperlinkListener {
263+
// override fun hyperlinkUpdate(hle: HyperlinkEvent?) {
264+
// if (HyperlinkEvent.EventType.ACTIVATED == hle?.eventType && hle?.description != null) {
265+
// Desktop.getDesktop().browse(URI(hle.description))
266+
// }
267+
// }
268+
// })
274269
steps.isEditable = false
275270
steps.addHyperlinkListener(object : HyperlinkListener {
276271
override fun hyperlinkUpdate(hle: HyperlinkEvent?) {
@@ -282,7 +277,10 @@ class SarifViewerWindowFactory : ToolWindowFactory {
282277
}
283278
})
284279

285-
details.addTab("Infos", infos)
280+
// Add the table to a scroll pane
281+
val scrollPane = JScrollPane(tableInfos)
282+
283+
details.addTab("Infos", scrollPane)
286284
details.addTab("Steps", steps)
287285

288286
layout = BoxLayout(this, BoxLayout.Y_AXIS)
@@ -436,17 +434,18 @@ class SarifViewerWindowFactory : ToolWindowFactory {
436434
val root = DefaultMutableTreeNode(project.name)
437435

438436
map.forEach { (key, value) ->
439-
val ruleNode = DefaultMutableTreeNode(key)
437+
val ruleNode = DefaultMutableTreeNode("$key (${value.size})")
440438
value.forEach { location ->
441439
val locationNode = DefaultMutableTreeNode(location)
442440
ruleNode.add(locationNode)
443441
}
444442
root.add(ruleNode)
445443
}
446444

447-
myList = JTree(root)
445+
myList = com.intellij.ui.treeStructure.Tree(root)
448446

449447
myList.isRootVisible = false
448+
myList.showsRootHandles = true
450449
main = ScrollPaneFactory.createScrollPane(myList)
451450

452451
details.isVisible = false
@@ -457,7 +456,7 @@ class SarifViewerWindowFactory : ToolWindowFactory {
457456
myList.addTreeSelectionListener(object : TreeSelectionListener {
458457
override fun valueChanged(e: TreeSelectionEvent?) {
459458
if (e != null && e.isAddedPath) {
460-
val leaves = map[e.path.parentPath.lastPathComponent.toString()]
459+
val leaves = map[e.path.parentPath.lastPathComponent.toString().split(" ").first()]
461460
if (!leaves.isNullOrEmpty()) {
462461
val leaf = try {
463462
leaves.first { it.address == ((e.path.lastPathComponent as DefaultMutableTreeNode).userObject as Leaf).address }
@@ -470,15 +469,31 @@ class SarifViewerWindowFactory : ToolWindowFactory {
470469
.replace("api/v3/", "")
471470
.replace("repos/", "")
472471
.replace("code-scanning/alerts", "security/code-scanning")
473-
val githubURL = "<a target=\"_BLANK\" href=\"$githubAlertUrl\">$githubAlertUrl</a>"
474-
475-
infos.contentType = "text/html"
476-
477-
infos.text =
478-
"${leaf.leafName} <br/> Level: ${leaf.level} <br/>Rule's name: ${leaf.ruleName} <br/>Rule's description ${leaf.ruleDescription} <br/>Location ${leaf.location} <br/>GitHub alert number: ${leaf.githubAlertNumber} <br/>GitHub alert url ${githubURL}\n"
479472

480-
steps.read(leaf.steps.joinToString("<br/>") { step ->
481-
"<a href=\"$step\">${step.split("/").last()}</a>"
473+
tableInfos.clearSelection()
474+
// Create a table model with "Property" and "Value" columns
475+
val defaultTableModel: DefaultTableModel =
476+
object : DefaultTableModel(arrayOf<Any>("Property", "Value"), 0) {
477+
override fun isCellEditable(row: Int, column: Int): Boolean {
478+
return false
479+
}
480+
}
481+
tableInfos.model = defaultTableModel
482+
// Set a custom cell renderer for the "Value" column
483+
tableInfos.columnModel.getColumn(1).setCellRenderer(UrlCellRenderer())
484+
485+
// Add some data
486+
defaultTableModel.addRow(arrayOf<Any>("Name", leaf.leafName))
487+
defaultTableModel.addRow(arrayOf<Any>("Level", leaf.level))
488+
defaultTableModel.addRow(arrayOf<Any>("Rule's name", leaf.ruleName))
489+
defaultTableModel.addRow(arrayOf<Any>("Rule's description", leaf.ruleDescription))
490+
defaultTableModel.addRow(arrayOf<Any>("Location", leaf.location))
491+
defaultTableModel.addRow(arrayOf<Any>("GitHub alert number", leaf.githubAlertNumber))
492+
defaultTableModel.addRow(arrayOf<Any>("GitHub alert url", githubAlertUrl))
493+
tableInfos.updateUI()
494+
495+
steps.read(leaf.steps.joinToString(" ", "<ul>", "</ul>") { step ->
496+
"<li><a href=\"$step\">${step.split("/").last()}</a></li>"
482497
}.byteInputStream(Charset.defaultCharset()), HTMLEditorKit::class.java)
483498

484499
steps.contentType = "text/html"
@@ -571,7 +586,8 @@ class SarifViewerWindowFactory : ToolWindowFactory {
571586
}
572587
}
573588

574-
infos.text = ""
589+
tableInfos.clearSelection()
590+
tableInfos.updateUI()
575591
steps.text = ""
576592
details.isVisible = false
577593
errorToolbar.isVisible = false
@@ -592,8 +608,10 @@ class SarifViewerWindowFactory : ToolWindowFactory {
592608
val mainResults: List<Result> = sarifMainBranch.flatMap { it.runs?.get(0)?.results ?: emptyList() }
593609

594610
for (currentResult in results) {
595-
if (mainResults.none { it.ruleId == currentResult.ruleId
596-
&& ("${currentResult.locations[0].physicalLocation.artifactLocation.uri}:${currentResult.locations[0].physicalLocation.region.startLine}" == "${it.locations[0].physicalLocation.artifactLocation.uri}:${it.locations[0].physicalLocation.region.startLine}") }) {
611+
if (mainResults.none {
612+
it.ruleId == currentResult.ruleId
613+
&& ("${currentResult.locations[0].physicalLocation.artifactLocation.uri}:${currentResult.locations[0].physicalLocation.region.startLine}" == "${it.locations[0].physicalLocation.artifactLocation.uri}:${it.locations[0].physicalLocation.region.startLine}")
614+
}) {
597615
resultsToDisplay.add(currentResult)
598616
}
599617
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
package com.github.adrienpessu.sarifviewer.toolWindow
2+
3+
import java.awt.Color
4+
import java.awt.Component
5+
import java.awt.Cursor
6+
import java.awt.Desktop
7+
import java.awt.event.MouseAdapter
8+
import java.awt.event.MouseEvent
9+
import java.net.URI
10+
import java.net.URISyntaxException
11+
import javax.swing.JLabel
12+
import javax.swing.JTable
13+
import javax.swing.table.TableCellRenderer
14+
15+
class UrlCellRenderer : JLabel(), TableCellRenderer {
16+
override fun getTableCellRendererComponent(
17+
table: JTable,
18+
value: Any,
19+
isSelected: Boolean,
20+
hasFocus: Boolean,
21+
row: Int,
22+
column: Int
23+
): Component {
24+
25+
if (value.toString().startsWith("http")) {
26+
text = "<html><a href=''>$value</a></html>"
27+
toolTipText = value.toString()
28+
29+
// Check if the value is a URL
30+
try {
31+
val uri = URI(value.toString())
32+
cursor = Cursor(Cursor.HAND_CURSOR)
33+
34+
addMouseListener(object : MouseAdapter() {
35+
override fun mouseClicked(e: MouseEvent) {
36+
if (Desktop.isDesktopSupported()) {
37+
Desktop.getDesktop().browse(uri)
38+
}
39+
}
40+
})
41+
42+
foreground = Color.BLUE
43+
} catch (e: URISyntaxException) {
44+
cursor = Cursor(Cursor.DEFAULT_CURSOR)
45+
}
46+
47+
return this
48+
} else {
49+
text = value.toString()
50+
cursor = Cursor(Cursor.DEFAULT_CURSOR)
51+
}
52+
53+
return this
54+
}
55+
}

0 commit comments

Comments
 (0)