diff --git a/BusinessLogic/Commands/Adaptivity/Task/DeleteAdaptivityTask.cs b/BusinessLogic/Commands/Adaptivity/Task/DeleteAdaptivityTask.cs index e9401b913..7190cffa6 100644 --- a/BusinessLogic/Commands/Adaptivity/Task/DeleteAdaptivityTask.cs +++ b/BusinessLogic/Commands/Adaptivity/Task/DeleteAdaptivityTask.cs @@ -38,7 +38,6 @@ public void Execute() "Deleted AdaptivityTask {AdaptivityTaskName} ({AdaptivityTaskId}) in AdaptivityContent {AdaptivityContentName}", AdaptivityTask.Name, AdaptivityTask.Id, AdaptivityContent.Name); MappingAction.Invoke(AdaptivityContent); - AdaptivityContent.UnsavedChanges = true; } else { diff --git a/IntegrationTest/Components/Adaptivity/Dialogues/AdaptivityContentDialogIt.cs b/IntegrationTest/Components/Adaptivity/Dialogues/AdaptivityContentDialogIt.cs index 92332f76f..1fcda90fe 100644 --- a/IntegrationTest/Components/Adaptivity/Dialogues/AdaptivityContentDialogIt.cs +++ b/IntegrationTest/Components/Adaptivity/Dialogues/AdaptivityContentDialogIt.cs @@ -4,15 +4,14 @@ using System.Threading.Tasks; using AutoMapper; using Bunit; -using BusinessLogic.Entities.LearningContent.Adaptivity; using Microsoft.AspNetCore.Components.Web; using Microsoft.Extensions.DependencyInjection; using MudBlazor; using NSubstitute; using NUnit.Framework; using Presentation.Components.Adaptivity.Dialogues; -using Presentation.Components.Forms; using Presentation.PresentationLogic.API; +using Presentation.PresentationLogic.LearningContent; using Presentation.PresentationLogic.LearningContent.AdaptivityContent; using Presentation.PresentationLogic.LearningContent.AdaptivityContent.Question; using Shared.Adaptivity; @@ -28,25 +27,26 @@ public void Setup() { PresentationLogic = Substitute.For(); Context.Services.AddSingleton(PresentationLogic); - FormDataContainer = Substitute.For>(); - FormDataContainer.FormModel.Returns(new AdaptivityContentFormModel()); - Context.Services.AddSingleton(FormDataContainer); - AdaptivityContent = FormModelProvider.GetAdaptivityContent(); + AdaptivityContentFormModel = FormModelProvider.GetAdaptivityContent(); Tasks = new List(); - AdaptivityContent.Tasks = Tasks; + AdaptivityContentFormModel.Tasks = Tasks; Mapper = Substitute.For(); - Mapper.When(x => x.Map(Arg.Any(), Arg.Any())).Do(y => + Mapper.When(x => x.Map(Arg.Any(), Arg.Any())).Do(y => { y.Arg().Tasks = Tasks; }); Context.Services.AddSingleton(Mapper); - PresentationLogic.When(x => x.CreateAdaptivityTask(AdaptivityContent, Arg.Any())).Do(y => + PresentationLogic.When(x => x.CreateAdaptivityTask(AdaptivityContentFormModel, Arg.Any())).Do(y => { var task = Substitute.For(); task.Name.Returns(y.ArgAt(1)); Tasks.Add(task); }); - PresentationLogic.When(x => x.DeleteAdaptivityTask(AdaptivityContent, Arg.Any())).Do( + PresentationLogic.When(x => + x.DeleteAdaptivityTask(AdaptivityContentFormModel, Arg.Any())).Do( + y => { Tasks.Remove(y.ArgAt(1)); }); + PresentationLogic.When(x => + x.DeleteAdaptivityTask(Arg.Any(), Arg.Any())).Do( y => { Tasks.Remove(y.ArgAt(1)); }); Context.ComponentFactories.AddStub(); } @@ -55,25 +55,35 @@ public void Setup() public void Teardown() { DialogProvider.Dispose(); + ContentToEdit = null!; + } + + private void SetupWithContentToEdit() + { + Setup(); + ContentToEdit = (AdaptivityContentViewModel)ViewModelProvider.GetAdaptivityContent(); + ((AdaptivityContentViewModel)ContentToEdit).Tasks = Tasks; } private IDialogReference Dialog { get; set; } = null!; - private AdaptivityContentFormModel AdaptivityContent { get; set; } = null!; + private AdaptivityContentFormModel AdaptivityContentFormModel { get; set; } = null!; private List Tasks { get; set; } = null!; private IPresentationLogic PresentationLogic { get; set; } = null!; private IMapper Mapper { get; set; } = null!; - private IFormDataContainer FormDataContainer { get; set; } = null!; + + private ILearningContentViewModel ContentToEdit { get; set; } = null!; private async Task GetDialogAsync() { var dialogParameters = new DialogParameters { - { nameof(AdaptivityContentDialog.MyContent), AdaptivityContent }, + { nameof(AdaptivityContentDialog.MyContent), AdaptivityContentFormModel }, + { nameof(AdaptivityContentDialog.ContentToEdit), ContentToEdit }, { nameof(AdaptivityContentDialog.DebounceInterval), 10 } }; Dialog = await OpenDialogAndGetDialogReferenceAsync(options: new DialogOptions(), parameters: dialogParameters); - Mapper.Received(1).Map(AdaptivityContent, FormDataContainer.FormModel); + Mapper.Received(1).Map(AdaptivityContentFormModel, ContentToEdit); Mapper.ClearReceivedCalls(); } @@ -84,22 +94,38 @@ public async Task AddTaskButtonClicked_CallsPresentationLogicAndMapper() await GetDialogAsync(); var button = DialogProvider.FindComponent().Find("button"); await button.ClickAsync(new MouseEventArgs()); - PresentationLogic.Received(1).CreateAdaptivityTask(AdaptivityContent, "AdaptivityContentDialog.NewTask.Name1"); - Mapper.Received(1).Map(AdaptivityContent, FormDataContainer.FormModel); + PresentationLogic.Received(1) + .CreateAdaptivityTask(AdaptivityContentFormModel, "AdaptivityContentDialog.NewTask.Name1"); + Mapper.Received(1).Map(AdaptivityContentFormModel, ContentToEdit); + } + + [Test] + // ANF-ID: [AWA0007] + public async Task DeleteTaskButtonClicked_ContentToEditNull_CallsPresentationLogic() + { + await GetDialogAsync(); + var button = DialogProvider.FindComponent().Find("button"); + await button.ClickAsync(new MouseEventArgs()); + var buttons = DialogProvider.FindComponents(); + var deleteButton = buttons[0].Find("button"); + var task = AdaptivityContentFormModel.Tasks.Last(); + await deleteButton.ClickAsync(new MouseEventArgs()); + PresentationLogic.Received(1).DeleteAdaptivityTask(AdaptivityContentFormModel, task); } [Test] // ANF-ID: [AWA0007] - public async Task DeleteTaskButtonClicked_CallsPresentationLogic() + public async Task DeleteTaskButtonClicked_ContentToEditNotNull_CallsPresentationLogic() { + SetupWithContentToEdit(); await GetDialogAsync(); var button = DialogProvider.FindComponent().Find("button"); await button.ClickAsync(new MouseEventArgs()); var buttons = DialogProvider.FindComponents(); var deleteButton = buttons[0].Find("button"); - var task = AdaptivityContent.Tasks.Last(); + var task = ((AdaptivityContentViewModel)ContentToEdit).Tasks.Last(); await deleteButton.ClickAsync(new MouseEventArgs()); - PresentationLogic.Received(1).DeleteAdaptivityTask(AdaptivityContent, task); + PresentationLogic.Received(1).DeleteAdaptivityTask((AdaptivityContentViewModel)ContentToEdit, task); } [Test] @@ -138,7 +164,7 @@ public async Task ChangeRequiredDifficulty_CallsPresentationLogic([Values] bool task.MinimumRequiredDifficulty.Returns(wasSelectedAsRequired ? QuestionDifficulty.Medium : null); - AdaptivityContent.Tasks.Add(task); + AdaptivityContentFormModel.Tasks.Add(task); await GetDialogAsync(); var iconButtons = DialogProvider.FindComponents(); var keyButton = iconButtons[3].Find("button"); @@ -155,7 +181,7 @@ public async Task DeleteQuestionButtonClicked_CallsPresentationLogic() var question = Substitute.For(); question.Difficulty.Returns(QuestionDifficulty.Medium); task.Questions.Returns(new List { question }); - AdaptivityContent.Tasks.Add(task); + AdaptivityContentFormModel.Tasks.Add(task); await GetDialogAsync(); var iconButtons = DialogProvider.FindComponents(); var deleteButton = iconButtons[2].Find("button"); diff --git a/Presentation/Components/Adaptivity/Dialogues/AdaptivityContentDialog.razor b/Presentation/Components/Adaptivity/Dialogues/AdaptivityContentDialog.razor index b5a8cab61..1996df72b 100644 --- a/Presentation/Components/Adaptivity/Dialogues/AdaptivityContentDialog.razor +++ b/Presentation/Components/Adaptivity/Dialogues/AdaptivityContentDialog.razor @@ -1,12 +1,11 @@ +@using System.Diagnostics.CodeAnalysis +@using AutoMapper +@using Microsoft.Extensions.Localization @using Presentation.PresentationLogic.API +@using Presentation.PresentationLogic.LearningContent @using Presentation.PresentationLogic.LearningContent.AdaptivityContent @using Presentation.PresentationLogic.LearningContent.AdaptivityContent.Question @using Shared.Adaptivity -@using Microsoft.Extensions.Localization -@using AutoMapper -@using BusinessLogic.Entities.LearningContent.Adaptivity -@using Presentation.Components.Forms -@using System.Diagnostics.CodeAnalysis

@Localizer["AdaptivityContentDialog.Subtitle"]

@@ -43,13 +42,13 @@ - @@ -63,10 +62,10 @@ @foreach (var difficulty in Enum.GetValues(typeof(QuestionDifficulty)).Cast()) { - @if (GetTaskQuestionWithQuestionDifficulty(context, difficulty) is {} question) + @if (GetTaskQuestionWithQuestionDifficulty(context, difficulty) is { } question) {
- +
@@ -79,25 +78,25 @@
- +
- - - @Localizer["AdaptivityContentDialog.Table.Button.Question." + difficulty] -
- -
-
+ + + @Localizer["AdaptivityContentDialog.Table.Button.Question." + difficulty] +
+ +
+
- - + +
- +
@@ -144,18 +143,16 @@ [Inject, AllowNull] //can never be null, DI will throw exception on unresolved types internal IMapper Mapper { get; set; } - [Inject, AllowNull] //can never be null, DI will throw exception on unresolved types - internal IFormDataContainer FormDataContainer { get; set; } + [Parameter, EditorRequired] public AdaptivityContentFormModel MyContent { get; set; } = null!; - [Parameter, EditorRequired] - public AdaptivityContentFormModel MyContent { get; set; } = null!; + [Parameter] //can never be null, DI will throw exception on unresolved types - n.stich + public ILearningContentViewModel? ContentToEdit { get; set; } = null; - [Parameter] - public int DebounceInterval { get; set; } = 300; + [Parameter] public int DebounceInterval { get; set; } = 300; private MudTable? _table; - + private readonly Dictionary _nameMudFormRefs = new(); private readonly Dictionary _nameValues = new(); @@ -173,7 +170,7 @@ private async Task MapIntoContainer() { - Mapper.Map(MyContent, FormDataContainer.FormModel); + Mapper.Map(MyContent, ContentToEdit); await InvokeAsync(StateHasChanged); } @@ -198,11 +195,21 @@ PresentationLogic.EditAdaptivityTask(task, task.Name, setChecked ? difficulty : null); } - private void RemoveTask(IAdaptivityTaskViewModel task) + private async Task RemoveTask(IAdaptivityTaskViewModel task) { - PresentationLogic.DeleteAdaptivityTask(MyContent, task); + if (ContentToEdit != null && ContentToEdit is AdaptivityContentViewModel adaptivityContentViewModel) + { + PresentationLogic.DeleteAdaptivityTask(adaptivityContentViewModel, task); + Mapper.Map(ContentToEdit, MyContent); + } + else + { + PresentationLogic.DeleteAdaptivityTask(MyContent, task); + } + _nameValues.Remove(task); _nameMudFormRefs.Remove(task); + await MapIntoContainer(); } private async Task AddOrEditQuestion(IAdaptivityTaskViewModel task, QuestionDifficulty difficulty) @@ -217,8 +224,8 @@ }; var dialog = await DialogService.ShowAsync("", new DialogParameters() { - {nameof(AdaptivityQuestionDialog.Task), task}, - {nameof(AdaptivityQuestionDialog.Difficulty), difficulty} + { nameof(AdaptivityQuestionDialog.Task), task }, + { nameof(AdaptivityQuestionDialog.Difficulty), difficulty } }, options); var result = await dialog.Result; await InvokeAsync(StateHasChanged); @@ -226,7 +233,7 @@ private void RemoveQuestion(IAdaptivityTaskViewModel task, QuestionDifficulty difficulty) { - if (task.Questions.FirstOrDefault(x => x.Difficulty == difficulty) is {} question) + if (task.Questions.FirstOrDefault(x => x.Difficulty == difficulty) is { } question) { PresentationLogic.DeleteAdaptivityQuestion(task, question); } diff --git a/Presentation/Components/Forms/Element/EditElementForm.razor b/Presentation/Components/Forms/Element/EditElementForm.razor index 700f8a8d9..7d42c5c04 100644 --- a/Presentation/Components/Forms/Element/EditElementForm.razor +++ b/Presentation/Components/Forms/Element/EditElementForm.razor @@ -300,7 +300,7 @@ {
+ Title=@Localizer["EditElementForm.Fields.Collapsable.Goals.Title"] InitiallyCollapsed="true">
@@ -446,7 +446,8 @@ }; var parameters = new DialogParameters { - { nameof(AdaptivityContentDialog.MyContent), FormDataContainer.FormModel.LearningContent } + { nameof(AdaptivityContentDialog.MyContent), FormDataContainer.FormModel.LearningContent }, + { nameof(AdaptivityContentDialog.ContentToEdit), ElementToEdit.LearningContent } }; var dialog = await DialogService.ShowAsync(Localizer["EditElementForm.AdaptivityContent.Dialog.Title"], parameters, options); _ = await dialog.Result; diff --git a/Presentation/PresentationLogic/API/IPresentationLogic.cs b/Presentation/PresentationLogic/API/IPresentationLogic.cs index 07ea83622..0a31ac9e9 100644 --- a/Presentation/PresentationLogic/API/IPresentationLogic.cs +++ b/Presentation/PresentationLogic/API/IPresentationLogic.cs @@ -458,9 +458,9 @@ void DeleteLearningElementInWorld(ILearningWorldViewModel learningWorldVm, /// /// Creates a Adaptivity Task in the given Adaptivity Content. /// - /// The Adaptivity Content to create the Task in. + /// The Adaptivity Content Form Model to create the Task in. /// The name of the Task. - void CreateAdaptivityTask(AdaptivityContentFormModel adaptivityContentVm, string name); + void CreateAdaptivityTask(AdaptivityContentFormModel adaptivityContentFm, string name); /// /// Edits a given Adaptivity Task @@ -474,9 +474,17 @@ void EditAdaptivityTask(IAdaptivityTaskViewModel adaptivityTaskVm, string name, /// /// Deletes a given Adaptivity Task from the given Adaptivity Content. /// - /// The Adaptivity Content to delete the Task from. + /// The Adaptivity Content Form Model to delete the Task from. /// The Adaptivity Task to delete. - void DeleteAdaptivityTask(AdaptivityContentFormModel adaptivityContentVm, + void DeleteAdaptivityTask(AdaptivityContentFormModel adaptivityContentFm, + IAdaptivityTaskViewModel adaptivityTaskVm); + + /// + /// Deletes a given Adaptivity Task from the given Adaptivity Content. + /// + /// The Adaptivity Content View Model to delete the Task from. + /// The Adaptivity Task to delete. + void DeleteAdaptivityTask(AdaptivityContentViewModel adaptivityContentVm, IAdaptivityTaskViewModel adaptivityTaskVm); diff --git a/Presentation/PresentationLogic/API/PresentationLogic.cs b/Presentation/PresentationLogic/API/PresentationLogic.cs index 09548fcb2..b8c3bcd89 100644 --- a/Presentation/PresentationLogic/API/PresentationLogic.cs +++ b/Presentation/PresentationLogic/API/PresentationLogic.cs @@ -983,11 +983,11 @@ public async Task LoadLearningContentViewModelAsync(s } /// - public void CreateAdaptivityTask(AdaptivityContentFormModel adaptivityContentVm, string name) + public void CreateAdaptivityTask(AdaptivityContentFormModel adaptivityContentFm, string name) { - var contentEntity = Mapper.Map(adaptivityContentVm); + var contentEntity = Mapper.Map(adaptivityContentFm); var command = TaskCommandFactory.GetCreateCommand(contentEntity, name, - content => CMapper.Map(content, adaptivityContentVm)); + content => CMapper.Map(content, adaptivityContentFm)); BusinessLogic.ExecuteCommand(command); } @@ -1002,7 +1002,18 @@ public void EditAdaptivityTask(IAdaptivityTaskViewModel adaptivityTaskVm, string } /// - public void DeleteAdaptivityTask(AdaptivityContentFormModel adaptivityContentVm, + public void DeleteAdaptivityTask(AdaptivityContentFormModel adaptivityContentFm, + IAdaptivityTaskViewModel adaptivityTaskVm) + { + var contentEntity = Mapper.Map(adaptivityContentFm); + var taskEntity = Mapper.Map(adaptivityTaskVm); + var command = TaskCommandFactory.GetDeleteCommand(contentEntity, taskEntity, + content => CMapper.Map(content, adaptivityContentFm)); + BusinessLogic.ExecuteCommand(command); + } + + /// + public void DeleteAdaptivityTask(AdaptivityContentViewModel adaptivityContentVm, IAdaptivityTaskViewModel adaptivityTaskVm) { var contentEntity = Mapper.Map(adaptivityContentVm); diff --git a/Presentation/PresentationLogic/LearningSpace/LearningSpaceViewModel.cs b/Presentation/PresentationLogic/LearningSpace/LearningSpaceViewModel.cs index 7727a8bed..cf09bde5f 100644 --- a/Presentation/PresentationLogic/LearningSpace/LearningSpaceViewModel.cs +++ b/Presentation/PresentationLogic/LearningSpace/LearningSpaceViewModel.cs @@ -117,6 +117,7 @@ public bool UnsavedChanges { get => InternalUnsavedChanges || ContainedLearningElements.Any(element => element.UnsavedChanges) || + LearningSpaceLayout.StoryElements.Values.Any(element => element.UnsavedChanges) || LearningOutcomeCollection.UnsavedChanges; set => InternalUnsavedChanges = value; }