Skip to content

Feat/ide 715 filter tree #226

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 58 commits into from
Nov 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
58 commits
Select commit Hold shift + click to select a range
dc7d5a8
feat: add view with tree view, browser and toolbar buttons
acke Nov 8, 2024
a8fff73
feat: added initial text and image to browser view. No styling!
acke Nov 8, 2024
19bfb64
fix: added buttons and handlers for product activation
acke Nov 8, 2024
008606d
fix: update the string for use in Eclipse
acke Nov 8, 2024
2fb730a
feat: Added Tree and View Menu
acke Nov 12, 2024
e31bd11
tidy: fix imports
acke Nov 12, 2024
3173105
fix: cleanup image when plugin is shuting down
acke Nov 12, 2024
5fc6f71
feat: enable/disable products, viewmenu buttons and preferencepage
acke Nov 13, 2024
9bf0b02
fix: added filters to preferencesstore
acke Nov 13, 2024
e027045
fix: added handlers for each severity
acke Nov 13, 2024
28a5264
chore: remove JAVASE-21 from manifest
bastiandoetsch Nov 13, 2024
8535cff
feat: add interfaces and first functionality to retrieve html
bastiandoetsch Nov 13, 2024
c220898
fix: tests
bastiandoetsch Nov 13, 2024
1f18607
fix: use basehandler for handlers
acke Nov 13, 2024
6c3c487
tidy: rename rootobject to rootnode
acke Nov 13, 2024
a460b03
feat: updated viewmenu and added handlers for stop scan and clear cac…
acke Nov 14, 2024
e5a630a
feat/IDE-712_populate-the-tree-view-with-publish-diagnostics-data-fro…
bastiandoetsch Nov 15, 2024
d352e75
feat: choose the right icon for root nodes in the treeview
acke Nov 14, 2024
a6db3e4
tidy: remove the open preference action, replaced by preference handler
acke Nov 14, 2024
057f58d
fix: removed conflicting handlers
acke Nov 14, 2024
ef137c5
feat/clear cache on command
acke Nov 14, 2024
ed87de2
fix: move strings to bundle.properties
acke Nov 14, 2024
cb1c8dc
fix: also clear scanstate when clearing cache
acke Nov 15, 2024
4b282a4
fix: added a SnykIcon class for all imagedescriptors and added collap…
acke Nov 15, 2024
5e72f3d
feat: adding logic for fixable issues filter.
acke Nov 15, 2024
b82f24c
fix: updated UX to use enabled/disabled icons
acke Nov 18, 2024
c47fe8d
chore: added unit test for BaseTreeNode
acke Nov 18, 2024
a3e2f1b
tidy: make fixable comments more clear
acke Nov 18, 2024
7179673
fix: update lsconfiguration when preferences has been updated
acke Nov 18, 2024
d04f2fe
tidy: reformat unit tests
acke Nov 18, 2024
e9ad7c2
fix: call ui updates after state updates
acke Nov 18, 2024
cfcb0c5
fix: handle enable/disable of tree filters
acke Nov 18, 2024
8f2893e
fix: remove unneeded ImageDescriptorProvider
acke Nov 18, 2024
eee6fb0
Merge pull request #216 from snyk/feat/IDE-711_icon-chooser
acke Nov 18, 2024
6bc37fa
Merge branch 'feat/IDE-711_create_a_new_snyk_view' into feat/fixable-…
acke Nov 18, 2024
7ed56b2
fix: update Ignores Preferences and some tidying
acke Nov 18, 2024
a39a67e
Merge pull request #219 from snyk/feat/fixable-issues-filter
acke Nov 18, 2024
4a658cd
feat: populate tree [IDE-712] (#218)
bastiandoetsch Nov 20, 2024
51e5437
fix: progress manager and tests (#222)
bastiandoetsch Nov 21, 2024
a2c059a
Fix/tests (#223)
bastiandoetsch Nov 21, 2024
8ba9294
feat: add product node suffixes (#224)
bastiandoetsch Nov 21, 2024
eed768d
feat: new setting for consistent ignores [IDE-714] (#221)
acke Nov 22, 2024
ff2ba5f
feat: style description panel (#220)
ShawkyZ Nov 22, 2024
425fa89
fix: cache test
ShawkyZ Nov 22, 2024
9217d96
fix: HtmlProviderTest doesn't extend LsBaseTest
ShawkyZ Nov 22, 2024
e9b5e27
fix: ignore calling workbench if in test
ShawkyZ Nov 22, 2024
9302af7
fix: assert nonexisting string
ShawkyZ Nov 22, 2024
16c5cf2
feat: filters for severity and ignores
acke Nov 25, 2024
5a18762
Merge branch 'main' into feat/IDE-715_filter-tree
acke Nov 25, 2024
ef58e01
fix: post merge cleanup
acke Nov 25, 2024
14be52d
fix: added oss filter
acke Nov 25, 2024
7ad1bb3
fix: added initialization of filters when plugin starts.
acke Nov 25, 2024
1029446
fix: removes filetreenodes if they have no visiable issuenodes
acke Nov 26, 2024
a13b160
fix: refactor collapse tree handler
acke Nov 26, 2024
0373d55
fix: add unit tests for TreeViewerFilter
acke Nov 26, 2024
d43d49c
Merge branch 'main' into feat/IDE-715_filter-tree
acke Nov 26, 2024
a95df80
fix: update to Tycho 4.0.9, to solve bug in jgit when building maven
acke Nov 27, 2024
a46c536
fix: remove duplicate filter entry
acke Nov 27, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 17 additions & 12 deletions plugin/plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -141,10 +141,15 @@
name="Ignored Issues">
</command>
<command
defaultHandler="io.snyk.eclipse.plugin.views.snyktoolview.handlers.snykFilterFixableIssuesHandler"
defaultHandler="io.snyk.eclipse.plugin.views.snyktoolview.handlers.FilterFixableIssuesHandler"
id="io.snyk.eclipse.plugin.commands.snykFilterFixableIssues"
name="AI Fixable">
</command>
<command
defaultHandler="io.snyk.eclipse.plugin.views.snyktoolview.handlers.FilterOssFixableIssuesHandler"
id="io.snyk.eclipse.plugin.commands.snykFilterOssFixableIssues"
name="Fixable">
</command>
<command
defaultHandler="io.snyk.eclipse.plugin.views.snyktoolview.handlers.EnableAllAiFixHandler"
id="io.snyk.eclipse.plugin.snykShowAllSeverities"
Expand Down Expand Up @@ -354,19 +359,19 @@
style="push"
tooltip="Show Only Net New Issues">
</command>
<separator
name="io.snyk.eclipse.plugin.separator.allIssues"
visible="true">
</separator>
<command
commandId="io.snyk.eclipse.plugin.command.snykShowAllIssuesStatus"
icon="icons/enabled.png"
style="push"
tooltip="Show all issues">
</command>
</menu>
<menu
id="io.snyk.eclipse.plugin.views.snyktoolview.filtersMenu"
id="io.snyk.eclipse.plugin.views.snyktoolview.filtersAiFixMenu"
label="Open Source Fixability">
<command
commandId="io.snyk.eclipse.plugin.commands.snykFilterOssFixableIssues"
icon="icons/enabled.png"
style="push"
tooltip="Show only issues with Open Source Upgrade suggestions">
</command>
</menu>
<menu
id="io.snyk.eclipse.plugin.views.snyktoolview.filtersOssMenu"
label="Code AI Fixability">
<command
commandId="io.snyk.eclipse.plugin.commands.snykFilterFixableIssues"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ public static synchronized Preferences getInstance(PreferenceStore store) {
public static final String FILTER_IGNORES_SHOW_OPEN_ISSUES = "FILTER_IGNORES_OPEN_ISSUES";
public static final String FILTER_IGNORES_SHOW_IGNORED_ISSUES = "FILTER_IGNORES_IGNORED_ISSUES";
public static final String FILTER_FIXABLE_ISSUES = "FILTER_FIXABLE_ISSUES";
public static final String FILTER_OSS_FIXABLE_ISSUES = "FILTER_OSS_FIXABLE_ISSUES";

// Feature flags
public static final String IS_GLOBAL_IGNORES_FEATURE_ENABLED = "IS_GLOBAL_IGNORES_FEATURE_ENABLED";
Expand All @@ -68,6 +69,7 @@ public static synchronized Preferences getInstance(PreferenceStore store) {
public static final String DEFAULT_ENDPOINT = "https://api.snyk.io";
public static final String DEVICE_ID = "deviceId";
public static final String RELEASE_CHANNEL = "releaseChannel";


private final PreferenceStore store;

Expand Down Expand Up @@ -97,9 +99,6 @@ public static synchronized Preferences getInstance(PreferenceStore store) {
if (getPref(FILTER_LOW) == null) {
store(FILTER_LOW, "false");
}
if (getPref(FILTER_CRITICAL) == null) {
store(FILTER_CRITICAL, "false");
}
if (getPref(FILTER_DELTA_NEW_ISSUES) == null) {
store(FILTER_DELTA_NEW_ISSUES, "false");
}
Expand All @@ -112,7 +111,10 @@ public static synchronized Preferences getInstance(PreferenceStore store) {
if (getPref(FILTER_FIXABLE_ISSUES) == null) {
store(FILTER_FIXABLE_ISSUES, "false");
}

if (getPref(FILTER_OSS_FIXABLE_ISSUES) == null) {
store(FILTER_OSS_FIXABLE_ISSUES, "false");
}

if (getPref(SEND_ERROR_REPORTS) == null) {
store(SEND_ERROR_REPORTS, "true");
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package io.snyk.eclipse.plugin.views.snyktoolview;

import java.util.function.Predicate;

import org.eclipse.jface.viewers.TreeViewer;

import io.snyk.eclipse.plugin.SnykStartup;
import io.snyk.eclipse.plugin.properties.preferences.Preferences;
import io.snyk.eclipse.plugin.views.snyktoolview.filters.FixableFilter;
import io.snyk.eclipse.plugin.views.snyktoolview.filters.IgnoresFilter;
import io.snyk.eclipse.plugin.views.snyktoolview.filters.IgnoresOpenIssuesFilter;
import io.snyk.eclipse.plugin.views.snyktoolview.filters.OssFixableFilter;
import io.snyk.eclipse.plugin.views.snyktoolview.filters.SeverityCriticalFilter;
import io.snyk.eclipse.plugin.views.snyktoolview.filters.SeverityHighFilter;
import io.snyk.eclipse.plugin.views.snyktoolview.filters.SeverityLowFilter;
import io.snyk.eclipse.plugin.views.snyktoolview.filters.SeverityMediumFilter;
import io.snyk.languageserver.protocolextension.messageObjects.scanResults.Issue;

public class TreeFilterManager {

private TreeViewer treeView;
private TreeViewerFilter filter;
private static TreeFilterManager filterManager;

public synchronized static TreeFilterManager getInstance() {
if (filterManager != null) {
return filterManager;
}
filterManager = new TreeFilterManager();

setupFilters();
return filterManager;
}

private static void setupFilters() {
// Severity filters
new SeverityCriticalFilter(TreeFilterManager.getInstance(), Preferences.getInstance(),
Preferences.FILTER_CRITICAL).applyFilter();
new SeverityHighFilter(TreeFilterManager.getInstance(), Preferences.getInstance(), Preferences.FILTER_HIGH)
.applyFilter();
new SeverityMediumFilter(TreeFilterManager.getInstance(), Preferences.getInstance(), Preferences.FILTER_MEDIUM)
.applyFilter();
new SeverityLowFilter(TreeFilterManager.getInstance(), Preferences.getInstance(), Preferences.FILTER_LOW)
.applyFilter();

// Ignores filters
new IgnoresFilter(TreeFilterManager.getInstance(), Preferences.getInstance(),
Preferences.FILTER_IGNORES_SHOW_IGNORED_ISSUES).applyFilter();
new IgnoresOpenIssuesFilter(TreeFilterManager.getInstance(), Preferences.getInstance(),
Preferences.FILTER_IGNORES_SHOW_OPEN_ISSUES).applyFilter();

// Fix
new FixableFilter(TreeFilterManager.getInstance(), Preferences.getInstance(), Preferences.FILTER_FIXABLE_ISSUES)
.applyFilter();
new OssFixableFilter(TreeFilterManager.getInstance(), Preferences.getInstance(),
Preferences.FILTER_OSS_FIXABLE_ISSUES).applyFilter();

}

private TreeFilterManager() {
treeView = SnykStartup.getView().getTreeViewer();
filter = new TreeViewerFilter();
}

public void addTreeFilter(String filterName, Predicate<? super Issue> filterPredicate) {
filter.setFilterPredicate(filterName, filterPredicate);
treeView.addFilter(filter);
updateTree(treeView);
}

public void removeTreeFilter(String filterName) {
filter.removeFilterPredicate(filterName);
treeView.addFilter(filter);
updateTree(treeView);
}

public void removeTreeFilters() {
treeView.resetFilters();
updateTree(treeView);
}

private void updateTree(TreeViewer treeView) {
treeView.getControl().setRedraw(false);
treeView.refresh();
treeView.getControl().setRedraw(true);
treeView.expandAll();
}

}
Original file line number Diff line number Diff line change
@@ -1,55 +1,66 @@
package io.snyk.eclipse.plugin.views.snyktoolview;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Predicate;

import org.eclipse.jface.viewers.ILabelProvider;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerFilter;

import io.snyk.languageserver.protocolextension.messageObjects.scanResults.Issue;

public class TreeViewerFilter extends ViewerFilter {
private List<String> searchStrings;
private boolean matchAll; // If true, all filters must match; if false, any filter can match
private Map<String, Predicate<? super Issue>> filters;

public TreeViewerFilter() {
this.searchStrings = new ArrayList<>();
this.matchAll = true; // Default to matching all filters
filters = new ConcurrentHashMap<>();
}

public void addSearchText(String s) {
if (s != null && !s.isEmpty()) {
this.searchStrings.add(".*" + s.toLowerCase() + ".*");
}
}
@Override
public boolean select(Viewer viewer, Object parentElement, Object element) {
if (element instanceof FileTreeNode) {
return hasVisibleChildren((FileTreeNode) element, viewer);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that looks good. I hope it wouldn't be a performance bottleneck tho.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, we only call the hasVisibleChildren if the node is a treenode, so its not called for all tree nodes. However this might be slow if a project has very many files.

}

if (!(element instanceof IssueTreeNode) || !(viewer instanceof TreeViewer)) {
return true;
}

public void clearSearchText() {
this.searchStrings.clear();
return isIssueVisible((IssueTreeNode) element);
}

public void setMatchAll(boolean matchAll) {
this.matchAll = matchAll;
private boolean hasVisibleChildren(FileTreeNode fileNode, Viewer viewer) {
Object[] children = ((ITreeContentProvider) ((TreeViewer) viewer).getContentProvider()).getChildren(fileNode);
for (Object child : children) {
if (child instanceof IssueTreeNode && isIssueVisible((IssueTreeNode) child)) {
return true;
}
}
return false;
}

@Override
public boolean select(Viewer viewer, Object parentElement, Object element) {
if (searchStrings.isEmpty()) {
return true;
}

TreeViewer treeViewer = (TreeViewer) viewer;
String label = ((ILabelProvider) treeViewer.getLabelProvider()).getText(element);
private boolean isIssueVisible(IssueTreeNode issueNode) {
Issue issue = issueNode.getIssue();
if (issue == null) {
return true;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why would it be visible if null?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't want to apply filters (and hide) tree elements if we don't match any filters.

}

if (label == null) {
return false;
}
for (var filter : this.filters.values()) {
if (!filter.test(issue)) {
return false;
}
}
return true;
}

String labelLower = label.toLowerCase();
public void setFilterPredicate(String filterName, Predicate<? super Issue> predicate) {
this.filters.put(filterName, predicate);
}

if (matchAll) {
return searchStrings.stream().allMatch(s -> labelLower.matches(s));
} else {
return searchStrings.stream().anyMatch(s -> labelLower.matches(s));
}
public void removeFilterPredicate(String filterName) {
this.filters.remove(filterName);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package io.snyk.eclipse.plugin.views.snyktoolview.filters;

public interface BaseFilter {
public void applyFilter();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package io.snyk.eclipse.plugin.views.snyktoolview.filters;

import io.snyk.eclipse.plugin.properties.preferences.Preferences;
import io.snyk.eclipse.plugin.views.snyktoolview.TreeFilterManager;

public class FixableFilter implements BaseFilter {
private TreeFilterManager filterManager;
private Preferences preferences;
private String preferenceKey;

public FixableFilter(TreeFilterManager filterManager, Preferences preferences, String preferenceKey) {
this.filterManager = filterManager;
this.preferences = preferences;
this.preferenceKey = preferenceKey;

}

@Override
public void applyFilter() {
boolean booleanPref = this.preferences.getBooleanPref(this.preferenceKey);

if (booleanPref) {
this.filterManager.addTreeFilter(this.preferenceKey, issue -> issue.hasFix());
} else {
this.filterManager.removeTreeFilter(this.preferenceKey);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package io.snyk.eclipse.plugin.views.snyktoolview.filters;

import io.snyk.eclipse.plugin.properties.preferences.Preferences;
import io.snyk.eclipse.plugin.views.snyktoolview.TreeFilterManager;

public class IgnoresFilter implements BaseFilter {
private TreeFilterManager filterManager;
private Preferences preferences;
private String preferenceKey;

public IgnoresFilter(TreeFilterManager filterManager, Preferences preferences, String preferenceKey) {
this.filterManager = filterManager;
this.preferences = preferences;
this.preferenceKey = preferenceKey;
}

@Override
public void applyFilter() {
boolean booleanPref = this.preferences.getBooleanPref(this.preferenceKey);

if (booleanPref) {
filterManager.removeTreeFilter(preferenceKey);
} else {
filterManager.addTreeFilter(preferenceKey, issue -> !issue.isIgnored());
}

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package io.snyk.eclipse.plugin.views.snyktoolview.filters;

import io.snyk.eclipse.plugin.properties.preferences.Preferences;
import io.snyk.eclipse.plugin.views.snyktoolview.TreeFilterManager;

public class IgnoresOpenIssuesFilter implements BaseFilter {
private TreeFilterManager filterManager;
private Preferences preferences;
private String preferenceKey;

public IgnoresOpenIssuesFilter(TreeFilterManager filterManager, Preferences preferences, String preferenceKey) {
this.filterManager = filterManager;
this.preferences = preferences;
this.preferenceKey = preferenceKey;
}

@Override
public void applyFilter() {
boolean booleanPref = this.preferences.getBooleanPref(Preferences.FILTER_IGNORES_SHOW_OPEN_ISSUES);

if (booleanPref) {
filterManager.removeTreeFilter(preferenceKey);
} else {
filterManager.addTreeFilter(preferenceKey, issue -> issue.isIgnored());
}

}
}
Loading