Skip to content

Commit 9fa1c16

Browse files
committed
feat: add "Unregister from Dataverse" command
Introduce command to unregister plugin assemblies from Dataverse via the project context menu. - Add UnregisterCommand with UI confirmation and service logic. - Implement IPluginRegistrationUI and VsPluginRegistrationUI for user prompts. - Extend PluginRegistrationService with UnregisterAsync for batch deletion. - Update command table and button placements for clarity. - Refactor UI interface location and method names. - Update branding to "Novovio" and bump version to 1.5.6. - Miscellaneous improvements to error handling and dependency checks.
1 parent 04ed639 commit 9fa1c16

16 files changed

+350
-84
lines changed

src/XrmTools.Core/Properties/AssemblyInfo.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@
88
[assembly: AssemblyTitle("XrmTools.Core")]
99
[assembly: AssemblyDescription("")]
1010
[assembly: AssemblyConfiguration("")]
11-
[assembly: AssemblyCompany("AG Insurance")]
11+
[assembly: AssemblyCompany("Novovio")]
1212
[assembly: AssemblyProduct("XrmTools.Core")]
13-
[assembly: AssemblyCopyright("Copyright © AG Insurance 2024")]
13+
[assembly: AssemblyCopyright("Copyright © Novovio 2024")]
1414
[assembly: AssemblyTrademark("")]
1515
[assembly: AssemblyCulture("")]
1616

src/XrmTools.UI.Controls/Properties/AssemblyInfo.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@
1010
[assembly: AssemblyTitle("XrmTools.UI.Controls")]
1111
[assembly: AssemblyDescription("")]
1212
[assembly: AssemblyConfiguration("")]
13-
[assembly: AssemblyCompany("AG Insurance")]
13+
[assembly: AssemblyCompany("Novovio")]
1414
[assembly: AssemblyProduct("XrmTools.UI.Controls")]
15-
[assembly: AssemblyCopyright("Copyright © AG Insurance 2024")]
15+
[assembly: AssemblyCopyright("Copyright © Novovio 2024")]
1616
[assembly: AssemblyTrademark("")]
1717
[assembly: AssemblyCulture("")]
1818

src/XrmTools/Commands/RegisterPluginCommand.cs

Lines changed: 2 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,12 @@ namespace XrmTools.Commands;
1515
using XrmTools.Logging.Compatibility;
1616
using XrmTools.Resources;
1717
using XrmTools.Services;
18+
using XrmTools.UI;
1819
using XrmTools.WebApi;
1920
using XrmTools.Xrm.Repositories;
2021
using static XrmTools.Helpers.ProjectExtensions;
2122
using Task = System.Threading.Tasks.Task;
2223

23-
/// <summary>
24-
/// Command handler to set the custom tool of the selected item to the Xrm Plugin Code Generator.
25-
/// </summary>
2624
[Command(PackageGuids.XrmToolsCmdSetIdString, PackageIds.RegisterPluginCmdId)]
2725
internal sealed class RegisterPluginCommand : BaseCommand<RegisterPluginCommand>
2826
{
@@ -44,15 +42,6 @@ internal sealed class RegisterPluginCommand : BaseCommand<RegisterPluginCommand>
4442
[Import]
4543
internal IPluginRegistrationService PluginRegistrationService { get; set; } = null!;
4644

47-
[Import]
48-
internal Validation.IValidationService Validator { get; set; } = null!;
49-
50-
public (bool suceeded, string message) RegisterPluginPackage()
51-
{
52-
53-
return (true, string.Empty);
54-
}
55-
5645
protected override async Task ExecuteAsync(OleMenuCmdEventArgs e)
5746
{
5847
var activeItem = await VS.Solutions.GetActiveItemAsync();
@@ -158,15 +147,7 @@ private void EnsureDependencies()
158147
if (WebApiService == null) throw new InvalidOperationException(string.Format(Strings.MissingServiceDependency, nameof(RegisterPluginCommand), nameof(WebApiService)));
159148
if (EnvironmentProvider == null) throw new InvalidOperationException(string.Format(Strings.MissingServiceDependency, nameof(RegisterPluginCommand), nameof(EnvironmentProvider)));
160149
if (RepositoryFactory == null) throw new InvalidOperationException(string.Format(Strings.MissingServiceDependency, nameof(RegisterPluginCommand), nameof(RepositoryFactory)));
161-
}
162-
163-
private sealed class VsPluginRegistrationUI : IPluginRegistrationUI
164-
{
165-
public async Task<bool> ConfirmRemovePluginsAsync(System.Collections.Generic.IEnumerable<string> removedTypeNames, System.Threading.CancellationToken cancellationToken)
166-
{
167-
var removedPluginNames = string.Join(", ", removedTypeNames);
168-
return await VS.MessageBox.ShowConfirmAsync("Xrm Tools", "Looks like you have removed the following plugins. Continuing will remove these plugins from Dataverse too. Is that ok?\r\n" + removedPluginNames);
169-
}
150+
if (PluginRegistrationService == null) throw new InvalidOperationException(string.Format(Strings.MissingServiceDependency, nameof(RegisterPluginCommand), nameof(PluginRegistrationService)));
170151
}
171152
}
172153
#nullable restore
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
#nullable enable
2+
namespace XrmTools.Commands;
3+
4+
using Community.VisualStudio.Toolkit;
5+
using Microsoft.VisualStudio.ComponentModelHost;
6+
using Microsoft.VisualStudio.Shell;
7+
using System;
8+
using System.Collections.Generic;
9+
using System.ComponentModel.Composition;
10+
using System.Threading.Tasks;
11+
using XrmTools.Analyzers;
12+
using XrmTools.Environments;
13+
using XrmTools.Helpers;
14+
using XrmTools.Logging.Compatibility;
15+
using XrmTools.Services;
16+
using XrmTools.UI;
17+
using XrmTools.WebApi;
18+
using XrmTools.Xrm.Repositories;
19+
using System.Diagnostics.CodeAnalysis;
20+
using XrmTools.Resources;
21+
22+
[Command(PackageGuids.XrmToolsCmdSetIdString, PackageIds.UnregisterPluginCmdId)]
23+
internal sealed class UnregisterCommand : BaseCommand<UnregisterCommand>
24+
{
25+
[Import]
26+
internal IWebApiService WebApiService { get; set; } = null!;
27+
28+
[Import]
29+
internal IEnvironmentProvider EnvironmentProvider { get; set; } = null!;
30+
31+
[Import]
32+
internal IXrmMetaDataService MetaDataService { get; set; } = null!;
33+
34+
[Import]
35+
internal IRepositoryFactory RepositoryFactory { get; set; } = null!;
36+
37+
[Import]
38+
internal ILogger<RegisterPluginCommand> Logger { get; set; } = null!;
39+
40+
[Import]
41+
internal IPluginRegistrationService PluginRegistrationService { get; set; } = null!;
42+
43+
override protected async Task ExecuteAsync(OleMenuCmdEventArgs e)
44+
{
45+
var activeItem = await VS.Solutions.GetActiveItemAsync();
46+
if (activeItem is null || activeItem.FullPath is null || !(activeItem.Type is SolutionItemType.Project or SolutionItemType.PhysicalFile)) return;
47+
48+
var project = activeItem.Type == SolutionItemType.Project ? (Project)activeItem : activeItem.FindParent(SolutionItemType.Project) as Project;
49+
if (project is null)
50+
{
51+
await VS.MessageBox.ShowErrorAsync(Vsix.Name, "The selected item is not a project or part of a project.");
52+
return;
53+
}
54+
55+
var ui = new VsPluginRegistrationUI();
56+
var confirmed = await ui.ConfirmUnregsiterAssemblyAsync(project.Name);
57+
if (!confirmed) return;
58+
59+
await VS.StatusBar.StartAnimationAsync(StatusAnimation.General);
60+
await VS.StatusBar.ShowMessageAsync("Unregistering from Dataverse...");
61+
62+
try
63+
{
64+
var input = new RegistrationInput(
65+
itemFullPath: activeItem.FullPath,
66+
isProject: true,
67+
nugetPackagePath: null);
68+
69+
var result = await PluginRegistrationService!.UnregisterAsync(input, ui);
70+
71+
if (!result.Succeeded)
72+
{
73+
await VS.StatusBar.EndAnimationAsync(StatusAnimation.General);
74+
await VS.StatusBar.ShowMessageAsync("Unregistration failed.");
75+
await VS.MessageBox.ShowErrorAsync(Vsix.Name, result.Message);
76+
return;
77+
}
78+
79+
await VS.StatusBar.ShowMessageAsync(result.Message);
80+
}
81+
catch (Exception ex)
82+
{
83+
Logger.LogError(ex, "An unexpected error occurred during plugin registration.");
84+
await VS.MessageBox.ShowErrorAsync(Vsix.Name, "Unregistration failed due to an unexpected error. " + ex.Message);
85+
}
86+
finally
87+
{
88+
await VS.StatusBar.EndAnimationAsync(StatusAnimation.General);
89+
}
90+
}
91+
92+
93+
protected override async Task InitializeCompletedAsync()
94+
{
95+
//Command.Supported = false;
96+
try
97+
{
98+
var componentModel = await Package.GetServiceAsync<SComponentModel, IComponentModel>().ConfigureAwait(false);
99+
componentModel?.DefaultCompositionService.SatisfyImportsOnce(this);
100+
EnsureDependencies();
101+
}
102+
catch (Exception ex)
103+
{
104+
Logger?.LogError(ex, "An error occurred while initializing the RegisterPluginCommand.");
105+
await VS.MessageBox.ShowErrorAsync(Vsix.Name, "An error occurred while initializing the RegisterPluginCommand. " + ex.Message);
106+
return;
107+
}
108+
}
109+
110+
[MemberNotNull(nameof(Logger), nameof(MetaDataService), nameof(WebApiService),
111+
nameof(EnvironmentProvider), nameof(RepositoryFactory))]
112+
private void EnsureDependencies()
113+
{
114+
if (Logger == null) throw new InvalidOperationException(string.Format(Strings.MissingServiceDependency, nameof(RegisterPluginCommand), nameof(Logger)));
115+
if (MetaDataService == null) throw new InvalidOperationException(string.Format(Strings.MissingServiceDependency, nameof(RegisterPluginCommand), nameof(MetaDataService)));
116+
if (WebApiService == null) throw new InvalidOperationException(string.Format(Strings.MissingServiceDependency, nameof(RegisterPluginCommand), nameof(WebApiService)));
117+
if (EnvironmentProvider == null) throw new InvalidOperationException(string.Format(Strings.MissingServiceDependency, nameof(RegisterPluginCommand), nameof(EnvironmentProvider)));
118+
if (RepositoryFactory == null) throw new InvalidOperationException(string.Format(Strings.MissingServiceDependency, nameof(RegisterPluginCommand), nameof(RepositoryFactory)));
119+
if (PluginRegistrationService == null) throw new InvalidOperationException(string.Format(Strings.MissingServiceDependency, nameof(RegisterPluginCommand), nameof(PluginRegistrationService)));
120+
}
121+
}
122+
#nullable restore

src/XrmTools/CustomMonikers.imagemanifest

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
<!-- Version: 17.0.0.4 -->
44
<ImageManifest xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://schemas.microsoft.com/VisualStudio/ImageManifestSchema/2014">
55
<Symbols>
6-
<String Name="Resources" Value="/XrmTools;v1.5.5.0;Component/Resources" />
6+
<String Name="Resources" Value="/XrmTools;v1.5.6.0;Component/Resources" />
77
<Guid Name="AssetsGuid" Value="{b11584c1-89bd-47a3-b6a4-05b05dd5fc13}" />
88
<ID Name="ApplyToDataverse" Value="10" />
99
<ID Name="Dataverse" Value="20" />

src/XrmTools/Helpers/UpsertRequestBuilder.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ internal class UpsertRequestBuilder(
2525

2626
public UpsertRequestBuilder WithPackage()
2727
{
28-
var package = _config.Package;
28+
var package = _config.Package ?? throw new InvalidOperationException("Package configuration is null.");
2929
_requests.Add(new UpsertRequest(
3030
package.ToReference(),
3131
new JObject

src/XrmTools/Services/IPluginRegistrationUI.cs

Lines changed: 0 additions & 12 deletions
This file was deleted.

0 commit comments

Comments
 (0)