diff --git a/src/AzureIoTHub.Portal.Server.Tests.Unit/Pages/Settings/DeviceTagsPageTests.cs b/src/AzureIoTHub.Portal.Server.Tests.Unit/Pages/Settings/DeviceTagsPageTests.cs index b2472a2b3..32563fc6d 100644 --- a/src/AzureIoTHub.Portal.Server.Tests.Unit/Pages/Settings/DeviceTagsPageTests.cs +++ b/src/AzureIoTHub.Portal.Server.Tests.Unit/Pages/Settings/DeviceTagsPageTests.cs @@ -6,7 +6,7 @@ namespace AzureIoTHub.Portal.Server.Tests.Unit.Pages.Settings using System; using System.Collections.Generic; using System.Linq; - using System.Threading.Tasks; + //using System.Threading.Tasks; using AutoFixture; using AzureIoTHub.Portal.Client.Exceptions; using AzureIoTHub.Portal.Client.Models; @@ -19,6 +19,7 @@ namespace AzureIoTHub.Portal.Server.Tests.Unit.Pages.Settings using Moq; using MudBlazor; using NUnit.Framework; + using System.Threading.Tasks; [TestFixture] public class DeviceTagsPageTests : BlazorUnitTest @@ -125,33 +126,56 @@ public void OnInitializedAsyncShouldProcessProblemDetailsExceptionWhenIssueOccur [Test] - public void ClickOnSaveShouldUpdateTagList() + public void ClickOnSaveShouldCreateUpdateTag() { - var expectedTags = new List - { - new() { - Label = "Label", - Name = "Name", - Required = false, - Searchable = false - } - }; - + //Arrange _ = this.mockDeviceTagSettingsClientService.Setup(service => service.GetDeviceTags()) - .ReturnsAsync(expectedTags); - - _ = this.mockDeviceTagSettingsClientService.Setup(service => service.UpdateDeviceTags(It.IsAny>())) + .ReturnsAsync(new List + { + new() + { + Label = "tagLabel", Name = "tagName", Required = false, + Searchable = false + } + }); + _ = this.mockDeviceTagSettingsClientService.Setup(service => service.CreateOrUpdateDeviceTag(It.IsAny())) .Returns(Task.CompletedTask); _ = this.mockSnackbarService.Setup(c => c.Add(It.IsAny(), Severity.Success, null)).Returns((Snackbar)null); var cut = RenderComponent(); - cut.WaitForAssertion(() => cut.Find("#saveButton")); cut.WaitForAssertion(() => cut.Markup.Should().NotContain("Loading...")); // Act - cut.Find("#saveButton").Click(); + cut.WaitForElement("#saveButton").Click(); + + cut.WaitForAssertion(() => MockRepository.VerifyAll()); + } + + [Test] + public void ClickOnDeleteShouldDeleteTag() + { + //Arrange + const string deviceTagName = "tagName"; + + _ = this.mockDeviceTagSettingsClientService.Setup(service => service.GetDeviceTags()) + .ReturnsAsync(new List + { + new() + { + Label = "tagLabel", Name = deviceTagName, Required = false, + Searchable = false + } + }); + _ = this.mockDeviceTagSettingsClientService.Setup(service => service.DeleteDeviceTagByName(deviceTagName)) + .Returns(Task.CompletedTask); + + var cut = RenderComponent(); + cut.WaitForAssertion(() => cut.Markup.Should().NotContain("Loading...")); + + // Act + cut.WaitForElement("#deleteButton").Click(); cut.WaitForAssertion(() => MockRepository.VerifyAll()); } @@ -232,7 +256,7 @@ public void ClickOnSaveShouldProcessProblemDetailsExceptionIfIssueOccursWhenUpda new () { Label = "Label", Name = "Name", Required = false, Searchable = false } }); - _ = this.mockDeviceTagSettingsClientService.Setup(service => service.UpdateDeviceTags(It.IsAny>())) + _ = this.mockDeviceTagSettingsClientService.Setup(service => service.CreateOrUpdateDeviceTag(It.IsAny())) .ThrowsAsync(new ProblemDetailsException(new ProblemDetailsWithExceptionDetails())); // Act diff --git a/src/AzureIoTHub.Portal.Server.Tests.Unit/Services/DeviceTagSettingsClientServiceTests.cs b/src/AzureIoTHub.Portal.Server.Tests.Unit/Services/DeviceTagSettingsClientServiceTests.cs index a42f2de63..fb55c0e2d 100644 --- a/src/AzureIoTHub.Portal.Server.Tests.Unit/Services/DeviceTagSettingsClientServiceTests.cs +++ b/src/AzureIoTHub.Portal.Server.Tests.Unit/Services/DeviceTagSettingsClientServiceTests.cs @@ -3,9 +3,9 @@ namespace AzureIoTHub.Portal.Server.Tests.Unit.Services { - using System.Collections.Generic; + //using System.Collections.Generic; using System.Linq; - using System.Net; + //using System.Net; using System.Net.Http; using System.Threading.Tasks; using AutoFixture; @@ -49,28 +49,28 @@ public async Task GetDeviceTagsShouldReturnDeviceTags() MockHttpClient.VerifyNoOutstandingExpectation(); } - [Test] - public async Task UpdateDeviceTagsShouldUpdateDeviceTags() - { - // Arrange - var expectedDeviceTags = Fixture.Build().CreateMany(3).ToList(); + //[Test] + //public async Task UpdateDeviceTagsShouldUpdateDeviceTags() + //{ + // // Arrange + // var expectedDeviceTags = Fixture.Build().CreateMany(3).ToList(); - _ = MockHttpClient.When(HttpMethod.Post, "/api/settings/device-tags") - .With(m => - { - _ = m.Content.Should().BeAssignableTo>>(); - var tags = m.Content as ObjectContent>; - _ = tags.Value.Should().BeEquivalentTo(expectedDeviceTags); - return true; - }) - .Respond(HttpStatusCode.Created); + // _ = MockHttpClient.When(HttpMethod.Post, "/api/settings/device-tags") + // .With(m => + // { + // _ = m.Content.Should().BeAssignableTo>>(); + // var tags = m.Content as ObjectContent>; + // _ = tags.Value.Should().BeEquivalentTo(expectedDeviceTags); + // return true; + // }) + // .Respond(HttpStatusCode.Created); - // Act - await this.deviceTagSettingsClientService.UpdateDeviceTags(expectedDeviceTags); + // // Act + // await this.deviceTagSettingsClientService.UpdateDeviceTags(expectedDeviceTags); - // Assert - MockHttpClient.VerifyNoOutstandingRequest(); - MockHttpClient.VerifyNoOutstandingExpectation(); - } + // // Assert + // MockHttpClient.VerifyNoOutstandingRequest(); + // MockHttpClient.VerifyNoOutstandingExpectation(); + //} } } diff --git a/src/AzureIoTHub.Portal/Client/Pages/Settings/DeviceTagsPage.razor b/src/AzureIoTHub.Portal/Client/Pages/Settings/DeviceTagsPage.razor index 63001622c..4209f113c 100644 --- a/src/AzureIoTHub.Portal/Client/Pages/Settings/DeviceTagsPage.razor +++ b/src/AzureIoTHub.Portal/Client/Pages/Settings/DeviceTagsPage.razor @@ -6,83 +6,87 @@ @inject IDeviceTagSettingsClientService DeviceTagSettingsClientService - - - - - Tags - - - - - - - - - - - - - - - Name - Label - Required - Searchable - Delete - - - - - - - - - - - - - - - - - - - - - + + + + + Tags + + + - - - - Add a new Tag - - - - No matching records found - - - Loading... - - - - Save Changes - - + + + + + + + + + + + + Name + Label + Required + Searchable + Delete + Validate + + + + + + + + + + + + + + + + + + + + + + + + + + Save Changes> + + + + + Add a new Tag + + + + No matching records found + + + Loading... + + + @code { [CascadingParameter] - public Error Error {get; set;} + public Error Error { get; set; } List Tags { get; set; } = new(); private MudForm FormName { get; set; } private MudForm FormLabel { get; set; } - + private bool isProcessing; protected override async Task OnInitializedAsync() @@ -120,48 +124,60 @@ private void DeleteTag(DeviceTag item) { - Tags.Remove(item); + try + { + DeviceTagSettingsClientService.DeleteDeviceTagByName(item.Name); + Tags.Remove(item); + } + catch (ProblemDetailsException exception) + { + Error?.ProcessProblemDetails(exception); + } } - private async Task Save() + private async Task Save(DeviceTag deviceTag) { - isProcessing = true; + try + { + isProcessing = true; - // Checks empty field and regex validation - await FormLabel.Validate(); - await FormName.Validate(); + await FormLabel.Validate(); + await FormName.Validate(); - // Checks duplicate - bool duplicated = false; - var query = Tags.GroupBy(x => x.Name) + // Checks duplicate + bool duplicated = false; + var query = Tags.GroupBy(x => x.Name) .Where(x => x.Count() > 1) .Select(x => x.Key) .ToList(); - foreach (var item in query) - { - Snackbar.Add($"The name '{item}' appears more than once!", Severity.Warning); - duplicated = true; - } + foreach (var item in query) + { + Snackbar.Add($"The name '{item}' appears more than once!", Severity.Warning); + duplicated = true; + } - if (FormLabel.IsValid && FormName.IsValid && !duplicated) - { - try + if (!FormLabel.IsValid || !FormName.IsValid || duplicated) { - await DeviceTagSettingsClientService.UpdateDeviceTags(Tags); + Snackbar.Add("One or more validation errors occurred", Severity.Error); - // Prompts a snack bar to inform the action was successful - Snackbar.Add($"Settings have been successfully updated!", Severity.Success); - } - catch (ProblemDetailsException exception) + isProcessing = false; + + return; + } + else { - Error?.ProcessProblemDetails(exception); + await DeviceTagSettingsClientService.CreateOrUpdateDeviceTag(deviceTag); } + + Snackbar.Add($"Settings have been successfully updated!", Severity.Success); } - else + catch (ProblemDetailsException exception) { - Snackbar.Add("One or more validation errors occurred", Severity.Error); + Error?.ProcessProblemDetails(exception); + } + finally + { + isProcessing = false; } - - isProcessing = false; } } diff --git a/src/AzureIoTHub.Portal/Client/Services/DeviceTagSettingsClientService.cs b/src/AzureIoTHub.Portal/Client/Services/DeviceTagSettingsClientService.cs index d07bd2225..406156712 100644 --- a/src/AzureIoTHub.Portal/Client/Services/DeviceTagSettingsClientService.cs +++ b/src/AzureIoTHub.Portal/Client/Services/DeviceTagSettingsClientService.cs @@ -6,7 +6,9 @@ namespace AzureIoTHub.Portal.Client.Services using System.Collections.Generic; using System.Net.Http; using System.Net.Http.Json; + using System.Text; using System.Threading.Tasks; + using Newtonsoft.Json; using Portal.Models.v10; public class DeviceTagSettingsClientService : IDeviceTagSettingsClientService @@ -18,14 +20,22 @@ public DeviceTagSettingsClientService(HttpClient http) this.http = http; } - public async Task> GetDeviceTags() + public Task CreateOrUpdateDeviceTag(DeviceTag deviceTag) { - return await this.http.GetFromJsonAsync>("api/settings/device-tags"); + var deviceTagAsJson = JsonConvert.SerializeObject(deviceTag); + using var content = new StringContent(deviceTagAsJson, Encoding.UTF8, "application/json"); + return this.http.PatchAsync("api/settings/device-tags", content); + } + + public Task DeleteDeviceTagByName(string deviceTagName) + { + return this.http.DeleteAsync($"api/settings/device-tags/{deviceTagName}"); } - public Task UpdateDeviceTags(IList deviceTags) + public async Task> GetDeviceTags() { - return this.http.PostAsJsonAsync("api/settings/device-tags", deviceTags); + return await this.http.GetFromJsonAsync>("api/settings/device-tags"); } + } } diff --git a/src/AzureIoTHub.Portal/Client/Services/IDeviceTagSettingsClientService.cs b/src/AzureIoTHub.Portal/Client/Services/IDeviceTagSettingsClientService.cs index f27a8962d..b7f0195f4 100644 --- a/src/AzureIoTHub.Portal/Client/Services/IDeviceTagSettingsClientService.cs +++ b/src/AzureIoTHub.Portal/Client/Services/IDeviceTagSettingsClientService.cs @@ -11,6 +11,8 @@ public interface IDeviceTagSettingsClientService { Task> GetDeviceTags(); - Task UpdateDeviceTags(IList deviceTags); + Task CreateOrUpdateDeviceTag(DeviceTag deviceTag); + + Task DeleteDeviceTagByName(string deviceTagName); } }