diff --git a/CHANGELOG.md b/CHANGELOG.md index eda3671..f37db59 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,11 @@ ## [Unreleased] +## [1.4.0] - 2024-09-06 + +- Add Violation Cards +- Add new toolbar actions: `Back to Home`, `Expand All`, `Collapse All` + ## [1.3.0] - 2024-08-28 - Add Tree View @@ -45,6 +50,8 @@ The first public release of the extension. +[1.4.0]: https://github.com/cycodehq/visual-studio-extension/releases/tag/v1.4.0 + [1.3.0]: https://github.com/cycodehq/visual-studio-extension/releases/tag/v1.3.0 [1.2.0]: https://github.com/cycodehq/visual-studio-extension/releases/tag/v1.2.0 @@ -63,4 +70,4 @@ The first public release of the extension. [1.0.0]: https://github.com/cycodehq/visual-studio-extension/releases/tag/v1.0.0 -[Unreleased]: https://github.com/cycodehq/visual-studio-extension/compare/v1.3.0...HEAD +[Unreleased]: https://github.com/cycodehq/visual-studio-extension/compare/v1.4.0...HEAD diff --git a/src/extension/Cycode.VisualStudio.Extension.14.0-16.0/source.extension.vsixmanifest b/src/extension/Cycode.VisualStudio.Extension.14.0-16.0/source.extension.vsixmanifest index 3ca4ee6..da792ae 100644 --- a/src/extension/Cycode.VisualStudio.Extension.14.0-16.0/source.extension.vsixmanifest +++ b/src/extension/Cycode.VisualStudio.Extension.14.0-16.0/source.extension.vsixmanifest @@ -1,7 +1,7 @@ - + Cycode Cycode for Visual Studio IDE https://github.com/cycodehq/visual-studio-extension diff --git a/src/extension/Cycode.VisualStudio.Extension.17.0/source.extension.vsixmanifest b/src/extension/Cycode.VisualStudio.Extension.17.0/source.extension.vsixmanifest index 97e7170..c988631 100644 --- a/src/extension/Cycode.VisualStudio.Extension.17.0/source.extension.vsixmanifest +++ b/src/extension/Cycode.VisualStudio.Extension.17.0/source.extension.vsixmanifest @@ -1,7 +1,7 @@ - + Cycode Cycode for Visual Studio IDE https://github.com/cycodehq/visual-studio-extension diff --git a/src/extension/Cycode.VisualStudio.Extension.Shared/Commands/BackToHomeScreenCommand.cs b/src/extension/Cycode.VisualStudio.Extension.Shared/Commands/BackToHomeScreenCommand.cs new file mode 100644 index 0000000..543668a --- /dev/null +++ b/src/extension/Cycode.VisualStudio.Extension.Shared/Commands/BackToHomeScreenCommand.cs @@ -0,0 +1,13 @@ +using Cycode.VisualStudio.Extension.Shared.DTO; +using Cycode.VisualStudio.Extension.Shared.Services; + +namespace Cycode.VisualStudio.Extension.Shared; + +[Command(PackageIds.BackToHomeScreenCommand)] +internal sealed class BackToHomeScreenCommand : BaseCommand { + protected override void Execute(object sender, EventArgs e) { + IToolWindowMessengerService toolWindowMessengerService = + ServiceLocator.GetService(); + toolWindowMessengerService.Send(new MessageEventArgs(MessengerCommand.BackToHomeScreen)); + } +} \ No newline at end of file diff --git a/src/extension/Cycode.VisualStudio.Extension.Shared/Commands/TreeViewCollapseAllCommand.cs b/src/extension/Cycode.VisualStudio.Extension.Shared/Commands/TreeViewCollapseAllCommand.cs new file mode 100644 index 0000000..21c899b --- /dev/null +++ b/src/extension/Cycode.VisualStudio.Extension.Shared/Commands/TreeViewCollapseAllCommand.cs @@ -0,0 +1,13 @@ +using Cycode.VisualStudio.Extension.Shared.DTO; +using Cycode.VisualStudio.Extension.Shared.Services; + +namespace Cycode.VisualStudio.Extension.Shared; + +[Command(PackageIds.TreeViewCollapseAllCommand)] +internal sealed class TreeViewCollapseAllCommand : BaseCommand { + protected override void Execute(object sender, EventArgs e) { + IToolWindowMessengerService toolWindowMessengerService = + ServiceLocator.GetService(); + toolWindowMessengerService.Send(new MessageEventArgs(MessengerCommand.TreeViewCollapseAll)); + } +} \ No newline at end of file diff --git a/src/extension/Cycode.VisualStudio.Extension.Shared/Commands/TreeViewExpandAllCommand.cs b/src/extension/Cycode.VisualStudio.Extension.Shared/Commands/TreeViewExpandAllCommand.cs new file mode 100644 index 0000000..36374e3 --- /dev/null +++ b/src/extension/Cycode.VisualStudio.Extension.Shared/Commands/TreeViewExpandAllCommand.cs @@ -0,0 +1,13 @@ +using Cycode.VisualStudio.Extension.Shared.DTO; +using Cycode.VisualStudio.Extension.Shared.Services; + +namespace Cycode.VisualStudio.Extension.Shared; + +[Command(PackageIds.TreeViewExpandAllCommand)] +internal sealed class TreeViewExpandAllCommand : BaseCommand { + protected override void Execute(object sender, EventArgs e) { + IToolWindowMessengerService toolWindowMessengerService = + ServiceLocator.GetService(); + toolWindowMessengerService.Send(new MessageEventArgs(MessengerCommand.TreeViewExpandAll)); + } +} \ No newline at end of file diff --git a/src/extension/Cycode.VisualStudio.Extension.Shared/Components/ToolWindows/CycodeToolWindowViewModel.cs b/src/extension/Cycode.VisualStudio.Extension.Shared/Components/ToolWindows/CycodeToolWindowViewModel.cs index ee7cbd5..ec9af17 100644 --- a/src/extension/Cycode.VisualStudio.Extension.Shared/Components/ToolWindows/CycodeToolWindowViewModel.cs +++ b/src/extension/Cycode.VisualStudio.Extension.Shared/Components/ToolWindows/CycodeToolWindowViewModel.cs @@ -10,6 +10,8 @@ namespace Cycode.VisualStudio.Extension.Shared.Components.ToolWindows; public class CycodeToolWindowViewModel : INotifyPropertyChanged { + private readonly ExtensionState _state = ServiceLocator.GetService().Load(); + private readonly CycodeTreeViewControl _cycodeTreeView; private UserControl _leftSideView; private UserControl _rightSideView; @@ -45,16 +47,44 @@ private void OnPropertyChanged(string propertyName) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } + private UserControl GetStateDependentRightSideView() { + UserControl newRightSideView; + + if (!_state.CliInstalled) { + newRightSideView = new LoadingControl(); + } else { + newRightSideView = _state.CliAuthed switch { + true => new MainControl(), + false => new AuthControl() + }; + } + + // return the new view if it's different from the current one + return newRightSideView.GetType() == RightSideView.GetType() ? RightSideView : newRightSideView; + } + private void OnMessageReceived(object sender, MessageEventArgs args) { RightSideView = args.Command switch { MessengerCommand.LoadLoadingControl => new LoadingControl(), MessengerCommand.LoadAuthControl => new AuthControl(), MessengerCommand.LoadMainControl => new MainControl(), - MessengerCommand.LoadSecretViolationCardControl => new SecretViolationCardControl((SecretDetection) args.Data), - MessengerCommand.LoadScaViolationCardControl => new ScaViolationCardControl((ScaDetection) args.Data), + MessengerCommand.LoadSecretViolationCardControl => new SecretViolationCardControl( + (SecretDetection)args.Data), + MessengerCommand.LoadScaViolationCardControl => new ScaViolationCardControl((ScaDetection)args.Data), + MessengerCommand.BackToHomeScreen => GetStateDependentRightSideView(), _ => RightSideView }; - if (args.Command == MessengerCommand.RefreshTreeView) _cycodeTreeView.RefreshTree(); + switch (args.Command) { + case MessengerCommand.TreeViewRefresh: + _cycodeTreeView.RefreshTree(); + break; + case MessengerCommand.TreeViewExpandAll: + _cycodeTreeView.ExpandAllNodes(); + break; + case MessengerCommand.TreeViewCollapseAll: + _cycodeTreeView.CollapseAllNodes(); + break; + } } } \ No newline at end of file diff --git a/src/extension/Cycode.VisualStudio.Extension.Shared/Components/TreeView/CycodeTreeViewControl.xaml b/src/extension/Cycode.VisualStudio.Extension.Shared/Components/TreeView/CycodeTreeViewControl.xaml index 02e0541..a0e24c5 100644 --- a/src/extension/Cycode.VisualStudio.Extension.Shared/Components/TreeView/CycodeTreeViewControl.xaml +++ b/src/extension/Cycode.VisualStudio.Extension.Shared/Components/TreeView/CycodeTreeViewControl.xaml @@ -29,6 +29,18 @@ + + stack = new(TreeView.Items.Cast()); + while (stack.Any()) { + BaseNode node = stack.Pop(); + foreach (BaseNode child in node.Items) stack.Push(child); + node.IsExpanded = isExpanded; + } + + TreeView.UpdateLayout(); + } + + public void ExpandAllNodes() { + _logger.Debug("Expand all nodes"); + SetIsExpandedToAllNodes(true); + } + + public void CollapseAllNodes() { + _logger.Debug("Collapse all nodes"); + SetIsExpandedToAllNodes(false); + } } \ No newline at end of file diff --git a/src/extension/Cycode.VisualStudio.Extension.Shared/Components/TreeView/Nodes/BaseNode.cs b/src/extension/Cycode.VisualStudio.Extension.Shared/Components/TreeView/Nodes/BaseNode.cs index ead1643..18b368b 100644 --- a/src/extension/Cycode.VisualStudio.Extension.Shared/Components/TreeView/Nodes/BaseNode.cs +++ b/src/extension/Cycode.VisualStudio.Extension.Shared/Components/TreeView/Nodes/BaseNode.cs @@ -1,10 +1,19 @@ using System.Collections.ObjectModel; +using System.Windows; namespace Cycode.VisualStudio.Extension.Shared.Components.TreeView.Nodes; -public class BaseNode { +public class BaseNode : DependencyObject { public string Title { get; set; } public string Summary { get; set; } public string Icon { get; set; } public ObservableCollection Items { get; set; } = []; + + public static readonly DependencyProperty IsExpandedProperty = DependencyProperty.Register( + nameof(IsExpanded), typeof(bool), typeof(BaseNode), new PropertyMetadata(false)); + + public bool IsExpanded { + get { return (bool)GetValue(IsExpandedProperty); } + set { SetValue(IsExpandedProperty, value); } + } } \ No newline at end of file diff --git a/src/extension/Cycode.VisualStudio.Extension.Shared/Cycode.VisualStudio.Extension.Shared.projitems b/src/extension/Cycode.VisualStudio.Extension.Shared/Cycode.VisualStudio.Extension.Shared.projitems index b4623fc..6fa75ab 100644 --- a/src/extension/Cycode.VisualStudio.Extension.Shared/Cycode.VisualStudio.Extension.Shared.projitems +++ b/src/extension/Cycode.VisualStudio.Extension.Shared/Cycode.VisualStudio.Extension.Shared.projitems @@ -33,11 +33,14 @@ + + + @@ -119,6 +122,15 @@ Always true + + Always + + + Always + + + Always + Always diff --git a/src/extension/Cycode.VisualStudio.Extension.Shared/CycodePackage.cs b/src/extension/Cycode.VisualStudio.Extension.Shared/CycodePackage.cs index 99ecd35..865c78e 100644 --- a/src/extension/Cycode.VisualStudio.Extension.Shared/CycodePackage.cs +++ b/src/extension/Cycode.VisualStudio.Extension.Shared/CycodePackage.cs @@ -44,6 +44,9 @@ protected override async Task InitializeAsync( IStateService stateService = ServiceLocator.GetService(); stateService.Load(); + ICliService cliService = ServiceLocator.GetService(); + cliService.ResetPluginCliState(); + await this.RegisterCommandsAsync(); this.RegisterToolWindows(); diff --git a/src/extension/Cycode.VisualStudio.Extension.Shared/DTO/MessengerCommand.cs b/src/extension/Cycode.VisualStudio.Extension.Shared/DTO/MessengerCommand.cs index 22a51d3..ea151e2 100644 --- a/src/extension/Cycode.VisualStudio.Extension.Shared/DTO/MessengerCommand.cs +++ b/src/extension/Cycode.VisualStudio.Extension.Shared/DTO/MessengerCommand.cs @@ -4,9 +4,13 @@ public static class MessengerCommand { public const string LoadLoadingControl = "load_loading_control"; public const string LoadAuthControl = "load_auth_control"; public const string LoadMainControl = "load_main_control"; - - public const string RefreshTreeView = "refresh_tree_view"; - + + public const string TreeViewRefresh = "tree_view_refresh"; + public const string TreeViewExpandAll = "tree_view_expand_all"; + public const string TreeViewCollapseAll = "tree_view_collapse_all"; + public const string LoadSecretViolationCardControl = "load_secret_violation_card_control"; public const string LoadScaViolationCardControl = "load_sca_violation_card_control"; + + public const string BackToHomeScreen = "back_to_home_screen"; } \ No newline at end of file diff --git a/src/extension/Cycode.VisualStudio.Extension.Shared/Resources/KnownMonikers/CollapseAll.png b/src/extension/Cycode.VisualStudio.Extension.Shared/Resources/KnownMonikers/CollapseAll.png new file mode 100644 index 0000000..2e01b78 Binary files /dev/null and b/src/extension/Cycode.VisualStudio.Extension.Shared/Resources/KnownMonikers/CollapseAll.png differ diff --git a/src/extension/Cycode.VisualStudio.Extension.Shared/Resources/KnownMonikers/ExpandAll.png b/src/extension/Cycode.VisualStudio.Extension.Shared/Resources/KnownMonikers/ExpandAll.png new file mode 100644 index 0000000..25c5581 Binary files /dev/null and b/src/extension/Cycode.VisualStudio.Extension.Shared/Resources/KnownMonikers/ExpandAll.png differ diff --git a/src/extension/Cycode.VisualStudio.Extension.Shared/Resources/KnownMonikers/Previous.png b/src/extension/Cycode.VisualStudio.Extension.Shared/Resources/KnownMonikers/Previous.png new file mode 100644 index 0000000..5493664 Binary files /dev/null and b/src/extension/Cycode.VisualStudio.Extension.Shared/Resources/KnownMonikers/Previous.png differ diff --git a/src/extension/Cycode.VisualStudio.Extension.Shared/Services/CliService.cs b/src/extension/Cycode.VisualStudio.Extension.Shared/Services/CliService.cs index c3df5aa..218b51b 100644 --- a/src/extension/Cycode.VisualStudio.Extension.Shared/Services/CliService.cs +++ b/src/extension/Cycode.VisualStudio.Extension.Shared/Services/CliService.cs @@ -115,7 +115,7 @@ public async Task ScanPathsScaAsync( ShowScanFileResultNotification(CliScanType.Sca, detectionsCount, onDemand); } - private void ResetPluginCliState() { + public void ResetPluginCliState() { logger.Debug("Resetting plugin CLI state"); _pluginState.CliAuthed = false; diff --git a/src/extension/Cycode.VisualStudio.Extension.Shared/Services/ErrorList/ErrorTaskCreatorService.cs b/src/extension/Cycode.VisualStudio.Extension.Shared/Services/ErrorList/ErrorTaskCreatorService.cs index 9dfb03d..6c9b887 100644 --- a/src/extension/Cycode.VisualStudio.Extension.Shared/Services/ErrorList/ErrorTaskCreatorService.cs +++ b/src/extension/Cycode.VisualStudio.Extension.Shared/Services/ErrorList/ErrorTaskCreatorService.cs @@ -18,7 +18,7 @@ public async Task RecreateAsync() { await CreateErrorTasksAsync(scanResultsService.GetScaResults()); CycodePackage.ErrorTaggerProvider.Rerender(); - toolWindowMessengerService.Send(new MessageEventArgs(MessengerCommand.RefreshTreeView)); + toolWindowMessengerService.Send(new MessageEventArgs(MessengerCommand.TreeViewRefresh)); } public async Task ClearErrorsAsync() { diff --git a/src/extension/Cycode.VisualStudio.Extension.Shared/Services/ICliService.cs b/src/extension/Cycode.VisualStudio.Extension.Shared/Services/ICliService.cs index 0828eed..ea28332 100644 --- a/src/extension/Cycode.VisualStudio.Extension.Shared/Services/ICliService.cs +++ b/src/extension/Cycode.VisualStudio.Extension.Shared/Services/ICliService.cs @@ -5,6 +5,8 @@ namespace Cycode.VisualStudio.Extension.Shared.Services; public interface ICliService { + void ResetPluginCliState(); + Task HealthCheckAsync(CancellationToken cancellationToken = default); Task CheckAuthAsync(CancellationToken cancellationToken = default); Task DoAuthAsync(CancellationToken cancellationToken = default); diff --git a/src/extension/Cycode.VisualStudio.Extension.Shared/VSCommandTable.cs b/src/extension/Cycode.VisualStudio.Extension.Shared/VSCommandTable.cs index ee5b19a..dd1c8ea 100644 --- a/src/extension/Cycode.VisualStudio.Extension.Shared/VSCommandTable.cs +++ b/src/extension/Cycode.VisualStudio.Extension.Shared/VSCommandTable.cs @@ -19,6 +19,9 @@ internal sealed class PackageIds { public const int ToolbarRunAllScansCommand = 0x1053; public const int ToolbarOpenWebDocsCommand = 0x1054; public const int ToolbarClearScanResultsCommand = 0x1055; + public const int BackToHomeScreenCommand = 0x1056; + public const int TreeViewExpandAllCommand = 0x1057; + public const int TreeViewCollapseAllCommand = 0x1058; public const int TopMenuCycodeCommand = 0x1103; public const int TopMenuOpenSettingsCommand = 0x1104; diff --git a/src/extension/Cycode.VisualStudio.Extension.Shared/VSCommandTable.vsct b/src/extension/Cycode.VisualStudio.Extension.Shared/VSCommandTable.vsct index 493333b..86d59bd 100644 --- a/src/extension/Cycode.VisualStudio.Extension.Shared/VSCommandTable.vsct +++ b/src/extension/Cycode.VisualStudio.Extension.Shared/VSCommandTable.vsct @@ -32,21 +32,42 @@ - + - + + - -