From f3b8a61391e2b25fb85c70c8ccb078a6e335fa99 Mon Sep 17 00:00:00 2001 From: Gabriela Trutan Date: Wed, 25 Sep 2024 14:51:37 +0200 Subject: [PATCH] SLVS-1448 Prevent deleting connection when in use (#5701) --- .../SlCoreConnectionAdapterTests.cs | 34 ++--- .../UI/ConnectedModeBindingServicesTests.cs | 4 +- .../PreventDeleteConnectionViewModelTests.cs | 65 ++++++++ .../ManageConnectionsViewModelTest.cs | 141 +++++++++++++++++- src/ConnectedMode/ConnectedMode.csproj | 3 + .../UI/ConnectedModeBindingServices.cs | 6 +- .../DeleteConnectionDialog.xaml | 2 +- .../PreventDeleteConnectionDialog.xaml | 73 +++++++++ .../PreventDeleteConnectionDialog.xaml.cs | 51 +++++++ .../PreventDeleteConnectionViewModel.cs | 37 +++++ .../ManageBinding/ManageBindingDialog.xaml.cs | 4 +- .../ManageConnectionsDialog.xaml.cs | 22 ++- .../ManageConnectionsViewModel.cs | 42 +++++- .../UI/Resources/UiResources.Designer.cs | 56 +++++-- .../UI/Resources/UiResources.resx | 26 +++- 15 files changed, 519 insertions(+), 47 deletions(-) create mode 100644 src/ConnectedMode.UnitTests/UI/DeleteConnection/PreventDeleteConnectionViewModelTests.cs create mode 100644 src/ConnectedMode/UI/DeleteConnection/PreventDeleteConnectionDialog.xaml create mode 100644 src/ConnectedMode/UI/DeleteConnection/PreventDeleteConnectionDialog.xaml.cs create mode 100644 src/ConnectedMode/UI/DeleteConnection/PreventDeleteConnectionViewModel.cs diff --git a/src/ConnectedMode.UnitTests/SlCoreConnectionAdapterTests.cs b/src/ConnectedMode.UnitTests/SlCoreConnectionAdapterTests.cs index b3f6423852..f6eef10f5e 100644 --- a/src/ConnectedMode.UnitTests/SlCoreConnectionAdapterTests.cs +++ b/src/ConnectedMode.UnitTests/SlCoreConnectionAdapterTests.cs @@ -39,8 +39,8 @@ namespace SonarLint.VisualStudio.ConnectedMode.UnitTests; public class SlCoreConnectionAdapterTests { private static readonly BasicAuthCredentials ValidToken = new ("I_AM_JUST_A_TOKEN", new SecureString()); - private static readonly ServerConnection.SonarQube SonarQubeConnection = new(new Uri("http://localhost:9000/"), new ServerConnectionSettings(true), ValidToken); - private static readonly ServerConnection.SonarCloud SonarCloudConnection = new("myOrg", new ServerConnectionSettings(true), ValidToken); + private readonly ServerConnection.SonarQube sonarQubeConnection = new(new Uri("http://localhost:9000/"), new ServerConnectionSettings(true), ValidToken); + private readonly ServerConnection.SonarCloud sonarCloudConnection = new("myOrg", new ServerConnectionSettings(true), ValidToken); private SlCoreConnectionAdapter testSubject; private ISLCoreServiceProvider slCoreServiceProvider; @@ -258,7 +258,7 @@ public async Task GetAllProjectsAsync_SwitchesToBackgroundThread() var threadHandlingMock = Substitute.For(); var slCoreConnectionAdapter = new SlCoreConnectionAdapter(slCoreServiceProvider, threadHandlingMock, logger); - await slCoreConnectionAdapter.GetAllProjectsAsync(SonarQubeConnection); + await slCoreConnectionAdapter.GetAllProjectsAsync(sonarQubeConnection); await threadHandlingMock.Received(1).RunOnBackgroundThread(Arg.Any>>>>()); } @@ -268,7 +268,7 @@ public async Task GetAllProjectsAsync_GettingConnectionConfigurationSLCoreServic { slCoreServiceProvider.TryGetTransientService(out IConnectionConfigurationSLCoreService _).Returns(false); - var response = await testSubject.GetAllProjectsAsync(SonarQubeConnection); + var response = await testSubject.GetAllProjectsAsync(sonarQubeConnection); logger.Received(1).LogVerbose($"[{nameof(IConnectionConfigurationSLCoreService)}] {SLCoreStrings.ServiceProviderNotInitialized}"); response.Success.Should().BeFalse(); @@ -277,7 +277,7 @@ public async Task GetAllProjectsAsync_GettingConnectionConfigurationSLCoreServic [TestMethod] public async Task GetAllProjectsAsync_ConnectionToSonarQubeWithToken_CallsGetAllProjectsAsyncWithCorrectParams() { - await testSubject.GetAllProjectsAsync(SonarQubeConnection); + await testSubject.GetAllProjectsAsync(sonarQubeConnection); await connectionConfigurationSlCoreService.Received(1) .GetAllProjectsAsync(Arg.Is(x => IsExpectedSonarQubeConnectionParams(x.transientConnection, ValidToken.UserName))); @@ -288,9 +288,9 @@ public async Task GetAllProjectsAsync_ConnectionToSonarQubeWithCredentials_Calls { const string username = "username"; const string password = "password"; - SonarQubeConnection.Credentials = new BasicAuthCredentials(username, password.CreateSecureString()); + sonarQubeConnection.Credentials = new BasicAuthCredentials(username, password.CreateSecureString()); - await testSubject.GetAllProjectsAsync(SonarQubeConnection); + await testSubject.GetAllProjectsAsync(sonarQubeConnection); await connectionConfigurationSlCoreService.Received(1) .GetAllProjectsAsync(Arg.Is(x => IsExpectedSonarQubeConnectionParams(x.transientConnection, username, password))); @@ -299,7 +299,7 @@ await connectionConfigurationSlCoreService.Received(1) [TestMethod] public async Task GetAllProjectsAsync_ConnectionToSonarCloudWithToken_CallsGetAllProjectsAsyncWithCorrectParams() { - await testSubject.GetAllProjectsAsync(SonarCloudConnection); + await testSubject.GetAllProjectsAsync(sonarCloudConnection); await connectionConfigurationSlCoreService.Received(1) .GetAllProjectsAsync(Arg.Is(x => IsExpectedSonarCloudConnectionParams(x.transientConnection, ValidToken.UserName))); @@ -310,9 +310,9 @@ public async Task GetAllProjectsAsync_ConnectionToSonarCloudWithCredentials_Call { const string username = "username"; const string password = "password"; - SonarCloudConnection.Credentials = new BasicAuthCredentials(username, password.CreateSecureString()); + sonarCloudConnection.Credentials = new BasicAuthCredentials(username, password.CreateSecureString()); - await testSubject.GetAllProjectsAsync(SonarCloudConnection); + await testSubject.GetAllProjectsAsync(sonarCloudConnection); await connectionConfigurationSlCoreService.Received(1) .GetAllProjectsAsync(Arg.Is(x => IsExpectedSonarCloudConnectionParams(x.transientConnection, username, password))); @@ -324,7 +324,7 @@ public async Task GetAllProjectsAsync_ReturnsResponseFromSlCore() List expectedServerProjects = [CreateSonarProjectDto("projKey1", "projName1"), CreateSonarProjectDto("projKey2", "projName2")]; connectionConfigurationSlCoreService.GetAllProjectsAsync(Arg.Any()).Returns(new GetAllProjectsResponse(expectedServerProjects)); - var response = await testSubject.GetAllProjectsAsync(SonarCloudConnection); + var response = await testSubject.GetAllProjectsAsync(sonarCloudConnection); response.Success.Should().BeTrue(); response.ResponseData.Count.Should().Be(expectedServerProjects.Count); @@ -340,7 +340,7 @@ public async Task GetServerProjectByKeyAsync_SwitchesToBackgroundThread() var threadHandlingMock = Substitute.For(); var slCoreConnectionAdapter = new SlCoreConnectionAdapter(slCoreServiceProvider, threadHandlingMock, logger); - await slCoreConnectionAdapter.GetServerProjectByKeyAsync(SonarCloudConnection, "server-project-key"); + await slCoreConnectionAdapter.GetServerProjectByKeyAsync(sonarCloudConnection, "server-project-key"); await threadHandlingMock.Received(1).RunOnBackgroundThread(Arg.Any>>>()); } @@ -350,7 +350,7 @@ public async Task GetServerProjectByKeyAsync_GettingConnectionConfigurationSLCor { slCoreServiceProvider.TryGetTransientService(out IConnectionConfigurationSLCoreService _).Returns(false); - var response = await testSubject.GetServerProjectByKeyAsync(SonarCloudConnection, "server-project-key"); + var response = await testSubject.GetServerProjectByKeyAsync(sonarCloudConnection, "server-project-key"); logger.Received(1).LogVerbose($"[{nameof(IConnectionConfigurationSLCoreService)}] {SLCoreStrings.ServiceProviderNotInitialized}"); response.Success.Should().BeFalse(); @@ -364,7 +364,7 @@ public async Task GetServerProjectByKeyAsync_SlCoreThrowsException_ReturnsFailed connectionConfigurationSlCoreService.When(x => x.GetProjectNamesByKeyAsync(Arg.Any())) .Do(_ => throw new Exception(exceptionMessage)); - var response = await testSubject.GetServerProjectByKeyAsync(SonarCloudConnection, "server-project-key"); + var response = await testSubject.GetServerProjectByKeyAsync(sonarCloudConnection, "server-project-key"); logger.Received(1).LogVerbose($"{Resources.GetServerProjectByKey_Fails}: {exceptionMessage}"); response.Success.Should().BeFalse(); @@ -378,7 +378,7 @@ public async Task GetServerProjectByKeyAsync_ProjectNotFound_ReturnsFailedRespon connectionConfigurationSlCoreService.GetProjectNamesByKeyAsync(Arg.Any()) .Returns(new GetProjectNamesByKeyResponse(slCoreResponse)); - var response = await testSubject.GetServerProjectByKeyAsync(SonarCloudConnection, "project-key"); + var response = await testSubject.GetServerProjectByKeyAsync(sonarCloudConnection, "project-key"); response.Success.Should().BeFalse(); response.ResponseData.Should().BeNull(); @@ -393,7 +393,7 @@ public async Task GetServerProjectByKeyAsync_ProjectFound_ReturnsSuccessResponse }; connectionConfigurationSlCoreService.GetProjectNamesByKeyAsync(Arg.Any()) .Returns(new GetProjectNamesByKeyResponse(slCoreResponse)); - var response = await testSubject.GetServerProjectByKeyAsync(SonarQubeConnection, "project-key"); + var response = await testSubject.GetServerProjectByKeyAsync(sonarQubeConnection, "project-key"); response.Success.Should().BeTrue(); response.ResponseData.Should().BeEquivalentTo(new ServerProject("project-key", "project-name")); @@ -407,7 +407,7 @@ public async Task GetAllProjectsAsync_SlCoreValidationThrowsException_ReturnsUns connectionConfigurationSlCoreService.When(x => x.GetAllProjectsAsync(Arg.Any())) .Do(_ => throw new Exception(exceptionMessage)); - var response = await testSubject.GetAllProjectsAsync(SonarCloudConnection); + var response = await testSubject.GetAllProjectsAsync(sonarCloudConnection); logger.Received(1).LogVerbose($"{Resources.GetAllProjects_Fails}: {exceptionMessage}"); response.Success.Should().BeFalse(); diff --git a/src/ConnectedMode.UnitTests/UI/ConnectedModeBindingServicesTests.cs b/src/ConnectedMode.UnitTests/UI/ConnectedModeBindingServicesTests.cs index 61b741097a..7ebf0103e3 100644 --- a/src/ConnectedMode.UnitTests/UI/ConnectedModeBindingServicesTests.cs +++ b/src/ConnectedMode.UnitTests/UI/ConnectedModeBindingServicesTests.cs @@ -23,6 +23,7 @@ using SonarLint.VisualStudio.ConnectedMode.UI; using SonarLint.VisualStudio.ConnectedMode.Shared; using SonarLint.VisualStudio.ConnectedMode.Binding; +using SonarLint.VisualStudio.Core.Binding; namespace SonarLint.VisualStudio.ConnectedMode.UnitTests.UI; @@ -35,6 +36,7 @@ public void MefCtor_CheckIsExported() MefTestHelpers.CheckTypeCanBeImported( MefTestHelpers.CreateExport(), MefTestHelpers.CreateExport(), - MefTestHelpers.CreateExport()); + MefTestHelpers.CreateExport(), + MefTestHelpers.CreateExport()); } } diff --git a/src/ConnectedMode.UnitTests/UI/DeleteConnection/PreventDeleteConnectionViewModelTests.cs b/src/ConnectedMode.UnitTests/UI/DeleteConnection/PreventDeleteConnectionViewModelTests.cs new file mode 100644 index 0000000000..76e22efa62 --- /dev/null +++ b/src/ConnectedMode.UnitTests/UI/DeleteConnection/PreventDeleteConnectionViewModelTests.cs @@ -0,0 +1,65 @@ +/* + * SonarLint for Visual Studio + * Copyright (C) 2016-2024 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +using SonarLint.VisualStudio.ConnectedMode.UI.DeleteConnection; + +namespace SonarLint.VisualStudio.ConnectedMode.UnitTests.UI.DeleteConnection; + +[TestClass] +public class PreventDeleteConnectionViewModelTests +{ + [TestMethod] + public void Ctor_SetsProperties() + { + var projectsToUnbind = Substitute.For>(); + var connectionInfo = new ConnectionInfo(default, default); + + var testSubject = new PreventDeleteConnectionViewModel(projectsToUnbind, connectionInfo); + + testSubject.ConnectionInfo.Should().BeSameAs(connectionInfo); + testSubject.ProjectsToUnbind.Should().BeSameAs(projectsToUnbind); + } + + [DataTestMethod] + public void DisplayProjectList_MultipleProjectsToUnbind_ReturnsTrue() + { + var projects = new[] { "binding1", "binding2"}; + + var testSubject = new PreventDeleteConnectionViewModel(projects, new ConnectionInfo(default, default)); + + testSubject.DisplayProjectList.Should().BeTrue(); + } + + [DataTestMethod] + public void DisplayProjectList_ProjectsIsNull_ReturnsFalse() + { + var testSubject = new PreventDeleteConnectionViewModel(null, new ConnectionInfo(default, default)); + + testSubject.DisplayProjectList.Should().BeFalse(); + } + + [DataTestMethod] + public void DisplayProjectList_NoProjectsToUnbind_ReturnsFalse() + { + var testSubject = new PreventDeleteConnectionViewModel([], new ConnectionInfo(default, default)); + + testSubject.DisplayProjectList.Should().BeFalse(); + } +} diff --git a/src/ConnectedMode.UnitTests/UI/ManageConnections/ManageConnectionsViewModelTest.cs b/src/ConnectedMode.UnitTests/UI/ManageConnections/ManageConnectionsViewModelTest.cs index a7ceb662fa..815b6bd1f1 100644 --- a/src/ConnectedMode.UnitTests/UI/ManageConnections/ManageConnectionsViewModelTest.cs +++ b/src/ConnectedMode.UnitTests/UI/ManageConnections/ManageConnectionsViewModelTest.cs @@ -24,6 +24,7 @@ using SonarLint.VisualStudio.ConnectedMode.UI.ManageConnections; using SonarLint.VisualStudio.ConnectedMode.UI.Resources; using SonarLint.VisualStudio.Core; +using SonarLint.VisualStudio.Core.Binding; namespace SonarLint.VisualStudio.ConnectedMode.UnitTests.UI.ManageConnections; @@ -37,19 +38,22 @@ public class ManageConnectionsViewModelTest private IServerConnectionsRepositoryAdapter serverConnectionsRepositoryAdapter; private IThreadHandling threadHandling; private ILogger logger; + private IConnectedModeBindingServices connectedModeBindingServices; + private ISolutionBindingRepository solutionBindingRepository; [TestInitialize] public void TestInitialize() { twoConnections = [ - new Connection(new ConnectionInfo("http://localhost:9000", ConnectionServerType.SonarQube), true), - new Connection(new ConnectionInfo("https://sonarcloud.io/organizations/myOrg", ConnectionServerType.SonarCloud), false) + new Connection(new ConnectionInfo(new Uri("http://localhost:9000").ToString(), ConnectionServerType.SonarQube), true), + new Connection(new ConnectionInfo("myOrg", ConnectionServerType.SonarCloud), false) ]; progressReporterViewModel = Substitute.For(); connectedModeServices = Substitute.For(); + connectedModeBindingServices = Substitute.For(); - testSubject = new ManageConnectionsViewModel(connectedModeServices, progressReporterViewModel); + testSubject = new ManageConnectionsViewModel(connectedModeServices, connectedModeBindingServices, progressReporterViewModel); MockServices(); } @@ -277,6 +281,124 @@ public void CreateNewConnection_ConnectionWasNotAddedToRepository_DoesNotAddConn serverConnectionsRepositoryAdapter.Received(1).TryAddConnection(connectionToAdd, Arg.Any()); } + [TestMethod] + public async Task GetConnectionReferencesWithProgressAsync_CalculatesReferencesAndReportsProgress() + { + progressReporterViewModel.ExecuteTaskWithProgressAsync(Arg.Any>>>()).Returns(new AdapterResponseWithData>(true, [])); + + await testSubject.GetConnectionReferencesWithProgressAsync(new ConnectionViewModel(new Connection(new ConnectionInfo("myOrg", ConnectionServerType.SonarCloud)))); + + await progressReporterViewModel.Received(1) + .ExecuteTaskWithProgressAsync( + Arg.Is>>>(x => + x.ProgressStatus == UiResources.CalculatingConnectionReferencesText && + x.WarningText == UiResources.CalculatingConnectionReferencesFailedText)); + } + + [TestMethod] + public async Task GetConnectionReferencesOnBackgroundThreadAsync_RunsOnBackgroundThread() + { + threadHandling.RunOnBackgroundThread(Arg.Any>>>>()).Returns(new AdapterResponseWithData>(true, [])); + + await testSubject.GetConnectionReferencesOnBackgroundThreadAsync(new ConnectionViewModel(new Connection(new ConnectionInfo("myOrg", ConnectionServerType.SonarCloud)))); + + await threadHandling.Received(1).RunOnBackgroundThread(Arg.Any>>>>()); + } + + [TestMethod] + [DataRow(true)] + [DataRow(false)] + public async Task GetConnectionReferencesOnBackgroundThreadAsync_ReturnsCalculatedReferences(bool expectedResponse) + { + var bindingKey = "localBindingKey"; + threadHandling.RunOnBackgroundThread(Arg.Any>>>>()).Returns(new AdapterResponseWithData>(expectedResponse, [bindingKey])); + + var responses = await testSubject.GetConnectionReferencesOnBackgroundThreadAsync(new ConnectionViewModel(new Connection(new ConnectionInfo("myOrg", ConnectionServerType.SonarCloud)))); + + responses.Success.Should().Be(expectedResponse); + responses.ResponseData.Should().Contain(bindingKey); + } + + [TestMethod] + public void GetConnectionReferences_NoBindingReferencesConnection_ReturnsEmptyList() + { + var response = testSubject.GetConnectionReferences(new ConnectionViewModel(new Connection(new ConnectionInfo("myOrg", ConnectionServerType.SonarCloud)))); + + response.Success.Should().BeTrue(); + response.ResponseData.Should().BeEmpty(); + } + + [TestMethod] + public void GetConnectionReferences_OneBindingReferencesSonarCloudConnection_ReturnsOneBinding() + { + var bindingKey = "localBindingKey"; + var sonarCloud = twoConnections.First(conn => conn.Info.ServerType == ConnectionServerType.SonarCloud); + solutionBindingRepository.List().Returns([new BoundServerProject(bindingKey, "myProject", CreateSonarCloudServerConnection(sonarCloud))]); + + var response = testSubject.GetConnectionReferences(new ConnectionViewModel(sonarCloud)); + + response.Success.Should().BeTrue(); + response.ResponseData.Should().Contain(bindingKey); + } + + [TestMethod] + public void GetConnectionReferences_OneBindingReferencesSonarQubeConnection_ReturnsOneBinding() + { + var bindingKey = "localBindingKey"; + var sonarQube = twoConnections.First(conn => conn.Info.ServerType == ConnectionServerType.SonarQube); + solutionBindingRepository.List().Returns([new BoundServerProject(bindingKey, "myProject", CreateSonarQubeServerConnection(sonarQube))]); + + var response = testSubject.GetConnectionReferences(new ConnectionViewModel(sonarQube)); + + response.Success.Should().BeTrue(); + response.ResponseData.Should().Contain(bindingKey); + } + + [TestMethod] + public void GetConnectionReferences_TwoBindingsReferencesSonarQubeConnection_ReturnsTwoBindings() + { + var sonarQube = twoConnections.First(conn => conn.Info.ServerType == ConnectionServerType.SonarQube); + var serverConnectionToBeRemoved = CreateSonarQubeServerConnection(sonarQube); + solutionBindingRepository.List().Returns([ + new BoundServerProject("binding1", "myProject", serverConnectionToBeRemoved), + new BoundServerProject("binding2", "myProject2", serverConnectionToBeRemoved) + ]); + + var response = testSubject.GetConnectionReferences(new ConnectionViewModel(sonarQube)); + + response.Success.Should().BeTrue(); + response.ResponseData.Should().BeEquivalentTo(["binding1", "binding2"]); + } + + [TestMethod] + public void GetConnectionReferences_TwoBindingsReferencesSonarCloudConnection_ReturnsTwoBindings() + { + var sonarCloud = twoConnections.First(conn => conn.Info.ServerType == ConnectionServerType.SonarQube); + var serverConnectionToBeRemoved = CreateSonarCloudServerConnection(sonarCloud); + solutionBindingRepository.List().Returns([ + new BoundServerProject("binding1", "myProject", serverConnectionToBeRemoved), + new BoundServerProject("binding2", "myProject2", serverConnectionToBeRemoved) + ]); + + var response = testSubject.GetConnectionReferences(new ConnectionViewModel(sonarCloud)); + + response.Success.Should().BeTrue(); + response.ResponseData.Should().BeEquivalentTo(["binding1", "binding2"]); + } + + [TestMethod] + public void GetConnectionReferences_BindingRepositoryThrowsException_ReturnsEmptyList() + { + var exceptionMsg = "Failed to retrieve bindings"; + solutionBindingRepository.When(repo => repo.List()).Do(_ => throw new Exception(exceptionMsg)); + + var response = testSubject.GetConnectionReferences(new ConnectionViewModel(twoConnections.First())); + + response.Success.Should().BeFalse(); + response.ResponseData.Should().BeEmpty(); + logger.Received(1).WriteLine(nameof(testSubject.GetConnectionReferences), exceptionMsg); + } + private void HasExpectedConnections(IEnumerable expectedConnections) { testSubject.ConnectionViewModels.Should().NotBeNull(); @@ -310,6 +432,9 @@ private void MockServices() connectedModeServices.ThreadHandling.Returns(threadHandling); connectedModeServices.Logger.Returns(logger); MockTryGetConnections(twoConnections); + + solutionBindingRepository = Substitute.For(); + connectedModeBindingServices.SolutionBindingRepository.Returns(solutionBindingRepository); } private void MockTryGetConnections(List connections) @@ -325,4 +450,14 @@ private static Connection CreateSonarCloudConnection() { return new Connection(new ConnectionInfo("mySecondOrg", ConnectionServerType.SonarCloud), false); } + + private static ServerConnection.SonarCloud CreateSonarCloudServerConnection(Connection sonarCloud) + { + return new ServerConnection.SonarCloud(sonarCloud.Info.Id); + } + + private static ServerConnection.SonarQube CreateSonarQubeServerConnection(Connection sonarQube) + { + return new ServerConnection.SonarQube(new Uri(sonarQube.Info.Id)); + } } diff --git a/src/ConnectedMode/ConnectedMode.csproj b/src/ConnectedMode/ConnectedMode.csproj index 0664c21d34..b7e4cb3a15 100644 --- a/src/ConnectedMode/ConnectedMode.csproj +++ b/src/ConnectedMode/ConnectedMode.csproj @@ -53,6 +53,9 @@ + + MSBuild:Compile + MSBuild:Compile diff --git a/src/ConnectedMode/UI/ConnectedModeBindingServices.cs b/src/ConnectedMode/UI/ConnectedModeBindingServices.cs index 79e48054c0..0ac2bd1511 100644 --- a/src/ConnectedMode/UI/ConnectedModeBindingServices.cs +++ b/src/ConnectedMode/UI/ConnectedModeBindingServices.cs @@ -22,6 +22,7 @@ using SonarLint.VisualStudio.ConnectedMode.Binding; using SonarLint.VisualStudio.ConnectedMode.Shared; using SonarLint.VisualStudio.Core; +using SonarLint.VisualStudio.Core.Binding; namespace SonarLint.VisualStudio.ConnectedMode.UI; @@ -30,6 +31,7 @@ public interface IConnectedModeBindingServices public IBindingController BindingController { get; } public ISolutionInfoProvider SolutionInfoProvider { get; } public ISharedBindingConfigProvider SharedBindingConfigProvider { get; } + public ISolutionBindingRepository SolutionBindingRepository { get; } } [Export(typeof(IConnectedModeBindingServices))] @@ -38,10 +40,12 @@ public interface IConnectedModeBindingServices public class ConnectedModeBindingServices( IBindingController bindingController, ISolutionInfoProvider solutionInfoProvider, - ISharedBindingConfigProvider sharedBindingConfigProvider) + ISharedBindingConfigProvider sharedBindingConfigProvider, + ISolutionBindingRepository solutionBindingRepository) : IConnectedModeBindingServices { public IBindingController BindingController { get; } = bindingController; public ISolutionInfoProvider SolutionInfoProvider { get; } = solutionInfoProvider; public ISharedBindingConfigProvider SharedBindingConfigProvider { get; } = sharedBindingConfigProvider; + public ISolutionBindingRepository SolutionBindingRepository { get; } = solutionBindingRepository; } diff --git a/src/ConnectedMode/UI/DeleteConnection/DeleteConnectionDialog.xaml b/src/ConnectedMode/UI/DeleteConnection/DeleteConnectionDialog.xaml index 092024da0c..6bca2088e1 100644 --- a/src/ConnectedMode/UI/DeleteConnection/DeleteConnectionDialog.xaml +++ b/src/ConnectedMode/UI/DeleteConnection/DeleteConnectionDialog.xaml @@ -42,6 +42,7 @@ + -