diff --git a/backend/src/Designer/Controllers/AppDevelopmentController.cs b/backend/src/Designer/Controllers/AppDevelopmentController.cs
index ae927c4eb05..8d4bcb73d66 100644
--- a/backend/src/Designer/Controllers/AppDevelopmentController.cs
+++ b/backend/src/Designer/Controllers/AppDevelopmentController.cs
@@ -159,15 +159,24 @@ await _mediator.Publish(new LayoutPageAddedEvent
/// Application identifier which is unique within an organisation.
/// The name of the layout set the specific layout belongs to
/// The form layout to be deleted
+ /// A that observes if operation is cancelled.
/// A success message if the save was successful
[HttpDelete]
[Route("form-layout/{layoutName}")]
- public ActionResult DeleteFormLayout(string org, string app, [FromQuery] string layoutSetName, [FromRoute] string layoutName)
+ public async Task DeleteFormLayout(string org, string app, [FromQuery] string layoutSetName, [FromRoute] string layoutName, CancellationToken cancellationToken)
{
try
{
string developer = AuthenticationHelper.GetDeveloperUserName(HttpContext);
var editingContext = AltinnRepoEditingContext.FromOrgRepoDeveloper(org, app, developer);
+
+ await _mediator.Publish(new LayoutPageDeletedEvent
+ {
+ EditingContext = editingContext,
+ LayoutSetName = layoutSetName,
+ LayoutName = layoutName,
+ }, cancellationToken);
+
_appDevelopmentService.DeleteFormLayout(editingContext, layoutSetName, layoutName);
return Ok();
}
diff --git a/backend/src/Designer/EventHandlers/LayoutPageDeleted/LayoutPageDeleterHandler.cs b/backend/src/Designer/EventHandlers/LayoutPageDeleted/LayoutPageDeleterHandler.cs
new file mode 100644
index 00000000000..17696840be4
--- /dev/null
+++ b/backend/src/Designer/EventHandlers/LayoutPageDeleted/LayoutPageDeleterHandler.cs
@@ -0,0 +1,86 @@
+
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using Altinn.Studio.Designer.Events;
+using Altinn.Studio.Designer.Hubs.SyncHub;
+using Altinn.Studio.Designer.Infrastructure.GitRepository;
+using Altinn.Studio.Designer.Models;
+using Altinn.Studio.Designer.Services.Interfaces;
+using MediatR;
+using System.Text.Json.Nodes;
+using Altinn.App.Core.Helpers;
+
+namespace Altinn.Studio.Designer.EventHandlers.LayoutPageDeleted;
+
+public class LayoutPageDeletedHandler(IAltinnGitRepositoryFactory altinnGitRepositoryFactory,
+ IFileSyncHandlerExecutor fileSyncHandlerExecutor) : INotificationHandler
+{
+ public async Task Handle(LayoutPageDeletedEvent notification, CancellationToken cancellationToken)
+ {
+ AltinnAppGitRepository altinnAppGitRepository = altinnGitRepositoryFactory.GetAltinnAppGitRepository(
+ notification.EditingContext.Org,
+ notification.EditingContext.Repo,
+ notification.EditingContext.Developer);
+
+ LayoutSets layoutSets = await altinnAppGitRepository.GetLayoutSetsFile(cancellationToken);
+
+ await fileSyncHandlerExecutor.ExecuteWithExceptionHandlingAndConditionalNotification(
+ notification.EditingContext,
+ SyncErrorCodes.LayoutPageDeletedSyncError,
+ "layouts",
+ async () =>
+ {
+ bool hasChanges = false;
+ foreach (LayoutSetConfig layoutSet in layoutSets.Sets)
+ {
+ Dictionary formLayouts = await altinnAppGitRepository.GetFormLayouts(layoutSet.Id, cancellationToken);
+ foreach (var formLayout in formLayouts)
+ {
+ hasChanges |= await RemoveComponentsReferencingLayout(
+ notification,
+ altinnAppGitRepository,
+ layoutSets.Sets,
+ layoutSet.Id,
+ formLayout,
+ cancellationToken);
+ }
+ }
+ return hasChanges;
+ });
+ }
+
+ private static async Task RemoveComponentsReferencingLayout(LayoutPageDeletedEvent notification, AltinnAppGitRepository altinnAppGitRepository, List layoutSets, string layoutSetName, KeyValuePair formLayout, CancellationToken cancellationToken)
+ {
+ if (formLayout.Value["data"] is not JsonObject data || data["layout"] is not JsonArray layoutArray)
+ {
+ return false;
+ }
+
+ bool hasChanges = false;
+ layoutArray.RemoveAll(jsonNode =>
+ {
+ if (jsonNode["type"]?.GetValue() == "Summary2" && jsonNode["target"] is JsonObject targetObject)
+ {
+ string summaryType = targetObject["type"]?.GetValue();
+ string taskId = targetObject["taskId"]?.GetValue();
+ string layouSetId = string.IsNullOrEmpty(taskId) ? layoutSetName : layoutSets?.FirstOrDefault(item => item.Tasks?.Contains(taskId) ?? false)?.Id;
+ bool hasLayoutSet = summaryType == "layout" && layouSetId == notification.LayoutSetName;
+ if (hasLayoutSet)
+ {
+ hasChanges = true;
+ return true;
+ }
+ }
+
+ return false;
+ });
+
+ if (hasChanges)
+ {
+ await altinnAppGitRepository.SaveLayout(layoutSetName, $"{formLayout.Key}.json", formLayout.Value, cancellationToken);
+ }
+ return hasChanges;
+ }
+}
diff --git a/backend/src/Designer/Events/LayoutPageDeletedEvent.cs b/backend/src/Designer/Events/LayoutPageDeletedEvent.cs
new file mode 100644
index 00000000000..8411d583169
--- /dev/null
+++ b/backend/src/Designer/Events/LayoutPageDeletedEvent.cs
@@ -0,0 +1,11 @@
+using Altinn.Studio.Designer.Models;
+using MediatR;
+
+namespace Altinn.Studio.Designer.Events;
+
+public class LayoutPageDeletedEvent : INotification
+{
+ public AltinnRepoEditingContext EditingContext { get; set; }
+ public string LayoutSetName { get; set; }
+ public string LayoutName { get; set; }
+}
diff --git a/backend/src/Designer/Hubs/SyncHub/SyncErrorCodes.cs b/backend/src/Designer/Hubs/SyncHub/SyncErrorCodes.cs
index 23556793c7b..76d1b5bbddd 100644
--- a/backend/src/Designer/Hubs/SyncHub/SyncErrorCodes.cs
+++ b/backend/src/Designer/Hubs/SyncHub/SyncErrorCodes.cs
@@ -13,4 +13,5 @@ public static class SyncErrorCodes
public const string LayoutSetSubFormButtonSyncError = nameof(LayoutSetSubFormButtonSyncError);
public const string SettingsComponentIdSyncError = nameof(SettingsComponentIdSyncError);
public const string LayoutPageAddSyncError = nameof(LayoutPageAddSyncError);
+ public const string LayoutPageDeletedSyncError = nameof(LayoutPageDeletedSyncError);
}