Skip to content

Commit 89ba440

Browse files
authored
VS | Count of vulnerabilities displayed similar to VS code (AST-106033) (#275)
1 parent 26983c9 commit 89ba440

File tree

6 files changed

+97
-38
lines changed

6 files changed

+97
-38
lines changed

.github/workflows/ci.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,12 @@ jobs:
2020
uses: microsoft/setup-msbuild@1ff57057b5cfdc39105cd07a01d78e9b0ea0c14c #v1.3.1
2121
with:
2222
vs-version: '17.2'
23+
24+
- name: Install .NET 6.0 Windows Desktop Runtime
25+
uses: actions/setup-dotnet@v4
26+
with:
27+
dotnet-version: '6.0.x'
28+
include-prerelease: false
2329

2430
- name: Restore NuGet packages
2531
run: nuget restore .

ast-visual-studio-extension/CxExtension/CxWindowControl.xaml

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -472,13 +472,13 @@
472472
<MenuItem.Icon>
473473
<imaging:CrispImage Moniker="{x:Static catalog:KnownMonikers.GroupBy}"/>
474474
</MenuItem.Icon>
475-
<MenuItem Style="{DynamicResource DefaultMenuItemStyle}" x:Name="SeverityGroupBy" Header="Severity" Click="GroupBy_Click"/>
476-
<MenuItem Style="{DynamicResource DefaultMenuItemStyle}" x:Name="VulnerabiltyTypeGroupBy" Header="Vulnerabilty Type" Click="GroupBy_Click"/>
477-
<MenuItem Style="{DynamicResource DefaultMenuItemStyle}" x:Name="StateGroupBy" Header="State" Click="GroupBy_Click"/>
478-
<MenuItem Style="{DynamicResource DefaultMenuItemStyle}" x:Name="StatusGroupBy" Header="Status" Click="GroupBy_Click"/>
479-
<MenuItem Style="{DynamicResource DefaultMenuItemStyle}" x:Name="LanguageGroupBy" Header="Language" Click="GroupBy_Click"/>
480-
<MenuItem Style="{DynamicResource DefaultMenuItemStyle}" x:Name="FileGroupBy" Header="File" Click="GroupBy_Click"/>
481-
<MenuItem Style="{DynamicResource DefaultMenuItemStyle}" x:Name="DirectDependencyGroupBy" Header="Direct Dependency" Click="GroupBy_Click"/>
475+
<MenuItem Style="{DynamicResource DefaultMenuItemStyle}" x:Name="SeverityGroupBy" Header="Group by: Severity" Click="GroupBy_Click"/>
476+
<MenuItem Style="{DynamicResource DefaultMenuItemStyle}" x:Name="VulnerabilityTypeGroupBy" Header="Group by: Vulnerability Type" Click="GroupBy_Click"/>
477+
<MenuItem Style="{DynamicResource DefaultMenuItemStyle}" x:Name="StateGroupBy" Header="Group by: State" Click="GroupBy_Click"/>
478+
<MenuItem Style="{DynamicResource DefaultMenuItemStyle}" x:Name="StatusGroupBy" Header="Group by: Status" Click="GroupBy_Click"/>
479+
<MenuItem Style="{DynamicResource DefaultMenuItemStyle}" x:Name="LanguageGroupBy" Header="Group by: Language" Click="GroupBy_Click"/>
480+
<MenuItem Style="{DynamicResource DefaultMenuItemStyle}" x:Name="FileGroupBy" Header="Group by: File" Click="GroupBy_Click"/>
481+
<MenuItem Style="{DynamicResource DefaultMenuItemStyle}" x:Name="DirectDependencyGroupBy" Header="Group by: Direct Dependency" Click="GroupBy_Click"/>
482482
</MenuItem>
483483
</Menu>
484484

@@ -557,7 +557,7 @@
557557
</UniformGrid>
558558

559559
<UniformGrid Rows="1" Columns="1">
560-
<TextBox Text="Comment (Optional)" Name="TriageComment" Margin="5,5,5,0" Height="50" TextWrapping="WrapWithOverflow" GotFocus="OnFocusComment" LostFocus="OnLostFocusComment"/>
560+
<TextBox Text="Note (Optional or required based on tenant configuration)" Name="TriageComment" Margin="5,5,5,0" Height="50" TextWrapping="WrapWithOverflow" GotFocus="OnFocusComment" LostFocus="OnLostFocusComment"/>
561561
</UniformGrid>
562562

563563
<!-- Description and Changes tabs -->

ast-visual-studio-extension/CxExtension/CxWindowControl.xaml.cs

Lines changed: 49 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,21 @@
33
using ast_visual_studio_extension.CxExtension.Toolbar;
44
using ast_visual_studio_extension.CxExtension.Utils;
55
using ast_visual_studio_extension.CxPreferences;
6+
using ast_visual_studio_extension.CxWrapper.Models;
67
using Microsoft.VisualStudio.Shell;
78
using System.Collections.Generic;
9+
using System.Diagnostics;
10+
using System.Diagnostics.CodeAnalysis;
11+
using System.Linq;
12+
using System.Threading;
13+
using System.Threading.Tasks;
814
using System.Windows;
915
using System.Windows.Controls;
1016
using System.Windows.Controls.Primitives;
1117
using System.Windows.Input;
1218
using System.Windows.Media;
13-
using System.Threading;
14-
using System.Threading.Tasks;
1519
using System;
16-
using System.Diagnostics;
1720
using ast_visual_studio_extension.CxExtension.Services;
18-
using System.Diagnostics.CodeAnalysis;
19-
using ast_visual_studio_extension.CxWrapper.Models;
2021

2122
namespace ast_visual_studio_extension.CxExtension
2223
{
@@ -71,7 +72,7 @@ public CxWindowControl(AsyncPackage package)
7172
.WithGroupByOptions(new Dictionary<MenuItem, GroupBy>
7273
{
7374
{ SeverityGroupBy, GroupBy.SEVERITY },
74-
{ VulnerabiltyTypeGroupBy, GroupBy.VULNERABILITY_TYPE },
75+
{ VulnerabilityTypeGroupBy, GroupBy.VULNERABILITY_TYPE },
7576
{ StateGroupBy, GroupBy.STATE },
7677
{ StatusGroupBy, GroupBy.STATUS },
7778
{ LanguageGroupBy, GroupBy.Language },
@@ -98,23 +99,55 @@ private async Task InitializeAsync()
9899
private Dictionary<MenuItem, State> CreateStateMenuItems(List<State> states)
99100
{
100101
StateFilterMenuItem.Items.Clear();
101-
Dictionary<MenuItem, State> statesMenuItems = new Dictionary<MenuItem, State>();
102-
foreach (var item in states)
102+
var statesMenuItems = new Dictionary<MenuItem, State>();
103+
104+
// Sort states by formatted name
105+
var sortedStates = states.OrderBy(s => UIUtils.FormatStateName(s.name));
106+
107+
foreach (var state in sortedStates)
103108
{
104-
string formattedState = UIUtils.FormatStateName(item.name);
105-
var menuItem = new MenuItem
106-
{
107-
Header = formattedState,
108-
Style = (Style)Application.Current.Resources["DefaultMenuItemStyle"]
109-
};
109+
string formattedState = UIUtils.FormatStateName(state.name);
110+
var menuItem = CreateMenuItem($"Filter: {formattedState}");
110111
menuItem.Click += StateFilter_Click;
112+
111113
StateFilterMenuItem.Items.Add(menuItem);
112-
statesMenuItems.Add(menuItem, item);
114+
statesMenuItems.Add(menuItem, state);
113115
}
114-
AddDependencyFilter("SCA Dev & Test Dependencies", statesMenuItems);
116+
117+
// Add dependency filters before final sort
118+
AddDependencyFilter("Filter: SCA Dev & Test Dependencies", statesMenuItems);
119+
120+
// Sort menu items by Header
121+
SortStateFilterMenuItems();
122+
115123
return statesMenuItems;
116124
}
117125

126+
private MenuItem CreateMenuItem(string header)
127+
{
128+
return new MenuItem
129+
{
130+
Header = header,
131+
Style = (Style)Application.Current.Resources["DefaultMenuItemStyle"]
132+
};
133+
}
134+
135+
private void SortStateFilterMenuItems()
136+
{
137+
var sortedItems = StateFilterMenuItem.Items
138+
.Cast<MenuItem>()
139+
.OrderBy(mi => mi.Header.ToString())
140+
.ToList();
141+
142+
StateFilterMenuItem.Items.Clear();
143+
144+
foreach (var item in sortedItems)
145+
{
146+
StateFilterMenuItem.Items.Add(item);
147+
}
148+
}
149+
150+
118151
private void AddDependencyFilter(string filterName, Dictionary<MenuItem, State> statesMenuItems)
119152
{
120153
var dependencyState = new State

ast-visual-studio-extension/CxExtension/Utils/CxConstants.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ internal class CxConstants
5858
public static string TOOLBAR_LOADING_SCANS => "Loading scans...";
5959

6060
/************ TRIAGE ************/
61-
public static string TRIAGE_COMMENT_PLACEHOLDER => "Comment (Optional)";
61+
public static string TRIAGE_COMMENT_PLACEHOLDER => "Note (Optional or required based on tenant configuration)";
6262
public static string TRIAGE_UPDATE_FAILED => "Triage Update failed. {0}";
6363
public static string TRIAGE_SHOW_FAILED => "Triage Show failed. {0}";
6464
public static string TRIAGE_LOADING_CHANGES => "Loading changes...";

ast-visual-studio-extension/CxExtension/Utils/ResultsFilteringAndGrouping.cs

Lines changed: 31 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@ public static List<TreeViewItem> FilterAndGroupResults(AsyncPackage package, Lis
2222

2323
var isDevOrTestSelected = stateManager.enabledCustemStates.Contains("SCA Dev & Test Dependencies");
2424
enabledGroupBys.Insert(0, GroupBy.ENGINE);
25+
26+
// Dictionary to store group headers and counts
27+
var groupNodeCounts = new Dictionary<TreeViewItem, int>();
28+
2529
foreach (TreeViewItem item in results)
2630
{
2731
var result = item.Tag as Result;
@@ -51,33 +55,43 @@ public static List<TreeViewItem> FilterAndGroupResults(AsyncPackage package, Lis
5155
continue;
5256
}
5357

54-
List<TreeViewItem> children = GetInsertLocation(enabledGroupBys, treeResults, result);
58+
List<TreeViewItem> children = GetInsertLocation(enabledGroupBys, treeResults, result, groupNodeCounts);
5559

5660
children.Add(item);
5761
}
5862

63+
// Update group headers with counts
64+
foreach (var kvp in groupNodeCounts)
65+
{
66+
var headerBlock = kvp.Key.Header as TextBlock;
67+
if (headerBlock != null)
68+
{
69+
string baseLabel = (headerBlock.Tag as string).Replace("_", " ");
70+
string labelWithCount = $"{baseLabel} ({kvp.Value})";
71+
72+
// Replace the existing header with a new TextBlock
73+
kvp.Key.Header = UIUtils.CreateTreeViewItemHeader(string.Empty, labelWithCount);
74+
kvp.Key.ToolTip = $"{baseLabel}";
75+
}
76+
}
77+
78+
5979
return treeResults;
6080
}
6181

62-
private static List<TreeViewItem> GetInsertLocation(List<GroupBy> enabledGroupBys, List<TreeViewItem> treeResults, Result result)
82+
private static List<TreeViewItem> GetInsertLocation(List<GroupBy> enabledGroupBys, List<TreeViewItem> treeResults, Result result, Dictionary<TreeViewItem, int> groupNodeCounts)
6383
{
6484
var children = treeResults;
6585
foreach (GroupBy groupBy in enabledGroupBys)
6686
{
6787
var generator = GetGroupByTitleGenerator(groupBy);
68-
if (generator == null)
69-
{
70-
continue;
71-
}
88+
if (generator == null) continue;
7289

7390
var childNodeName = GetGroupByTitleGenerator(groupBy).Invoke(result);
74-
if (childNodeName == null)
75-
{
76-
continue;
77-
}
91+
if (childNodeName == null) continue;
7892

7993
// single underscore is used as mnemonic
80-
childNodeName = childNodeName.Replace("_", "__");
94+
childNodeName = childNodeName.Replace("_", " ");
8195

8296
TreeViewItem child = null;
8397

@@ -93,6 +107,12 @@ private static List<TreeViewItem> GetInsertLocation(List<GroupBy> enabledGroupBy
93107
child = UIUtils.CreateTreeViewItemWithItemsSource(childNodeName, new List<TreeViewItem> { new TreeViewItem() });
94108
(child.ItemsSource as List<TreeViewItem>).Clear();
95109
children.Add(child);
110+
groupNodeCounts[child] = 0; // initialize count
111+
}
112+
// Increment count for this group node
113+
if (groupNodeCounts.ContainsKey(child))
114+
{
115+
groupNodeCounts[child]++;
96116
}
97117
children = child.ItemsSource as List<TreeViewItem>;
98118
}

ast-visual-studio-extension/CxExtension/Utils/UIUtils.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ public static TextBlock CreateTreeViewItemHeader(string severity, string display
5050

5151
Label resultDisplayName = new Label
5252
{
53-
Content = displayName
53+
Content = displayName.Replace("_", " ")
5454
};
5555
stackPanel.Children.Add(resultDisplayName);
5656

@@ -60,7 +60,7 @@ public static TextBlock CreateTreeViewItemHeader(string severity, string display
6060
resultUIElement.Inlines.Add(uiContainer);
6161
resultUIElement.Tag = displayName;
6262
resultUIElement.TextWrapping = TextWrapping.WrapWithOverflow;
63-
63+
if (!string.IsNullOrEmpty(severity)) resultUIElement.ToolTip = displayName.Replace("_" ," ");
6464
return resultUIElement;
6565
}
6666

0 commit comments

Comments
 (0)