Skip to content

Commit a3cb5cd

Browse files
authored
CM-33449 - Add Action Toolbar (#55)
1 parent 626f935 commit a3cb5cd

File tree

17 files changed

+365
-23
lines changed

17 files changed

+365
-23
lines changed

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,10 @@
44

55
## [Unreleased]
66

7-
## [1.5.0] - 2024-03-XX
7+
## [1.5.0] - 2024-03-13
88

99
- Add SCA Violation Card
10+
- Add action toolbar to the Cycode tab
1011
- Add the on-demand scan of an entire project for Secrets
1112

1213
## [1.4.0] - 2024-02-28

src/main/kotlin/com/cycode/plugin/components/toolWindow/CycodeContentTab.kt

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,20 @@ package com.cycode.plugin.components.toolWindow
22

33
import com.cycode.plugin.components.toolWindow.components.treeView.TreeView
44
import com.intellij.openapi.project.Project
5+
import com.intellij.openapi.ui.SimpleToolWindowPanel
56
import javax.swing.JPanel
67

7-
class CycodeContentTab(project: Project) {
8+
class CycodeContentTab(project: Project) : SimpleToolWindowPanel(false, false) {
89
private val treeView = TreeView(project)
910

11+
init {
12+
setContent(treeView)
13+
}
14+
1015
fun updateContent(rightPanel: JPanel): JPanel {
1116
treeView.refreshTree()
1217
return treeView.replaceRightPanel(rightPanel)
1318
}
19+
20+
fun getTreeView() = treeView
1421
}

src/main/kotlin/com/cycode/plugin/components/toolWindow/CycodeToolWindowFactory.kt

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.cycode.plugin.components.toolWindow
22

33
import com.cycode.plugin.components.toolWindow.components.authContentTab.AuthContentTab
4+
import com.cycode.plugin.components.toolWindow.components.cycodeActionToolBar.CycodeActionToolbar
45
import com.cycode.plugin.components.toolWindow.components.loadingContentTab.LoadingContentTab
56
import com.cycode.plugin.components.toolWindow.components.scanContentTab.ScanContentTab
67
import com.cycode.plugin.icons.PluginIcons
@@ -30,8 +31,12 @@ class CycodeToolWindowFactory : DumbAware, ToolWindowFactory {
3031
val contentTab = CycodeContentTab(project)
3132
TabManager.addTab(project, contentTab)
3233

34+
CycodeActionToolbar().attachActionToolbar(contentTab)
35+
3336
val initRightPanel = getRightPanelDependingOnState(project)
34-
val toolWindowContent = createToolWindowContent(contentTab.updateContent(initRightPanel))
37+
contentTab.updateContent(initRightPanel)
38+
39+
val toolWindowContent = createToolWindowContent(contentTab)
3540
toolWindow.contentManager.addContent(toolWindowContent)
3641

3742
Disposer.register(service, toolWindowContent)
@@ -66,7 +71,7 @@ private fun createToolWindowContent(component: JPanel): Content {
6671
return ContentFactory.SERVICE.getInstance().createContent(component, null, false)
6772
}
6873

69-
private fun getRightPanelDependingOnState(project: Project): JPanel {
74+
fun getRightPanelDependingOnState(project: Project): JPanel {
7075
val service = cycode(project)
7176
val pluginState = pluginState()
7277

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package com.cycode.plugin.components.toolWindow.components.cycodeActionToolBar
2+
3+
import com.cycode.plugin.CycodeBundle
4+
import com.cycode.plugin.components.toolWindow.CycodeContentTab
5+
import com.cycode.plugin.components.toolWindow.components.cycodeActionToolBar.actions.*
6+
import com.intellij.openapi.actionSystem.ActionManager
7+
import com.intellij.openapi.actionSystem.ActionToolbar
8+
import com.intellij.openapi.actionSystem.DefaultActionGroup
9+
10+
class CycodeActionToolbar {
11+
fun attachActionToolbar(contentTab: CycodeContentTab): ActionToolbar {
12+
val actionGroup = DefaultActionGroup().apply {
13+
add(HomeAction.create(contentTab))
14+
addSeparator()
15+
add(RunAllAction.create(contentTab))
16+
addSeparator()
17+
add(ExpandAllAction.create(contentTab))
18+
add(CollapseAllAction.create(contentTab))
19+
addSeparator()
20+
add(FilterBySeverityAction.create(contentTab, "Critical"))
21+
add(FilterBySeverityAction.create(contentTab, "High"))
22+
add(FilterBySeverityAction.create(contentTab, "Medium"))
23+
add(FilterBySeverityAction.create(contentTab, "Low"))
24+
addSeparator()
25+
add(ClearAction.create(contentTab))
26+
addSeparator()
27+
add(SettingsAction.create(contentTab))
28+
add(HelpAction.create(contentTab))
29+
}
30+
31+
val toolbar = ActionManager.getInstance().createActionToolbar(
32+
CycodeBundle.message("toolbarId"), actionGroup, true
33+
)
34+
toolbar.setTargetComponent(contentTab)
35+
contentTab.toolbar = toolbar.component
36+
37+
return toolbar
38+
}
39+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package com.cycode.plugin.components.toolWindow.components.cycodeActionToolBar.actions
2+
3+
import com.cycode.plugin.CycodeBundle
4+
import com.cycode.plugin.components.toolWindow.CycodeContentTab
5+
import com.cycode.plugin.services.scanResults
6+
import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer
7+
import com.intellij.icons.AllIcons
8+
import com.intellij.openapi.actionSystem.AnActionEvent
9+
import com.intellij.openapi.project.DumbAwareAction
10+
import java.util.function.Supplier
11+
12+
class ClearAction(private val contentTab: CycodeContentTab) :
13+
DumbAwareAction(Supplier { CycodeBundle.message("toolbarClearAction") }, AllIcons.Actions.GC) {
14+
companion object {
15+
fun create(contentTab: CycodeContentTab): ClearAction {
16+
return ClearAction(contentTab)
17+
}
18+
}
19+
20+
override fun actionPerformed(e: AnActionEvent) {
21+
val project = e.project ?: return
22+
scanResults(project).clear()
23+
contentTab.getTreeView().refreshTree()
24+
DaemonCodeAnalyzer.getInstance(project).restart()
25+
}
26+
27+
override fun update(e: AnActionEvent) {
28+
e.presentation.isEnabled = e.project != null &&
29+
!e.project!!.isDisposed &&
30+
scanResults(e.project!!).hasResults()
31+
}
32+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package com.cycode.plugin.components.toolWindow.components.cycodeActionToolBar.actions
2+
3+
import com.cycode.plugin.components.toolWindow.CycodeContentTab
4+
import com.intellij.ide.CommonActionsManager
5+
import com.intellij.ide.DefaultTreeExpander
6+
import com.intellij.openapi.actionSystem.AnAction
7+
8+
class CollapseAllAction {
9+
companion object {
10+
fun create(contentTab: CycodeContentTab): AnAction {
11+
val tree = contentTab.getTreeView().getTree()
12+
val treeExpander = DefaultTreeExpander(tree)
13+
14+
val commonActionsManager = CommonActionsManager.getInstance()
15+
return commonActionsManager.createCollapseAllAction(treeExpander, tree)
16+
}
17+
}
18+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package com.cycode.plugin.components.toolWindow.components.cycodeActionToolBar.actions
2+
3+
import com.cycode.plugin.components.toolWindow.CycodeContentTab
4+
import com.intellij.ide.CommonActionsManager
5+
import com.intellij.ide.DefaultTreeExpander
6+
import com.intellij.openapi.actionSystem.AnAction
7+
8+
class ExpandAllAction {
9+
companion object {
10+
fun create(contentTab: CycodeContentTab): AnAction {
11+
val tree = contentTab.getTreeView().getTree()
12+
val treeExpander = DefaultTreeExpander(tree)
13+
14+
val commonActionsManager = CommonActionsManager.getInstance()
15+
return commonActionsManager.createExpandAllAction(treeExpander, tree)
16+
}
17+
}
18+
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
package com.cycode.plugin.components.toolWindow.components.cycodeActionToolBar.actions
2+
3+
import com.cycode.plugin.CycodeBundle
4+
import com.cycode.plugin.components.toolWindow.CycodeContentTab
5+
import com.cycode.plugin.icons.PluginIcons
6+
import com.intellij.openapi.actionSystem.AnActionEvent
7+
import com.intellij.openapi.actionSystem.ToggleAction
8+
import com.intellij.openapi.project.DumbAware
9+
import com.intellij.openapi.project.Project
10+
import java.util.function.Supplier
11+
12+
private class SeverityFilterManager {
13+
// FIXME(MarshalX): remove closed projects?
14+
15+
companion object {
16+
val INSTANCE = SeverityFilterManager()
17+
}
18+
19+
private val severityFilterStates = mutableMapOf<Project, SeverityFilterState>()
20+
21+
fun getOrCreateState(project: Project): SeverityFilterState {
22+
return severityFilterStates.getOrPut(project) { SeverityFilterState() }
23+
}
24+
}
25+
26+
27+
private class SeverityFilterState {
28+
private val selectedFilters = mutableMapOf<String, Boolean>()
29+
30+
fun setState(filter: String, selected: Boolean) {
31+
selectedFilters[filter.toLowerCase()] = selected
32+
}
33+
34+
fun getState(filter: String): Boolean {
35+
// by default, all filters are selected
36+
return selectedFilters.getOrDefault(filter.toLowerCase(), true)
37+
}
38+
39+
fun exportState(): Map<String, Boolean> {
40+
return selectedFilters
41+
}
42+
}
43+
44+
class FilterBySeverityAction(private val contentTab: CycodeContentTab, private val severity: String) :
45+
ToggleAction(
46+
Supplier { CycodeBundle.message("toolbarFilterBySeverityAction", severity) },
47+
PluginIcons.getSeverityIcon(severity)
48+
),
49+
DumbAware {
50+
companion object {
51+
fun create(contentTab: CycodeContentTab, severity: String): FilterBySeverityAction {
52+
return FilterBySeverityAction(contentTab, severity)
53+
}
54+
}
55+
56+
override fun isSelected(e: AnActionEvent): Boolean {
57+
val project = e.project ?: return false
58+
val stateManager = SeverityFilterManager.INSTANCE.getOrCreateState(project)
59+
return stateManager.getState(severity)
60+
}
61+
62+
override fun setSelected(e: AnActionEvent, state: Boolean) {
63+
val project = e.project ?: return
64+
val stateManager = SeverityFilterManager.INSTANCE.getOrCreateState(project)
65+
stateManager.setState(severity, state)
66+
67+
contentTab.getTreeView().updateSeverityFilter(stateManager.exportState())
68+
}
69+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package com.cycode.plugin.components.toolWindow.components.cycodeActionToolBar.actions
2+
3+
import com.cycode.plugin.CycodeBundle
4+
import com.cycode.plugin.components.openURL
5+
import com.cycode.plugin.components.toolWindow.CycodeContentTab
6+
import com.intellij.icons.AllIcons
7+
import com.intellij.openapi.actionSystem.AnActionEvent
8+
import com.intellij.openapi.project.DumbAwareAction
9+
import java.util.function.Supplier
10+
11+
class HelpAction :
12+
DumbAwareAction(Supplier { CycodeBundle.message("toolbarHelpAction") }, AllIcons.Actions.Help) {
13+
companion object {
14+
fun create(contentTab: CycodeContentTab): HelpAction {
15+
return HelpAction()
16+
}
17+
}
18+
19+
override fun actionPerformed(e: AnActionEvent) {
20+
openURL(CycodeBundle.message("docsUrl"))
21+
}
22+
23+
override fun update(e: AnActionEvent) {
24+
e.presentation.isEnabled = e.project != null && !e.project!!.isDisposed
25+
}
26+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package com.cycode.plugin.components.toolWindow.components.cycodeActionToolBar.actions
2+
3+
import com.cycode.plugin.CycodeBundle
4+
import com.cycode.plugin.components.toolWindow.CycodeContentTab
5+
import com.cycode.plugin.components.toolWindow.getRightPanelDependingOnState
6+
import com.intellij.icons.AllIcons
7+
import com.intellij.openapi.actionSystem.AnActionEvent
8+
import com.intellij.openapi.project.DumbAwareAction
9+
import java.util.function.Supplier
10+
11+
class HomeAction(private val contentTab: CycodeContentTab) :
12+
DumbAwareAction(Supplier { CycodeBundle.message("toolbarHomeAction") }, AllIcons.Actions.Back) {
13+
companion object {
14+
fun create(contentTab: CycodeContentTab): HomeAction {
15+
return HomeAction(contentTab)
16+
}
17+
}
18+
19+
override fun actionPerformed(e: AnActionEvent) {
20+
val initRightPanel = getRightPanelDependingOnState(e.project!!)
21+
contentTab.updateContent(initRightPanel)
22+
}
23+
24+
override fun update(e: AnActionEvent) {
25+
e.presentation.isEnabled = e.project != null && !e.project!!.isDisposed
26+
}
27+
}

0 commit comments

Comments
 (0)