Skip to content

Commit

Permalink
Merge branch 'main' into 13400-replace-react-modal-with-studiomodal
Browse files Browse the repository at this point in the history
  • Loading branch information
Jondyr authored Oct 10, 2024
2 parents ace95b4 + 5c1c757 commit 62415f9
Show file tree
Hide file tree
Showing 108 changed files with 1,042 additions and 1,717 deletions.
6 changes: 6 additions & 0 deletions backend/src/Designer/Controllers/AppDevelopmentController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,12 @@ public async Task<ActionResult> DeleteLayoutSet(string org, string app, [FromRou
string developer = AuthenticationHelper.GetDeveloperUserName(HttpContext);
var editingContext = AltinnRepoEditingContext.FromOrgRepoDeveloper(org, app, developer);
LayoutSets layoutSets = await _appDevelopmentService.DeleteLayoutSet(editingContext, layoutSetIdToUpdate, cancellationToken);

await _mediator.Publish(new LayoutSetDeletedEvent
{
EditingContext = editingContext,
LayoutSetId = layoutSetIdToUpdate
}, cancellationToken);
return Ok(layoutSets);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
using System.Collections.Generic;
using System.Text.Json.Nodes;
using System.Threading;
using System.Threading.Tasks;
using Altinn.App.Core.Helpers;
using Altinn.Studio.Designer.Events;
using Altinn.Studio.Designer.Hubs.SyncHub;
using Altinn.Studio.Designer.Infrastructure.GitRepository;
using Altinn.Studio.Designer.Services.Interfaces;
using MediatR;

namespace Altinn.Studio.Designer.EventHandlers.LayoutSetDeleted;

public class LayoutSetDeletedComponentRefHandler(IAltinnGitRepositoryFactory altinnGitRepositoryFactory, IFileSyncHandlerExecutor fileSyncHandlerExecutor) : INotificationHandler<LayoutSetDeletedEvent>
{
public async Task Handle(LayoutSetDeletedEvent notification, CancellationToken cancellationToken)
{
AltinnAppGitRepository altinnAppGitRepository = altinnGitRepositoryFactory.GetAltinnAppGitRepository(
notification.EditingContext.Org,
notification.EditingContext.Repo,
notification.EditingContext.Developer);

string[] layoutSetNames = altinnAppGitRepository.GetLayoutSetNames();

await fileSyncHandlerExecutor.ExecuteWithExceptionHandlingAndConditionalNotification(
notification.EditingContext,
SyncErrorCodes.LayoutSetSubLayoutSyncError,
"layouts",
async () =>
{
bool hasChanges = false;
foreach (string layoutSetName in layoutSetNames)
{
Dictionary<string, JsonNode> formLayouts = await altinnAppGitRepository.GetFormLayouts(layoutSetName, cancellationToken);
foreach (var formLayout in formLayouts)
{
hasChanges |= await RemoveComponentsReferencingLayoutSet(
notification,
altinnAppGitRepository,
layoutSetName,
formLayout,
cancellationToken);
}
}
return hasChanges;
});
}

private static async Task<bool> RemoveComponentsReferencingLayoutSet(LayoutSetDeletedEvent notification, AltinnAppGitRepository altinnAppGitRepository, string layoutSetName, KeyValuePair<string, JsonNode> 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["layoutSet"]?.GetValue<string>() == notification.LayoutSetId)
{
hasChanges = true;
return true;
}
return false;
});

if (hasChanges)
{
await altinnAppGitRepository.SaveLayout(layoutSetName, $"{formLayout.Key}.json", formLayout.Value, cancellationToken);
}
return hasChanges;
}
}
10 changes: 10 additions & 0 deletions backend/src/Designer/Events/LayoutSetDeletedEvent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using Altinn.Studio.Designer.Models;
using MediatR;

namespace Altinn.Studio.Designer.Events;

public class LayoutSetDeletedEvent : INotification
{
public string LayoutSetId { get; set; }
public AltinnRepoEditingContext EditingContext { get; set; }
}
1 change: 1 addition & 0 deletions backend/src/Designer/Hubs/SyncHub/SyncErrorCodes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ public static class SyncErrorCodes
public const string ApplicationMetadataDataTypeSyncError = nameof(ApplicationMetadataDataTypeSyncError);
public const string LayoutSetsDataTypeSyncError = nameof(LayoutSetsDataTypeSyncError);
public const string LayoutSetComponentIdSyncError = nameof(LayoutSetComponentIdSyncError);
public const string LayoutSetSubLayoutSyncError = nameof(LayoutSetSubLayoutSyncError);
public const string SettingsComponentIdSyncError = nameof(SettingsComponentIdSyncError);
public const string LayoutPageAddSyncError = nameof(LayoutPageAddSyncError);
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Text.Json;
using System.Text.Json.Nodes;
using System.Threading.Tasks;
using Altinn.Platform.Storage.Interface.Models;
using Altinn.Studio.Designer.Factories;
Expand Down Expand Up @@ -133,6 +134,32 @@ public async Task DeleteLayoutSet_AppWithoutLayoutSets_ReturnsNotFound(string or
response.StatusCode.Should().Be(HttpStatusCode.NotFound);
}

[Theory]
[InlineData("ttd", "app-with-layoutsets", "testUser", "layoutSet3",
"layoutSet2", "layoutFile1InSet2", "subform-component-id")]
public async Task DeleteLayoutSet_RemovesComponentsReferencingLayoutSet(string org, string app, string developer, string layoutSetToDeleteId,
string layoutSetWithRef, string layoutSetFile, string deletedComponentId)
{
string targetRepository = TestDataHelper.GenerateTestRepoName();
await CopyRepositoryForTest(org, app, developer, targetRepository);

string url = $"{VersionPrefix(org, targetRepository)}/layout-set/{layoutSetToDeleteId}";
using var httpRequestMessage = new HttpRequestMessage(HttpMethod.Delete, url);

using var response = await HttpClient.SendAsync(httpRequestMessage);
response.StatusCode.Should().Be(HttpStatusCode.OK, await response.Content.ReadAsStringAsync());

JsonNode formLayout = (await GetFormLayouts(org, targetRepository, developer, layoutSetWithRef))[layoutSetFile];
JsonArray layout = formLayout["data"]?["layout"] as JsonArray;

layout.Should().NotBeNull();
layout
.Where(jsonNode => jsonNode["layoutSet"] != null)
.Should()
.NotContain(jsonNode => jsonNode["layoutSet"].GetValue<string>() == deletedComponentId,
$"No components should reference the deleted layout set {deletedComponentId}");
}

private async Task<LayoutSets> GetLayoutSetsFile(string org, string app, string developer)
{
AltinnGitRepositoryFactory altinnGitRepositoryFactory =
Expand All @@ -143,6 +170,16 @@ private async Task<LayoutSets> GetLayoutSetsFile(string org, string app, string
return await altinnAppGitRepository.GetLayoutSetsFile();
}

private async Task<Dictionary<string, JsonNode>> GetFormLayouts(string org, string app, string developer, string layoutSetName)
{
AltinnGitRepositoryFactory altinnGitRepositoryFactory =
new(TestDataHelper.GetTestDataRepositoriesRootDirectory());
AltinnAppGitRepository altinnAppGitRepository =
altinnGitRepositoryFactory.GetAltinnAppGitRepository(org, app, developer);
Dictionary<string, JsonNode> formLayouts = await altinnAppGitRepository.GetFormLayouts(layoutSetName);
return formLayouts;
}

private async Task<Application> GetApplicationMetadataFile(string org, string app, string developer)
{
AltinnGitRepositoryFactory altinnGitRepositoryFactory =
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
{
"schema": "https://altinncdn.no/schemas/json/layout/layout.schema.v1.json",
"data": {
"layout": [{
"id": "component-id",
"type": "Header",
"textResourceBindings": {
"title": "some-old-id",
"body": "another-key"
}
}]
}
"schema": "https://altinncdn.no/schemas/json/layout/layout.schema.v1.json",
"data": {
"layout": [
{
"id": "component-id",
"type": "Header",
"textResourceBindings": {
"title": "some-old-id",
"body": "another-key"
}
},
{
"id": "subform-component-id",
"layoutSet": "layoutSet3"
}
]
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.popoverContent {
/* This is so that it goes above the header which has an z-index of 2000 */
z-index: 2001;
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import React, { useState } from 'react';
import classes from './CreateNewWrapper.module.css';
import { ErrorMessage, Textfield } from '@digdir/designsystemet-react';
import { useTranslation } from 'react-i18next';
import { PlusIcon } from '@studio/icons';
Expand Down Expand Up @@ -91,7 +92,7 @@ export function CreateNewWrapper({
{<PlusIcon />}
{t('general.create_new')}
</StudioPopover.Trigger>
<StudioPopover.Content>
<StudioPopover.Content className={classes.popoverContent}>
<Textfield
id='newModelInput'
label={t('schema_editor.create_model_description')}
Expand Down
2 changes: 1 addition & 1 deletion frontend/app-development/layout/PageHeader/PageHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { type HeaderMenuItem } from 'app-development/types/HeaderMenu/HeaderMenu
import { useTranslation } from 'react-i18next';
import { LargeNavigationMenu } from './LargeNavigationMenu';
import { usePageHeaderContext } from 'app-development/contexts/PageHeaderContext';
import { useUserNameAndOrg } from 'app-shared/components/AltinnHeaderProfile/hooks/useUserNameAndOrg';
import { useUserNameAndOrg } from 'app-shared/hooks/useUserNameAndOrg';

export type PageHeaderProps = {
showSubMenu: boolean;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import { SmallHeaderMenuItem } from './SmallHeaderMenuItem';
import { useStudioEnvironmentParams } from 'app-shared/hooks/useStudioEnvironmentParams';
import { useRepoMetadataQuery } from 'app-shared/hooks/queries';
import { usePageHeaderContext } from 'app-development/contexts/PageHeaderContext';
import { useUserNameAndOrg } from 'app-shared/components/AltinnHeaderProfile/hooks/useUserNameAndOrg';
import { useUserNameAndOrg } from 'app-shared/hooks/useUserNameAndOrg';
import { type HeaderMenuGroup } from 'app-development/types/HeaderMenu/HeaderMenuGroup';
import {
groupMenuItemsByGroup,
Expand Down
4 changes: 4 additions & 0 deletions frontend/app-preview/App.css
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
:root {
font-family: Roboto, 'San Fransisco', 'Helvetica Neue', Helvetica, Arial, sans-serif;
}

body {
margin: 0;
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React, { type ReactElement } from 'react';
import { type Repository, type User } from 'app-shared/types/Repository';
import { useTranslation } from 'react-i18next';
import { useUserNameAndOrg } from 'app-shared/components/AltinnHeaderProfile/hooks/useUserNameAndOrg';
import { useUserNameAndOrg } from 'app-shared/hooks/useUserNameAndOrg';
import { useStudioEnvironmentParams } from 'app-shared/hooks/useStudioEnvironmentParams';
import {
useMediaQuery,
Expand Down
1 change: 0 additions & 1 deletion frontend/language/src/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -771,7 +771,6 @@
"testing.testing_in_testenv_title": "Testing in test environment",
"top_menu.about": "About",
"top_menu.create": "Create",
"top_menu.dashboard": "Dashboard",
"top_menu.data_model": "Data model",
"top_menu.deploy": "Deploy",
"top_menu.policy_editor": "Policy",
Expand Down
8 changes: 7 additions & 1 deletion frontend/language/src/nb.json
Original file line number Diff line number Diff line change
Expand Up @@ -1038,7 +1038,6 @@
"top_bar.group_tools": "Verktøy",
"top_menu.about": "Oversikt",
"top_menu.create": "Utforming",
"top_menu.dashboard": "Dashboard",
"top_menu.data_model": "Datamodell",
"top_menu.deploy": "Publiser",
"top_menu.menu": "Meny",
Expand Down Expand Up @@ -1285,6 +1284,13 @@
"ux_editor.component_properties.stickyHeader": "Fest tittelraden",
"ux_editor.component_properties.style": "Stil",
"ux_editor.component_properties.subdomains": "Subdomener (kommaseparert)",
"ux_editor.component_properties.subform": "Sidegruppe for underskjema",
"ux_editor.component_properties.subform.choose_layout_set": "Velg sidegruppe...",
"ux_editor.component_properties.subform.choose_layout_set_label": "Velg sidegruppe å knytte til underskjema",
"ux_editor.component_properties.subform.go_to_layout_set": "Gå til utforming av underskjemaet",
"ux_editor.component_properties.subform.no_layout_sets_acting_as_subform": "Det finnes ingen sidegrupper i løsningen som kan brukes som et underskjema",
"ux_editor.component_properties.subform.selected_layout_set_label": "Underskjema",
"ux_editor.component_properties.subform.selected_layout_set_title": "Endre underskjemakobling til {{subform}}",
"ux_editor.component_properties.summary.add_override": "Legg til overstyring",
"ux_editor.component_properties.summary.override.component_id": "ID på komponenten",
"ux_editor.component_properties.summary.override.empty_field_text": "Tekst for tomme felter",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { useBpmnApiContext } from '../../../../contexts/BpmnApiContext';
import { useTranslation } from 'react-i18next';
import { ShieldLockIcon } from '@studio/icons';
import classes from './EditPolicy.module.css';
import { RedirectBox } from '@altinn/process-editor/components/RedirectBox';
import { RedirectBox } from 'app-shared/components/RedirectBox';

export const EditPolicy = () => {
const { t } = useTranslation();
Expand All @@ -25,7 +25,6 @@ export const EditPolicy = () => {
color='second'
icon={<ShieldLockIcon />}
iconPlacement='left'
className={classes.policyEditorButton}
>
{t('process_editor.configuration_panel.edit_policy_open_policy_editor_button')}
</StudioButton>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { StudioButton } from '@studio/components';
import { useLocalStorage } from '@studio/components/src/hooks/useLocalStorage';
import { useTranslation } from 'react-i18next';
import { useBpmnApiContext } from '../../../../../contexts/BpmnApiContext';
import { RedirectBox } from '../../../../RedirectBox';
import { RedirectBox } from 'app-shared/components/RedirectBox';
import { Link } from '@digdir/designsystemet-react';

export const RedirectToCreatePageButton = (): React.ReactElement => {
Expand All @@ -16,7 +16,7 @@ export const RedirectToCreatePageButton = (): React.ReactElement => {
const packagesRouter = new PackagesRouter({ org, app });
const { existingCustomReceiptLayoutSetId } = useBpmnApiContext();

const [, setSelectedLayoutSet] = useLocalStorage<string>('layoutSet/' + app, null);
const [, setSelectedLayoutSet] = useLocalStorage<string>('layoutSet/' + app);

const handleClick = () => {
setSelectedLayoutSet(existingCustomReceiptLayoutSetId);
Expand Down

This file was deleted.

Loading

0 comments on commit 62415f9

Please sign in to comment.