From 2e2d7e6bf49796a40f0d42f10fec69a98c902b2e Mon Sep 17 00:00:00 2001 From: JamalAlabdullah <90609090+JamalAlabdullah@users.noreply.github.com> Date: Wed, 29 May 2024 15:18:10 +0200 Subject: [PATCH 01/27] Bug/12252 cant add rename delete pages after naming a pagewith(.) (#12877) * addded validation to not allow using period in page_id name --- frontend/language/src/nb.json | 1 + .../src/utils/designViewUtils/designViewUtils.test.ts | 10 ++++++++++ .../src/utils/designViewUtils/designViewUtils.ts | 2 ++ 3 files changed, 13 insertions(+) diff --git a/frontend/language/src/nb.json b/frontend/language/src/nb.json index 5387fe3ac99..6787c81a4a7 100644 --- a/frontend/language/src/nb.json +++ b/frontend/language/src/nb.json @@ -2002,6 +2002,7 @@ "ux_editor.pages_add": "Legg til ny side", "ux_editor.pages_error_empty": "Navnet kan ikke være tomt.", "ux_editor.pages_error_format": "Navnet må bestå av bokstaver (a-z), tall, eller \"-\", \"_\" og \".\".", + "ux_editor.pages_error_invalid_format": "Navnet kan ikke inneholde punktum.", "ux_editor.pages_error_length": "Navnet kan ikke være lengre enn 30 tegn.", "ux_editor.pages_error_unique": "Navnet må være unikt.", "ux_editor.preview": "Forhåndsvisning", diff --git a/frontend/packages/ux-editor/src/utils/designViewUtils/designViewUtils.test.ts b/frontend/packages/ux-editor/src/utils/designViewUtils/designViewUtils.test.ts index 829ec4dedae..e419f40d60a 100644 --- a/frontend/packages/ux-editor/src/utils/designViewUtils/designViewUtils.test.ts +++ b/frontend/packages/ux-editor/src/utils/designViewUtils/designViewUtils.test.ts @@ -5,6 +5,7 @@ const mockNewNameCandidateExists: string = 'page2'; const mockNewNameCandidateEmpty: string = ''; const mockNewNameCandidateTooLong: string = 'ThisStringIsTooooooooooooooLong'; const mockNewNameCandidateIllegal: string = 'Page????'; +const mockNewNameCandidateWithPeriod: string = 'Page.2'; const mockOldName: string = 'oldName'; const mockLayoutOrder: string[] = [mockOldName, mockNewNameCandidateExists, 'page3']; @@ -50,6 +51,15 @@ describe('designViewUtils', () => { expect(nameErrorkey).toEqual('ux_editor.pages_error_length'); }); + it('returns formate error when name contains period (.)', () => { + const nameErrorkey = getPageNameErrorKey( + mockNewNameCandidateWithPeriod, + mockOldName, + mockLayoutOrder, + ); + expect(nameErrorkey).toEqual('ux_editor.pages_error_invalid_format'); + }); + it('returns format error key when name contains illegal characters', () => { const nameErrorkey = getPageNameErrorKey( mockNewNameCandidateIllegal, diff --git a/frontend/packages/ux-editor/src/utils/designViewUtils/designViewUtils.ts b/frontend/packages/ux-editor/src/utils/designViewUtils/designViewUtils.ts index 704aedda342..f313c74c5ca 100644 --- a/frontend/packages/ux-editor/src/utils/designViewUtils/designViewUtils.ts +++ b/frontend/packages/ux-editor/src/utils/designViewUtils/designViewUtils.ts @@ -25,6 +25,8 @@ export const getPageNameErrorKey = ( return 'ux_editor.pages_error_unique'; } else if (!newNameCandidate) { return 'ux_editor.pages_error_empty'; + } else if (newNameCandidate.includes('.')) { + return 'ux_editor.pages_error_invalid_format'; } else if (newNameCandidate.length >= 30) { return 'ux_editor.pages_error_length'; } else if (!validateLayoutNameAndLayoutSetName(newNameCandidate)) { From db9b0b873418854cb916cde15b64693cc1b4d4af Mon Sep 17 00:00:00 2001 From: Lars <74791975+lassopicasso@users.noreply.github.com> Date: Wed, 29 May 2024 15:53:08 +0200 Subject: [PATCH 02/27] fix textkey: combination_inline_object_disclaimer (#12881) --- .../src/components/SchemaInspector/InlineObject.tsx | 2 +- .../src/components/SchemaInspector/ItemPropertiesTab.test.tsx | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/frontend/packages/schema-editor/src/components/SchemaInspector/InlineObject.tsx b/frontend/packages/schema-editor/src/components/SchemaInspector/InlineObject.tsx index 8e76c494b92..83270fafd81 100644 --- a/frontend/packages/schema-editor/src/components/SchemaInspector/InlineObject.tsx +++ b/frontend/packages/schema-editor/src/components/SchemaInspector/InlineObject.tsx @@ -16,7 +16,7 @@ export function InlineObject({ item }: IInlineObjectProps) { {JSON.stringify(item, null, ' ')}
- {t('combination_inline_object_disclaimer')} + {t('schema_editor.combination_inline_object_disclaimer')}
); diff --git a/frontend/packages/schema-editor/src/components/SchemaInspector/ItemPropertiesTab.test.tsx b/frontend/packages/schema-editor/src/components/SchemaInspector/ItemPropertiesTab.test.tsx index d4d7cbbe6ab..6b461a38c54 100644 --- a/frontend/packages/schema-editor/src/components/SchemaInspector/ItemPropertiesTab.test.tsx +++ b/frontend/packages/schema-editor/src/components/SchemaInspector/ItemPropertiesTab.test.tsx @@ -43,7 +43,9 @@ describe('ItemPropertiesTab', () => { renderWithProviders({ appContextProps: { schemaModel: SchemaModel.fromArray(uiSchemaNodes) }, })(); - expect(screen.getByText(textMock('combination_inline_object_disclaimer'))).toBeDefined(); + expect( + screen.getByText(textMock('schema_editor.combination_inline_object_disclaimer')), + ).toBeDefined(); }); it('Renders a name field when a field node is selected', async () => { From 8d5d3b21cd8bdef5889da9c9104250869f928483 Mon Sep 17 00:00:00 2001 From: WilliamThorenfeldt <133344438+WilliamThorenfeldt@users.noreply.github.com> Date: Wed, 29 May 2024 16:14:12 +0200 Subject: [PATCH 03/27] Rename useStudioParams to useStudioEnvironmentParams (#12868) --- .../features/appPublish/components/CreateRelease.tsx | 4 ++-- .../features/appPublish/components/Deploy.tsx | 4 ++-- .../features/appPublish/components/DeployDropdown.tsx | 4 ++-- .../features/appPublish/components/Release.tsx | 4 ++-- .../features/appPublish/containers/DeploymentContainer.tsx | 4 ++-- .../features/appPublish/containers/ReleaseContainer.tsx | 4 ++-- .../features/appPublish/pages/DeployPage.tsx | 4 ++-- .../SchemaEditorWithToolbar/SelectedSchemaEditor.tsx | 4 ++-- .../features/overview/components/DeploymentContainer.tsx | 4 ++-- .../features/overview/components/DeploymentStatus.tsx | 4 ++-- .../features/overview/components/DeploymentStatusList.tsx | 4 ++-- .../features/overview/components/Deployments.tsx | 4 ++-- .../app-development/features/overview/components/Header.tsx | 4 ++-- .../features/processEditor/ProcessEditor.tsx | 4 ++-- frontend/app-development/features/textEditor/TextEditor.tsx | 4 ++-- .../hooks/mutations/useCreateDataModelMutation.ts | 4 ++-- .../hooks/mutations/useDeleteDataModelMutation.ts | 4 ++-- .../hooks/mutations/useGenerateModelsMutation.ts | 4 ++-- .../app-development/hooks/mutations/useSchemaMutation.ts | 4 ++-- .../hooks/mutations/useUploadDataModelMutation.ts | 4 ++-- frontend/app-development/hooks/queries/useSchemaQuery.ts | 4 ++-- frontend/app-development/router/routes.tsx | 4 ++-- .../src/components/AppBarConfig/AppPreviewBarConfig.tsx | 4 ++-- frontend/app-preview/src/views/LandingPage.tsx | 4 ++-- .../RedirectToCreatePageButton.tsx | 4 ++-- .../GiteaHeader/ThreeDotsMenu/CloneModal/CloneModal.tsx | 4 ++-- ...UrlParams.test.ts => useStudioEnvironmentParams.test.ts} | 6 +++--- ...{useStudioUrlParams.ts => useStudioEnvironmentParams.ts} | 6 +++--- .../src/navigation/main-header/ProfileMenu/ProfileMenu.tsx | 4 ++-- frontend/packages/text-editor/src/TextList.tsx | 4 ++-- frontend/packages/ux-editor-v3/src/App.tsx | 4 ++-- frontend/packages/ux-editor-v3/src/SubApp.tsx | 4 ++-- .../ux-editor-v3/src/components/Elements/Elements.tsx | 4 ++-- .../src/components/Elements/LayoutSetsContainer.tsx | 4 ++-- .../src/components/FormComponent/FormComponent.tsx | 4 ++-- .../ux-editor-v3/src/components/Preview/Preview.tsx | 4 ++-- .../src/components/Properties/OldDynamicsInfo.tsx | 4 ++-- .../ux-editor-v3/src/components/TextResourceEdit.tsx | 6 +++--- .../src/components/config/EditFormContainer.tsx | 4 ++-- .../ExpressionEditMode/SimpleExpression/DataSourceValue.tsx | 4 ++-- .../src/components/config/SelectDataModelComponent.tsx | 4 ++-- .../src/components/config/editModal/EditCodeList.tsx | 4 ++-- .../components/config/editModal/EditDataModelBindings.tsx | 4 ++-- .../src/components/toolbar/ConditionalRenderingModal.tsx | 4 ++-- .../ux-editor-v3/src/components/toolbar/RuleModal.tsx | 4 ++-- .../ux-editor-v3/src/containers/DesignView/DesignView.tsx | 4 ++-- .../FormTree/FormItem/FormItemTitle/useDeleteItem.ts | 4 ++-- .../useDeleteUnknownComponentReference.ts | 4 ++-- .../PageAccordion/NavigationMenu/NavigationMenu.tsx | 4 ++-- .../containers/DesignView/PageAccordion/PageAccordion.tsx | 4 ++-- .../containers/DesignView/PageAccordion/useDeleteLayout.ts | 4 ++-- .../packages/ux-editor-v3/src/containers/FormDesigner.tsx | 4 ++-- .../ux-editor-v3/src/containers/FormItemContext.tsx | 4 ++-- .../ux-editor-v3/src/hooks/useFormLayoutsSelector.ts | 4 ++-- .../ux-editor-v3/src/hooks/useTextResourcesSelector.ts | 4 ++-- .../packages/ux-editor-v3/src/hooks/useValidateComponent.ts | 4 ++-- frontend/packages/ux-editor/src/App.tsx | 4 ++-- .../packages/ux-editor/src/components/Elements/Elements.tsx | 4 ++-- .../src/components/Elements/LayoutSetsContainer.tsx | 4 ++-- .../src/components/FormComponent/FormComponent.tsx | 4 ++-- .../packages/ux-editor/src/components/Preview/Preview.tsx | 4 ++-- .../ux-editor/src/components/Properties/OldDynamicsInfo.tsx | 4 ++-- .../components/Properties/PageConfigPanel/EditPageId.tsx | 4 ++-- .../Properties/PageConfigPanel/HiddenExpressionOnLayout.tsx | 4 ++-- .../Properties/PageConfigPanel/PageConfigWarning.tsx | 4 ++-- .../TextResourceValueEditor/TextResourceValueEditor.tsx | 4 ++-- .../config/ExpressionContent/ExpressionContent.tsx | 4 ++-- .../src/components/config/SelectDataModelComponent.tsx | 4 ++-- .../AttachmentList/AttachmentListComponent.tsx | 4 ++-- .../RepeatingGroup/RepeatingGroupComponent.tsx | 4 ++-- .../config/editModal/EditCodeList/EditCodeList.tsx | 4 ++-- .../EditDataModelBindings/EditDataModelBindings.tsx | 4 ++-- .../src/components/toolbar/ConditionalRenderingModal.tsx | 4 ++-- .../packages/ux-editor/src/components/toolbar/RuleModal.tsx | 4 ++-- .../ux-editor/src/containers/DesignView/DesignView.tsx | 4 ++-- .../FormTree/FormItem/FormItemTitle/useDeleteItem.ts | 4 ++-- .../useDeleteUnknownComponentReference.ts | 4 ++-- .../PageAccordion/NavigationMenu/NavigationMenu.tsx | 4 ++-- .../containers/DesignView/PageAccordion/PageAccordion.tsx | 4 ++-- frontend/packages/ux-editor/src/containers/FormDesigner.tsx | 4 ++-- .../packages/ux-editor/src/containers/FormItemContext.tsx | 4 ++-- frontend/packages/ux-editor/src/hooks/useFormLayouts.ts | 4 ++-- .../ux-editor/src/hooks/useSelectedFormLayoutName.ts | 4 ++-- .../ux-editor/src/hooks/useSelectedFormLayoutSetName.ts | 4 ++-- frontend/packages/ux-editor/src/hooks/useSelectedTaskId.ts | 4 ++-- .../ux-editor/src/hooks/useTextResourcesSelector.ts | 4 ++-- .../packages/ux-editor/src/hooks/useValidateComponent.ts | 4 ++-- 87 files changed, 177 insertions(+), 177 deletions(-) rename frontend/packages/shared/src/hooks/{useStudioUrlParams.test.ts => useStudioEnvironmentParams.test.ts} (51%) rename frontend/packages/shared/src/hooks/{useStudioUrlParams.ts => useStudioEnvironmentParams.ts} (54%) diff --git a/frontend/app-development/features/appPublish/components/CreateRelease.tsx b/frontend/app-development/features/appPublish/components/CreateRelease.tsx index 678b8baf311..8b183df3f0d 100644 --- a/frontend/app-development/features/appPublish/components/CreateRelease.tsx +++ b/frontend/app-development/features/appPublish/components/CreateRelease.tsx @@ -6,12 +6,12 @@ import { versionNameValid } from './utils'; import { useBranchStatusQuery, useAppReleasesQuery } from '../../../hooks/queries'; import { useCreateReleaseMutation } from '../../../hooks/mutations'; import { useTranslation } from 'react-i18next'; -import { useStudioUrlParams } from 'app-shared/hooks/useStudioUrlParams'; +import { useStudioEnvironmentParams } from 'app-shared/hooks/useStudioEnvironmentParams'; import { FormField } from 'app-shared/components/FormField'; import { StudioButton } from '@studio/components'; export function CreateRelease() { - const { org, app } = useStudioUrlParams(); + const { org, app } = useStudioEnvironmentParams(); const [tagName, setTagName] = useState(''); const [body, setBody] = useState(''); const { data: releases = [] } = useAppReleasesQuery(org, app); diff --git a/frontend/app-development/features/appPublish/components/Deploy.tsx b/frontend/app-development/features/appPublish/components/Deploy.tsx index f24e1f955c4..84a28f3cb23 100644 --- a/frontend/app-development/features/appPublish/components/Deploy.tsx +++ b/frontend/app-development/features/appPublish/components/Deploy.tsx @@ -2,7 +2,7 @@ import React, { useState } from 'react'; import { DeployDropdown } from './DeployDropdown'; import { useCreateDeploymentMutation } from '../../../hooks/mutations'; import { Trans, useTranslation } from 'react-i18next'; -import { useStudioUrlParams } from 'app-shared/hooks/useStudioUrlParams'; +import { useStudioEnvironmentParams } from 'app-shared/hooks/useStudioEnvironmentParams'; import { toast } from 'react-toastify'; import { Alert, Link } from '@digdir/design-system-react'; import { useDeployPermissionsQuery } from 'app-development/hooks/queries'; @@ -28,7 +28,7 @@ export const Deploy = ({ const [selectedImageTag, setSelectedImageTag] = useState(null); const { t } = useTranslation(); - const { org, app } = useStudioUrlParams(); + const { org, app } = useStudioEnvironmentParams(); const { data: permissions, isPending: permissionsIsPending, diff --git a/frontend/app-development/features/appPublish/components/DeployDropdown.tsx b/frontend/app-development/features/appPublish/components/DeployDropdown.tsx index 39620882957..b3697d59be1 100644 --- a/frontend/app-development/features/appPublish/components/DeployDropdown.tsx +++ b/frontend/app-development/features/appPublish/components/DeployDropdown.tsx @@ -8,7 +8,7 @@ import { useTranslation } from 'react-i18next'; import { useAppReleasesQuery } from 'app-development/hooks/queries'; import { BuildResult } from 'app-shared/types/Build'; import { DateUtils } from '@studio/pure-functions'; -import { useStudioUrlParams } from 'app-shared/hooks/useStudioUrlParams'; +import { useStudioEnvironmentParams } from 'app-shared/hooks/useStudioEnvironmentParams'; export interface DeployDropdownProps { appDeployedVersion: string; @@ -27,7 +27,7 @@ export const DeployDropdown = ({ startDeploy, isPending, }: DeployDropdownProps) => { - const { org, app } = useStudioUrlParams(); + const { org, app } = useStudioEnvironmentParams(); const [isConfirmDeployDialogOpen, setIsConfirmDeployDialogOpen] = useState(); const { t } = useTranslation(); diff --git a/frontend/app-development/features/appPublish/components/Release.tsx b/frontend/app-development/features/appPublish/components/Release.tsx index 6454ae081cf..31f4450b823 100644 --- a/frontend/app-development/features/appPublish/components/Release.tsx +++ b/frontend/app-development/features/appPublish/components/Release.tsx @@ -8,7 +8,7 @@ import { StudioSpinner } from '@studio/components'; import type { Build } from 'app-shared/types/Build'; import { BuildResult, BuildStatus } from 'app-shared/types/Build'; import type { AppRelease } from 'app-shared/types/AppRelease'; -import { useStudioUrlParams } from 'app-shared/hooks/useStudioUrlParams'; +import { useStudioEnvironmentParams } from 'app-shared/hooks/useStudioEnvironmentParams'; interface IReleaseComponent { release: AppRelease; @@ -50,7 +50,7 @@ export function Release(props: IReleaseComponent) { } return release.body; } - const { org, app } = useStudioUrlParams(); + const { org, app } = useStudioEnvironmentParams(); return (
diff --git a/frontend/app-development/features/appPublish/containers/DeploymentContainer.tsx b/frontend/app-development/features/appPublish/containers/DeploymentContainer.tsx index 252db801443..534d58f979a 100644 --- a/frontend/app-development/features/appPublish/containers/DeploymentContainer.tsx +++ b/frontend/app-development/features/appPublish/containers/DeploymentContainer.tsx @@ -7,7 +7,7 @@ import { useAppDeploymentsQuery, } from '../../../hooks/queries'; import type { Environment } from 'app-shared/types/Environment'; -import { useStudioUrlParams } from 'app-shared/hooks/useStudioUrlParams'; +import { useStudioEnvironmentParams } from 'app-shared/hooks/useStudioEnvironmentParams'; import { DeploymentEnvironment } from '../components/DeploymentEnvironment'; import { getAppLink } from 'app-shared/ext-urls'; import { useTranslation } from 'react-i18next'; @@ -15,7 +15,7 @@ import { Alert } from '@digdir/design-system-react'; import { PROD_ENV_TYPE } from 'app-shared/constants'; export const DeploymentContainer = () => { - const { org, app } = useStudioUrlParams(); + const { org, app } = useStudioEnvironmentParams(); const { t } = useTranslation(); const { diff --git a/frontend/app-development/features/appPublish/containers/ReleaseContainer.tsx b/frontend/app-development/features/appPublish/containers/ReleaseContainer.tsx index 4e6c739c298..16f6931f538 100644 --- a/frontend/app-development/features/appPublish/containers/ReleaseContainer.tsx +++ b/frontend/app-development/features/appPublish/containers/ReleaseContainer.tsx @@ -15,11 +15,11 @@ import { useQueryClient } from '@tanstack/react-query'; import { QueryKey } from 'app-shared/types/QueryKey'; import { useRepoStatusQuery } from 'app-shared/hooks/queries'; -import { useStudioUrlParams } from 'app-shared/hooks/useStudioUrlParams'; +import { useStudioEnvironmentParams } from 'app-shared/hooks/useStudioEnvironmentParams'; export function ReleaseContainer() { const hiddenMdDown = useMediaQuery('(max-width: 1025px)'); - const { org, app } = useStudioUrlParams(); + const { org, app } = useStudioEnvironmentParams(); const [popoverOpenClick, setPopoverOpenClick] = useState(false); const [popoverOpenHover, setPopoverOpenHover] = useState(false); diff --git a/frontend/app-development/features/appPublish/pages/DeployPage.tsx b/frontend/app-development/features/appPublish/pages/DeployPage.tsx index 6167aedc471..8e2b34e680c 100644 --- a/frontend/app-development/features/appPublish/pages/DeployPage.tsx +++ b/frontend/app-development/features/appPublish/pages/DeployPage.tsx @@ -7,11 +7,11 @@ import { useDeployPermissionsQuery, useOrgListQuery } from '../../../hooks/queri import { Trans, useTranslation } from 'react-i18next'; import { AltinnContentLoader } from 'app-shared/components/molecules/AltinnContentLoader'; import { useInvalidator } from '../../../hooks/useInvalidator'; -import { useStudioUrlParams } from 'app-shared/hooks/useStudioUrlParams'; +import { useStudioEnvironmentParams } from 'app-shared/hooks/useStudioEnvironmentParams'; import { Alert } from '@digdir/design-system-react'; export function DeployPage() { - const { org, app } = useStudioUrlParams(); + const { org, app } = useStudioEnvironmentParams(); const { t } = useTranslation(); const { data: orgs, isPending: orgsIsPending, isError: orgsIsError } = useOrgListQuery(); const { diff --git a/frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/SelectedSchemaEditor.tsx b/frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/SelectedSchemaEditor.tsx index 9b91e15e32d..0c40e865a98 100644 --- a/frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/SelectedSchemaEditor.tsx +++ b/frontend/app-development/features/dataModelling/SchemaEditorWithToolbar/SelectedSchemaEditor.tsx @@ -14,7 +14,7 @@ import type { } from 'app-shared/types/DataModelMetadata'; import { useQueryClient } from '@tanstack/react-query'; import { QueryKey } from 'app-shared/types/QueryKey'; -import { useStudioUrlParams } from 'app-shared/hooks/useStudioUrlParams'; +import { useStudioEnvironmentParams } from 'app-shared/hooks/useStudioEnvironmentParams'; import { mergeJsonAndXsdData } from 'app-development/utils/metadataUtils'; import { extractFilename, removeSchemaExtension } from 'app-shared/utils/filenameUtils'; export interface SelectedSchemaEditorProps { @@ -58,7 +58,7 @@ interface SchemaEditorWithDebounceProps { } const SchemaEditorWithDebounce = ({ jsonSchema, modelPath }: SchemaEditorWithDebounceProps) => { - const { org, app } = useStudioUrlParams(); + const { org, app } = useStudioEnvironmentParams(); const { mutate } = useSchemaMutation(); const queryClient = useQueryClient(); const [model, setModel] = useState(jsonSchema); diff --git a/frontend/app-development/features/overview/components/DeploymentContainer.tsx b/frontend/app-development/features/overview/components/DeploymentContainer.tsx index 76a9328fd64..966b62a7cce 100644 --- a/frontend/app-development/features/overview/components/DeploymentContainer.tsx +++ b/frontend/app-development/features/overview/components/DeploymentContainer.tsx @@ -5,7 +5,7 @@ import { useEnvironmentsQuery, useOrgListQuery, } from 'app-development/hooks/queries'; -import { useStudioUrlParams } from 'app-shared/hooks/useStudioUrlParams'; +import { useStudioEnvironmentParams } from 'app-shared/hooks/useStudioEnvironmentParams'; import { Alert } from '@digdir/design-system-react'; import { useTranslation } from 'react-i18next'; import { DeploymentStatusList } from './DeploymentStatusList'; @@ -16,7 +16,7 @@ import type { Environment } from 'app-shared/types/Environment'; type DeploymentContainerProps = Pick, 'className'>; export const DeploymentContainer = ({ className }: DeploymentContainerProps) => { - const { org, app } = useStudioUrlParams(); + const { org, app } = useStudioEnvironmentParams(); const { t } = useTranslation(); const { diff --git a/frontend/app-development/features/overview/components/DeploymentStatus.tsx b/frontend/app-development/features/overview/components/DeploymentStatus.tsx index af94db200fc..748605dcd8f 100644 --- a/frontend/app-development/features/overview/components/DeploymentStatus.tsx +++ b/frontend/app-development/features/overview/components/DeploymentStatus.tsx @@ -1,6 +1,6 @@ import React from 'react'; import classes from './DeploymentStatus.module.css'; -import { useStudioUrlParams } from 'app-shared/hooks/useStudioUrlParams'; +import { useStudioEnvironmentParams } from 'app-shared/hooks/useStudioEnvironmentParams'; import { Trans, useTranslation } from 'react-i18next'; import { Alert, Heading, Paragraph, Spinner, Link } from '@digdir/design-system-react'; import { DateUtils } from '@studio/pure-functions'; @@ -24,7 +24,7 @@ export const DeploymentStatus = ({ isProduction, urlToApp, }: DeploymentStatusProps) => { - const { org, app } = useStudioUrlParams(); + const { org, app } = useStudioEnvironmentParams(); const { t } = useTranslation(); const formatDateTime = (dateAsString: string): string => { diff --git a/frontend/app-development/features/overview/components/DeploymentStatusList.tsx b/frontend/app-development/features/overview/components/DeploymentStatusList.tsx index 219d06f5058..cd4f130165e 100644 --- a/frontend/app-development/features/overview/components/DeploymentStatusList.tsx +++ b/frontend/app-development/features/overview/components/DeploymentStatusList.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { useStudioUrlParams } from 'app-shared/hooks/useStudioUrlParams'; +import { useStudioEnvironmentParams } from 'app-shared/hooks/useStudioEnvironmentParams'; import type { Environment } from 'app-shared/types/Environment'; import { DeploymentStatus } from './DeploymentStatus'; import classes from './DeploymentStatusList.module.css'; @@ -20,7 +20,7 @@ export const DeploymentStatusList = ({ kubernetesDeploymentList, pipelineDeploymentList, }: DeploymentStatusListProps) => { - const { org, app } = useStudioUrlParams(); + const { org, app } = useStudioEnvironmentParams(); return (
diff --git a/frontend/app-development/features/overview/components/Deployments.tsx b/frontend/app-development/features/overview/components/Deployments.tsx index 7f15e8584e0..9a8feb2cfcf 100644 --- a/frontend/app-development/features/overview/components/Deployments.tsx +++ b/frontend/app-development/features/overview/components/Deployments.tsx @@ -1,7 +1,7 @@ import type { HTMLAttributes } from 'react'; import React from 'react'; import { useOrgListQuery } from 'app-development/hooks/queries'; -import { useStudioUrlParams } from 'app-shared/hooks/useStudioUrlParams'; +import { useStudioEnvironmentParams } from 'app-shared/hooks/useStudioEnvironmentParams'; import { Alert } from '@digdir/design-system-react'; import { useTranslation } from 'react-i18next'; import { StudioSpinner } from '@studio/components'; @@ -13,7 +13,7 @@ import { DeploymentContainer } from './DeploymentContainer'; type DeploymentsProps = Pick, 'className'>; export const Deployments = ({ className }: DeploymentsProps) => { - const { org, app } = useStudioUrlParams(); + const { org, app } = useStudioEnvironmentParams(); const { data: orgs, diff --git a/frontend/app-development/features/overview/components/Header.tsx b/frontend/app-development/features/overview/components/Header.tsx index 05d41551962..fcb911a8328 100644 --- a/frontend/app-development/features/overview/components/Header.tsx +++ b/frontend/app-development/features/overview/components/Header.tsx @@ -1,13 +1,13 @@ import React, { useEffect } from 'react'; import { useAppConfigQuery } from 'app-development/hooks/queries'; -import { useStudioUrlParams } from 'app-shared/hooks/useStudioUrlParams'; +import { useStudioEnvironmentParams } from 'app-shared/hooks/useStudioEnvironmentParams'; import { Heading } from '@digdir/design-system-react'; import { toast } from 'react-toastify'; import { useTranslation } from 'react-i18next'; import { StudioSpinner } from '@studio/components'; export const Header = () => { - const { org, app } = useStudioUrlParams(); + const { org, app } = useStudioEnvironmentParams(); const { data: appConfigData, diff --git a/frontend/app-development/features/processEditor/ProcessEditor.tsx b/frontend/app-development/features/processEditor/ProcessEditor.tsx index e881b20f863..96e4329d79b 100644 --- a/frontend/app-development/features/processEditor/ProcessEditor.tsx +++ b/frontend/app-development/features/processEditor/ProcessEditor.tsx @@ -2,7 +2,7 @@ import React from 'react'; import { ProcessEditor as ProcessEditorImpl } from '@altinn/process-editor'; import { useAppPolicyMutation, useBpmnMutation } from '../../hooks/mutations'; import { useBpmnQuery } from '../../hooks/queries/useBpmnQuery'; -import { useStudioUrlParams } from 'app-shared/hooks/useStudioUrlParams'; +import { useStudioEnvironmentParams } from 'app-shared/hooks/useStudioEnvironmentParams'; import { toast } from 'react-toastify'; import { StudioPageSpinner } from '@studio/components'; import { useTranslation } from 'react-i18next'; @@ -36,7 +36,7 @@ enum SyncClientsName { export const ProcessEditor = (): React.ReactElement => { const { t } = useTranslation(); - const { org, app } = useStudioUrlParams(); + const { org, app } = useStudioEnvironmentParams(); const queryClient = useQueryClient(); const { data: currentPolicy, isPending: isPendingCurrentPolicy } = useAppPolicyQuery(org, app); const { mutate: mutateApplicationPolicy } = useAppPolicyMutation(org, app); diff --git a/frontend/app-development/features/textEditor/TextEditor.tsx b/frontend/app-development/features/textEditor/TextEditor.tsx index 99e52ba9c9d..d3fa1779271 100644 --- a/frontend/app-development/features/textEditor/TextEditor.tsx +++ b/frontend/app-development/features/textEditor/TextEditor.tsx @@ -11,13 +11,13 @@ import { useDeleteLanguageMutation, useTextIdMutation, } from '../../hooks/mutations'; -import { useStudioUrlParams } from 'app-shared/hooks/useStudioUrlParams'; +import { useStudioEnvironmentParams } from 'app-shared/hooks/useStudioEnvironmentParams'; import { useTranslation } from 'react-i18next'; import { useUpsertTextResourceMutation } from 'app-shared/hooks/mutations/useUpsertTextResourceMutation'; export const TextEditor = () => { const { t } = useTranslation(); - const { org, app } = useStudioUrlParams(); + const { org, app } = useStudioEnvironmentParams(); const [searchParams, setSearchParams] = useSearchParams({ lang: '', search: '' }); const selectedLanguagesStorageKey = `${org}:${app}:selectedLanguages`; diff --git a/frontend/app-development/hooks/mutations/useCreateDataModelMutation.ts b/frontend/app-development/hooks/mutations/useCreateDataModelMutation.ts index 15280a3d96a..0b2fc9bd5ca 100644 --- a/frontend/app-development/hooks/mutations/useCreateDataModelMutation.ts +++ b/frontend/app-development/hooks/mutations/useCreateDataModelMutation.ts @@ -2,7 +2,7 @@ import { useMutation, useQueryClient } from '@tanstack/react-query'; import { useServicesContext } from 'app-shared/contexts/ServicesContext'; import type { CreateDataModelPayload } from 'app-shared/types/api'; import { QueryKey } from 'app-shared/types/QueryKey'; -import { useStudioUrlParams } from 'app-shared/hooks/useStudioUrlParams'; +import { useStudioEnvironmentParams } from 'app-shared/hooks/useStudioEnvironmentParams'; export interface CreateDataModelMutationArgs { name: string; @@ -11,7 +11,7 @@ export interface CreateDataModelMutationArgs { export const useCreateDataModelMutation = () => { const { createDataModel } = useServicesContext(); - const { org, app } = useStudioUrlParams(); + const { org, app } = useStudioEnvironmentParams(); const queryClient = useQueryClient(); return useMutation({ mutationFn: async ({ name, relativePath }: CreateDataModelMutationArgs) => { diff --git a/frontend/app-development/hooks/mutations/useDeleteDataModelMutation.ts b/frontend/app-development/hooks/mutations/useDeleteDataModelMutation.ts index 110e60e6974..9d75689918b 100644 --- a/frontend/app-development/hooks/mutations/useDeleteDataModelMutation.ts +++ b/frontend/app-development/hooks/mutations/useDeleteDataModelMutation.ts @@ -1,13 +1,13 @@ import { useMutation, useQueryClient } from '@tanstack/react-query'; import { useServicesContext } from 'app-shared/contexts/ServicesContext'; import { QueryKey } from 'app-shared/types/QueryKey'; -import { useStudioUrlParams } from 'app-shared/hooks/useStudioUrlParams'; +import { useStudioEnvironmentParams } from 'app-shared/hooks/useStudioEnvironmentParams'; import { isXsdFile } from 'app-shared/utils/filenameUtils'; import type { DataModelMetadata } from 'app-shared/types/DataModelMetadata'; export const useDeleteDataModelMutation = () => { const { deleteDataModel } = useServicesContext(); - const { org, app } = useStudioUrlParams(); + const { org, app } = useStudioEnvironmentParams(); const queryClient = useQueryClient(); return useMutation({ mutationFn: async (modelPath: string) => { diff --git a/frontend/app-development/hooks/mutations/useGenerateModelsMutation.ts b/frontend/app-development/hooks/mutations/useGenerateModelsMutation.ts index d064abbc0aa..9ba270b0979 100644 --- a/frontend/app-development/hooks/mutations/useGenerateModelsMutation.ts +++ b/frontend/app-development/hooks/mutations/useGenerateModelsMutation.ts @@ -4,7 +4,7 @@ import { QueryKey } from 'app-shared/types/QueryKey'; import { useServicesContext } from 'app-shared/contexts/ServicesContext'; import type { AxiosError } from 'axios'; import type { JsonSchema } from 'app-shared/types/JsonSchema'; -import { useStudioUrlParams } from 'app-shared/hooks/useStudioUrlParams'; +import { useStudioEnvironmentParams } from 'app-shared/hooks/useStudioEnvironmentParams'; import type { ApiError } from 'app-shared/types/api/ApiError'; export const useGenerateModelsMutation = ( @@ -12,7 +12,7 @@ export const useGenerateModelsMutation = ( meta?: QueryMeta, ): UseMutationResult> => { const queryClient = useQueryClient(); - const { org, app } = useStudioUrlParams(); + const { org, app } = useStudioEnvironmentParams(); const { generateModels } = useServicesContext(); return useMutation({ mutationFn: (payload: JsonSchema) => generateModels(org, app, modelPath, payload), diff --git a/frontend/app-development/hooks/mutations/useSchemaMutation.ts b/frontend/app-development/hooks/mutations/useSchemaMutation.ts index 4f200985010..43458bef467 100644 --- a/frontend/app-development/hooks/mutations/useSchemaMutation.ts +++ b/frontend/app-development/hooks/mutations/useSchemaMutation.ts @@ -2,11 +2,11 @@ import { useMutation, useQueryClient } from '@tanstack/react-query'; import { QueryKey } from 'app-shared/types/QueryKey'; import { useServicesContext } from 'app-shared/contexts/ServicesContext'; import type { JsonSchema } from 'app-shared/types/JsonSchema'; -import { useStudioUrlParams } from 'app-shared/hooks/useStudioUrlParams'; +import { useStudioEnvironmentParams } from 'app-shared/hooks/useStudioEnvironmentParams'; export const useSchemaMutation = () => { const queryClient = useQueryClient(); - const { org, app } = useStudioUrlParams(); + const { org, app } = useStudioEnvironmentParams(); const { saveDataModel } = useServicesContext(); return useMutation({ mutationFn: async (args: { modelPath: string; model: JsonSchema }) => { diff --git a/frontend/app-development/hooks/mutations/useUploadDataModelMutation.ts b/frontend/app-development/hooks/mutations/useUploadDataModelMutation.ts index 55637941c30..9ee31f87c16 100644 --- a/frontend/app-development/hooks/mutations/useUploadDataModelMutation.ts +++ b/frontend/app-development/hooks/mutations/useUploadDataModelMutation.ts @@ -2,11 +2,11 @@ import type { MutationMeta } from '@tanstack/react-query'; import { useMutation, useQueryClient } from '@tanstack/react-query'; import { useServicesContext } from 'app-shared/contexts/ServicesContext'; import { QueryKey } from 'app-shared/types/QueryKey'; -import { useStudioUrlParams } from 'app-shared/hooks/useStudioUrlParams'; +import { useStudioEnvironmentParams } from 'app-shared/hooks/useStudioEnvironmentParams'; export const useUploadDataModelMutation = (meta?: MutationMeta) => { const { uploadDataModel } = useServicesContext(); - const { org, app } = useStudioUrlParams(); + const { org, app } = useStudioEnvironmentParams(); const queryClient = useQueryClient(); return useMutation({ mutationFn: (file: FormData) => uploadDataModel(org, app, file), diff --git a/frontend/app-development/hooks/queries/useSchemaQuery.ts b/frontend/app-development/hooks/queries/useSchemaQuery.ts index 28e4155e482..4ac480e726a 100644 --- a/frontend/app-development/hooks/queries/useSchemaQuery.ts +++ b/frontend/app-development/hooks/queries/useSchemaQuery.ts @@ -6,13 +6,13 @@ import type { AxiosError } from 'axios'; import type { JsonSchema } from 'app-shared/types/JsonSchema'; import { isXsdFile } from 'app-shared/utils/filenameUtils'; import { StringUtils } from '@studio/pure-functions'; -import { useStudioUrlParams } from 'app-shared/hooks/useStudioUrlParams'; +import { useStudioEnvironmentParams } from 'app-shared/hooks/useStudioEnvironmentParams'; import type { ApiError } from 'app-shared/types/api/ApiError'; export const useSchemaQuery = ( modelPath: string, ): UseQueryResult> => { - const { org, app } = useStudioUrlParams(); + const { org, app } = useStudioEnvironmentParams(); const { getDataModel, addXsdFromRepo } = useServicesContext(); return useQuery>({ queryKey: [QueryKey.JsonSchema, org, app, modelPath], diff --git a/frontend/app-development/router/routes.tsx b/frontend/app-development/router/routes.tsx index 4172b8306d4..6088c6ccd20 100644 --- a/frontend/app-development/router/routes.tsx +++ b/frontend/app-development/router/routes.tsx @@ -7,7 +7,7 @@ import { DeployPage } from '../features/appPublish/pages/DeployPage'; import { ProcessEditor } from 'app-development/features/processEditor'; import { RoutePaths } from 'app-development/enums/RoutePaths'; import type { AppVersion } from 'app-shared/types/AppVersion'; -import { useStudioUrlParams } from 'app-shared/hooks/useStudioUrlParams'; +import { useStudioEnvironmentParams } from 'app-shared/hooks/useStudioEnvironmentParams'; import { useAppVersionQuery } from 'app-shared/hooks/queries'; import React from 'react'; @@ -35,7 +35,7 @@ const isLatestFrontendVersion = (version: AppVersion): boolean => version?.frontendVersion?.startsWith(latestFrontendVersion); const UiEditor = () => { - const { org, app } = useStudioUrlParams(); + const { org, app } = useStudioEnvironmentParams(); const { data: version } = useAppVersionQuery(org, app); if (!version) return null; return isLatestFrontendVersion(version) ? : ; diff --git a/frontend/app-preview/src/components/AppBarConfig/AppPreviewBarConfig.tsx b/frontend/app-preview/src/components/AppBarConfig/AppPreviewBarConfig.tsx index a2383ed66f6..27f8057b09b 100644 --- a/frontend/app-preview/src/components/AppBarConfig/AppPreviewBarConfig.tsx +++ b/frontend/app-preview/src/components/AppBarConfig/AppPreviewBarConfig.tsx @@ -8,7 +8,7 @@ import { ArrowCirclepathIcon, EyeIcon, LinkIcon } from '@studio/icons'; import { useTranslation } from 'react-i18next'; import type { AppPreviewSubMenuProps } from '../AppPreviewSubMenu'; import { useLayoutSetsQuery } from 'app-shared/hooks/queries/useLayoutSetsQuery'; -import { useStudioUrlParams } from 'app-shared/hooks/useStudioUrlParams'; +import { useStudioEnvironmentParams } from 'app-shared/hooks/useStudioEnvironmentParams'; import { TopBarMenu } from 'app-shared/enums/TopBarMenu'; import type { TopBarMenuItem } from 'app-shared/types/TopBarMenuItem'; import { PackagesRouter } from 'app-shared/navigation/PackagesRouter'; @@ -43,7 +43,7 @@ export const SubPreviewMenuLeftContent = ({ handleChangeLayoutSet, }: AppPreviewSubMenuProps) => { const { t } = useTranslation(); - const { org, app } = useStudioUrlParams(); + const { org, app } = useStudioEnvironmentParams(); const { data: layoutSets } = useLayoutSetsQuery(org, app); return ( diff --git a/frontend/app-preview/src/views/LandingPage.tsx b/frontend/app-preview/src/views/LandingPage.tsx index b2a0d762529..9e469d1f0a8 100644 --- a/frontend/app-preview/src/views/LandingPage.tsx +++ b/frontend/app-preview/src/views/LandingPage.tsx @@ -13,7 +13,7 @@ import { } from '../components/AppBarConfig/AppPreviewBarConfig'; import { AppPreviewSubMenu } from '../components/AppPreviewSubMenu'; -import { useStudioUrlParams } from 'app-shared/hooks/useStudioUrlParams'; +import { useStudioEnvironmentParams } from 'app-shared/hooks/useStudioEnvironmentParams'; import { previewPage } from 'app-shared/api/paths'; import type { TopBarMenuItem } from 'app-shared/types/TopBarMenuItem'; import { PreviewLimitationsInfo } from 'app-shared/components/PreviewLimitationsInfo/PreviewLimitationsInfo'; @@ -30,7 +30,7 @@ export interface LandingPageProps { export type PreviewAsViewSize = 'desktop' | 'mobile'; export const LandingPage = ({ variant = 'preview' }: LandingPageProps) => { - const { org, app } = useStudioUrlParams(); + const { org, app } = useStudioEnvironmentParams(); const { t } = useTranslation(); const previewConnection = usePreviewConnection(); const { data: user } = useUserQuery(); diff --git a/frontend/packages/process-editor/src/components/ConfigPanel/ConfigEndEvent/CustomReceiptContent/RedirectToCreatePageButton/RedirectToCreatePageButton.tsx b/frontend/packages/process-editor/src/components/ConfigPanel/ConfigEndEvent/CustomReceiptContent/RedirectToCreatePageButton/RedirectToCreatePageButton.tsx index 29cad995f32..9a838e00dba 100644 --- a/frontend/packages/process-editor/src/components/ConfigPanel/ConfigEndEvent/CustomReceiptContent/RedirectToCreatePageButton/RedirectToCreatePageButton.tsx +++ b/frontend/packages/process-editor/src/components/ConfigPanel/ConfigEndEvent/CustomReceiptContent/RedirectToCreatePageButton/RedirectToCreatePageButton.tsx @@ -1,6 +1,6 @@ import React from 'react'; import classes from './RedirectToCreatePageButton.module.css'; -import { useStudioUrlParams } from 'app-shared/hooks/useStudioUrlParams'; +import { useStudioEnvironmentParams } from 'app-shared/hooks/useStudioEnvironmentParams'; import { PackagesRouter } from 'app-shared/navigation/PackagesRouter'; import { PencilWritingIcon } from '@studio/icons'; import { StudioButton } from '@studio/components'; @@ -11,7 +11,7 @@ import { RedirectBox } from '../../../../RedirectBox'; export const RedirectToCreatePageButton = (): React.ReactElement => { const { t } = useTranslation(); - const { org, app } = useStudioUrlParams(); + const { org, app } = useStudioEnvironmentParams(); const packagesRouter = new PackagesRouter({ org, app }); const { existingCustomReceiptLayoutSetId } = useBpmnApiContext(); diff --git a/frontend/packages/shared/src/components/GiteaHeader/ThreeDotsMenu/CloneModal/CloneModal.tsx b/frontend/packages/shared/src/components/GiteaHeader/ThreeDotsMenu/CloneModal/CloneModal.tsx index b6a62e6990e..7e548bb33bd 100644 --- a/frontend/packages/shared/src/components/GiteaHeader/ThreeDotsMenu/CloneModal/CloneModal.tsx +++ b/frontend/packages/shared/src/components/GiteaHeader/ThreeDotsMenu/CloneModal/CloneModal.tsx @@ -7,7 +7,7 @@ import classes from './CloneModal.module.css'; import { LegacyTextField } from '@digdir/design-system-react'; import { useTranslation } from 'react-i18next'; import { useDataModelsXsdQuery } from 'app-shared/hooks/queries'; -import { useStudioUrlParams } from 'app-shared/hooks/useStudioUrlParams'; +import { useStudioEnvironmentParams } from 'app-shared/hooks/useStudioEnvironmentParams'; import { InformationSquareFillIcon } from '@studio/icons'; import { StudioButton } from '@studio/components'; @@ -17,7 +17,7 @@ export interface ICloneModalProps { } export const CloneModal = (props: ICloneModalProps) => { - const { org, app } = useStudioUrlParams(); + const { org, app } = useStudioEnvironmentParams(); const gitUrl = window.location.origin.toString() + repositoryGitPath(org, app); const copyGitUrl = () => navigator.clipboard.writeText(gitUrl); const canCopy = document.queryCommandSupported ? document.queryCommandSupported('copy') : false; diff --git a/frontend/packages/shared/src/hooks/useStudioUrlParams.test.ts b/frontend/packages/shared/src/hooks/useStudioEnvironmentParams.test.ts similarity index 51% rename from frontend/packages/shared/src/hooks/useStudioUrlParams.test.ts rename to frontend/packages/shared/src/hooks/useStudioEnvironmentParams.test.ts index 3cd746722f9..4b36cf424b5 100644 --- a/frontend/packages/shared/src/hooks/useStudioUrlParams.test.ts +++ b/frontend/packages/shared/src/hooks/useStudioEnvironmentParams.test.ts @@ -1,10 +1,10 @@ import { app, org } from '@studio/testing/testids'; import { renderHook } from '@testing-library/react'; -import { useStudioUrlParams } from 'app-shared/hooks/useStudioUrlParams'; +import { useStudioEnvironmentParams } from 'app-shared/hooks/useStudioEnvironmentParams'; -describe('useStudioUrlParams', () => { +describe('useStudioEnvironmentParams', () => { it('Returns the org and app names from the URL', () => { - const { result } = renderHook(() => useStudioUrlParams()); + const { result } = renderHook(() => useStudioEnvironmentParams()); expect(result.current).toEqual({ org, app }); }); }); diff --git a/frontend/packages/shared/src/hooks/useStudioUrlParams.ts b/frontend/packages/shared/src/hooks/useStudioEnvironmentParams.ts similarity index 54% rename from frontend/packages/shared/src/hooks/useStudioUrlParams.ts rename to frontend/packages/shared/src/hooks/useStudioEnvironmentParams.ts index 73e2b70736c..9a17e3cf45a 100644 --- a/frontend/packages/shared/src/hooks/useStudioUrlParams.ts +++ b/frontend/packages/shared/src/hooks/useStudioEnvironmentParams.ts @@ -1,6 +1,6 @@ import { useParams } from 'react-router-dom'; -interface StudioUrlParams { +interface StudioEnvironmentParams { org: string; app: string; } @@ -9,7 +9,7 @@ interface StudioUrlParams { * Retrieves the org and app names from the URL. * @returns {StudioUrlParams} The org and app names. */ -export const useStudioUrlParams = (): StudioUrlParams => { - const { org, app } = useParams>(); +export const useStudioEnvironmentParams = (): StudioEnvironmentParams => { + const { org, app } = useParams>(); return { org, app }; }; diff --git a/frontend/packages/shared/src/navigation/main-header/ProfileMenu/ProfileMenu.tsx b/frontend/packages/shared/src/navigation/main-header/ProfileMenu/ProfileMenu.tsx index 13e10121fe7..ca47834f4da 100644 --- a/frontend/packages/shared/src/navigation/main-header/ProfileMenu/ProfileMenu.tsx +++ b/frontend/packages/shared/src/navigation/main-header/ProfileMenu/ProfileMenu.tsx @@ -7,7 +7,7 @@ import { post } from '../../../utils/networking'; import { repositoryPath, userLogoutAfterPath, userLogoutPath } from '../../../api/paths'; import { useTranslation } from 'react-i18next'; import type { User } from 'app-shared/types/Repository'; -import { useStudioUrlParams } from 'app-shared/hooks/useStudioUrlParams'; +import { useStudioEnvironmentParams } from 'app-shared/hooks/useStudioEnvironmentParams'; import { StudioButton } from '@studio/components'; import { profileButtonId } from '@studio/testing/testids'; @@ -37,7 +37,7 @@ export const ProfileMenu = ({ const menuRef = useRef(null); const [menuOpen, setMenuOpen] = useState(false); - const { org, app } = useStudioUrlParams(); + const { org, app } = useStudioEnvironmentParams(); const handleClick = (event: any) => setMenuOpen(true); const handleClose = () => setMenuOpen(false); diff --git a/frontend/packages/text-editor/src/TextList.tsx b/frontend/packages/text-editor/src/TextList.tsx index 17dc5d7bd96..afd4ede9365 100644 --- a/frontend/packages/text-editor/src/TextList.tsx +++ b/frontend/packages/text-editor/src/TextList.tsx @@ -14,7 +14,7 @@ import { import { useTranslation } from 'react-i18next'; import { APP_NAME } from 'app-shared/constants'; import { useLayoutNamesQuery } from './hooks/useLayoutNamesQuery'; -import { useStudioUrlParams } from 'app-shared/hooks/useStudioUrlParams'; +import { useStudioEnvironmentParams } from 'app-shared/hooks/useStudioEnvironmentParams'; export type TextListProps = { resourceRows: TextTableRow[]; @@ -30,7 +30,7 @@ export const TextList = ({ selectedLanguages, ...rest }: TextListProps) => { - const { org, app } = useStudioUrlParams(); + const { org, app } = useStudioEnvironmentParams(); const { t } = useTranslation(); const { data: layoutNames, isPending: layoutNamesPending } = useLayoutNamesQuery(org, app); diff --git a/frontend/packages/ux-editor-v3/src/App.tsx b/frontend/packages/ux-editor-v3/src/App.tsx index b58a476a1cc..8bd247f5f90 100644 --- a/frontend/packages/ux-editor-v3/src/App.tsx +++ b/frontend/packages/ux-editor-v3/src/App.tsx @@ -9,7 +9,7 @@ import { selectedLayoutNameSelector } from './selectors/formLayoutSelectors'; import { useWidgetsQuery } from './hooks/queries/useWidgetsQuery'; import { useTextResourcesQuery } from 'app-shared/hooks/queries/useTextResourcesQuery'; import { useLayoutSetsQuery } from 'app-shared/hooks/queries/useLayoutSetsQuery'; -import { useStudioUrlParams } from 'app-shared/hooks/useStudioUrlParams'; +import { useStudioEnvironmentParams } from 'app-shared/hooks/useStudioEnvironmentParams'; import { useAppContext } from './hooks/useAppContext'; import { FormItemContextProvider } from './containers/FormItemContext'; @@ -21,7 +21,7 @@ import { FormItemContextProvider } from './containers/FormItemContext'; export function App() { const t = useText(); - const { org, app } = useStudioUrlParams(); + const { org, app } = useStudioEnvironmentParams(); const selectedLayout = useSelector(selectedLayoutNameSelector); const { selectedLayoutSet, setSelectedLayoutSet, removeSelectedLayoutSet } = useAppContext(); const { data: layoutSets, isSuccess: areLayoutSetsFetched } = useLayoutSetsQuery(org, app); diff --git a/frontend/packages/ux-editor-v3/src/SubApp.tsx b/frontend/packages/ux-editor-v3/src/SubApp.tsx index d2288698d6b..2160dee3ffa 100644 --- a/frontend/packages/ux-editor-v3/src/SubApp.tsx +++ b/frontend/packages/ux-editor-v3/src/SubApp.tsx @@ -5,13 +5,13 @@ import { setupStore } from './store'; import './styles/index.css'; import { AppContext } from './AppContext'; import { useReactiveLocalStorage } from 'app-shared/hooks/useReactiveLocalStorage'; -import { useStudioUrlParams } from 'app-shared/hooks/useStudioUrlParams'; +import { useStudioEnvironmentParams } from 'app-shared/hooks/useStudioEnvironmentParams'; const store = setupStore(); export const SubApp = () => { const previewIframeRef = useRef(null); - const { app } = useStudioUrlParams(); + const { app } = useStudioEnvironmentParams(); const [selectedLayoutSet, setSelectedLayoutSet, removeSelectedLayoutSet] = useReactiveLocalStorage('layoutSet/' + app, null); diff --git a/frontend/packages/ux-editor-v3/src/components/Elements/Elements.tsx b/frontend/packages/ux-editor-v3/src/components/Elements/Elements.tsx index 3c8adc8a9f3..030a495a925 100644 --- a/frontend/packages/ux-editor-v3/src/components/Elements/Elements.tsx +++ b/frontend/packages/ux-editor-v3/src/components/Elements/Elements.tsx @@ -9,12 +9,12 @@ import { useFormLayoutSettingsQuery } from '../../hooks/queries/useFormLayoutSet import { useLayoutSetsQuery } from 'app-shared/hooks/queries/useLayoutSetsQuery'; import { LayoutSetsContainer } from './LayoutSetsContainer'; -import { useStudioUrlParams } from 'app-shared/hooks/useStudioUrlParams'; +import { useStudioEnvironmentParams } from 'app-shared/hooks/useStudioEnvironmentParams'; import classes from './Elements.module.css'; import { useAppContext } from '../../hooks/useAppContext'; export const Elements = () => { - const { org, app } = useStudioUrlParams(); + const { org, app } = useStudioEnvironmentParams(); const selectedLayout: string = useSelector(selectedLayoutNameSelector); const { selectedLayoutSet } = useAppContext(); const layoutSetsQuery = useLayoutSetsQuery(org, app); diff --git a/frontend/packages/ux-editor-v3/src/components/Elements/LayoutSetsContainer.tsx b/frontend/packages/ux-editor-v3/src/components/Elements/LayoutSetsContainer.tsx index 612538c2200..08928286ec1 100644 --- a/frontend/packages/ux-editor-v3/src/components/Elements/LayoutSetsContainer.tsx +++ b/frontend/packages/ux-editor-v3/src/components/Elements/LayoutSetsContainer.tsx @@ -1,13 +1,13 @@ import React from 'react'; import { useLayoutSetsQuery } from 'app-shared/hooks/queries/useLayoutSetsQuery'; import { NativeSelect } from '@digdir/design-system-react'; -import { useStudioUrlParams } from 'app-shared/hooks/useStudioUrlParams'; +import { useStudioEnvironmentParams } from 'app-shared/hooks/useStudioEnvironmentParams'; import { useText } from '../../hooks'; import classes from './LayoutSetsContainer.module.css'; import { useAppContext } from '../../hooks/useAppContext'; export function LayoutSetsContainer() { - const { org, app } = useStudioUrlParams(); + const { org, app } = useStudioEnvironmentParams(); const layoutSetsQuery = useLayoutSetsQuery(org, app); const layoutSetNames = layoutSetsQuery.data?.sets?.map((set) => set.id); const t = useText(); diff --git a/frontend/packages/ux-editor-v3/src/components/FormComponent/FormComponent.tsx b/frontend/packages/ux-editor-v3/src/components/FormComponent/FormComponent.tsx index 30a96f5b8ae..6f9c50515d4 100644 --- a/frontend/packages/ux-editor-v3/src/components/FormComponent/FormComponent.tsx +++ b/frontend/packages/ux-editor-v3/src/components/FormComponent/FormComponent.tsx @@ -16,7 +16,7 @@ import { useDeleteFormComponentMutation } from '../../hooks/mutations/useDeleteF import { useTextResourcesSelector } from '../../hooks'; import { useTranslation } from 'react-i18next'; import { AltinnConfirmDialog } from 'app-shared/components'; -import { useStudioUrlParams } from 'app-shared/hooks/useStudioUrlParams'; +import { useStudioEnvironmentParams } from 'app-shared/hooks/useStudioEnvironmentParams'; import { useAppContext } from '../../hooks/useAppContext'; export interface IFormComponentProps { @@ -40,7 +40,7 @@ export const FormComponent = memo(function FormComponent({ isEditMode, }: IFormComponentProps) { const { t } = useTranslation(); - const { org, app } = useStudioUrlParams(); + const { org, app } = useStudioEnvironmentParams(); const textResources: ITextResource[] = useTextResourcesSelector( textResourcesByLanguageSelector(DEFAULT_LANGUAGE), diff --git a/frontend/packages/ux-editor-v3/src/components/Preview/Preview.tsx b/frontend/packages/ux-editor-v3/src/components/Preview/Preview.tsx index 2c2df9f2742..500d841ce27 100644 --- a/frontend/packages/ux-editor-v3/src/components/Preview/Preview.tsx +++ b/frontend/packages/ux-editor-v3/src/components/Preview/Preview.tsx @@ -1,6 +1,6 @@ import React, { useState } from 'react'; import classes from './Preview.module.css'; -import { useStudioUrlParams } from 'app-shared/hooks/useStudioUrlParams'; +import { useStudioEnvironmentParams } from 'app-shared/hooks/useStudioEnvironmentParams'; import { useSelector } from 'react-redux'; import cn from 'classnames'; import { selectedLayoutNameSelector } from '../../selectors/formLayoutSelectors'; @@ -60,7 +60,7 @@ const NoSelectedPageMessage = () => { // The actual preview frame that displays the selected page const PreviewFrame = () => { - const { org, app } = useStudioUrlParams(); + const { org, app } = useStudioEnvironmentParams(); const [viewportToSimulate, setViewportToSimulate] = useState('desktop'); const { t } = useTranslation(); const { previewIframeRef, selectedLayoutSet } = useAppContext(); diff --git a/frontend/packages/ux-editor-v3/src/components/Properties/OldDynamicsInfo.tsx b/frontend/packages/ux-editor-v3/src/components/Properties/OldDynamicsInfo.tsx index 6194b9d0b4d..346c5af4042 100644 --- a/frontend/packages/ux-editor-v3/src/components/Properties/OldDynamicsInfo.tsx +++ b/frontend/packages/ux-editor-v3/src/components/Properties/OldDynamicsInfo.tsx @@ -3,14 +3,14 @@ import classes from './OldDynamicsInfo.module.css'; import { ExternalLinkIcon } from '@studio/icons'; import { useTranslation } from 'react-i18next'; import { giteaEditLink, altinnDocsUrl } from 'app-shared/ext-urls'; -import { useStudioUrlParams } from 'app-shared/hooks/useStudioUrlParams'; +import { useStudioEnvironmentParams } from 'app-shared/hooks/useStudioEnvironmentParams'; import { useAppContext } from '../../hooks/useAppContext'; import { Link } from '@digdir/design-system-react'; export const OldDynamicsInfo = () => { const { t } = useTranslation(); const { selectedLayoutSet } = useAppContext(); - const { app, org } = useStudioUrlParams(); + const { app, org } = useStudioEnvironmentParams(); const dynamicLocation = selectedLayoutSet ? `App/ui/${selectedLayoutSet}/RuleHandler.js` : 'App/ui/RuleHandler.js'; diff --git a/frontend/packages/ux-editor-v3/src/components/TextResourceEdit.tsx b/frontend/packages/ux-editor-v3/src/components/TextResourceEdit.tsx index 598892a5d43..4cb72db68c5 100644 --- a/frontend/packages/ux-editor-v3/src/components/TextResourceEdit.tsx +++ b/frontend/packages/ux-editor-v3/src/components/TextResourceEdit.tsx @@ -10,14 +10,14 @@ import { useTextResourcesSelector } from '../hooks'; import { useUpsertTextResourcesMutation } from 'app-shared/hooks/mutations'; import { useTranslation } from 'react-i18next'; import { useTextResourcesQuery } from 'app-shared/hooks/queries'; -import { useStudioUrlParams } from 'app-shared/hooks/useStudioUrlParams'; +import { useStudioEnvironmentParams } from 'app-shared/hooks/useStudioEnvironmentParams'; import { useAppContext } from '../hooks/useAppContext'; import { StudioButton } from '@studio/components'; export const TextResourceEdit = () => { const dispatch = useDispatch(); const editId = useSelector(getCurrentEditId); - const { org, app } = useStudioUrlParams(); + const { org, app } = useStudioEnvironmentParams(); const { data: textResources } = useTextResourcesQuery(org, app); const languages: string[] = useTextResourcesSelector(getAllLanguages); const setEditId = (id: string) => dispatch(setCurrentEditId(id)); @@ -64,7 +64,7 @@ export interface TextBoxProps { } const TextBox = ({ language, t, textResource, textResourceId }: TextBoxProps) => { - const { org, app } = useStudioUrlParams(); + const { org, app } = useStudioEnvironmentParams(); const { mutate } = useUpsertTextResourcesMutation(org, app); const { previewIframeRef } = useAppContext(); diff --git a/frontend/packages/ux-editor-v3/src/components/config/EditFormContainer.tsx b/frontend/packages/ux-editor-v3/src/components/config/EditFormContainer.tsx index 3ed51a16ca6..8b23beffd19 100644 --- a/frontend/packages/ux-editor-v3/src/components/config/EditFormContainer.tsx +++ b/frontend/packages/ux-editor-v3/src/components/config/EditFormContainer.tsx @@ -25,7 +25,7 @@ import { selectedLayoutNameSelector } from '../../selectors/formLayoutSelectors' import { useFormLayoutsQuery } from '../../hooks/queries/useFormLayoutsQuery'; import { FormField } from '../FormField'; import type { FormContainer } from '../../types/FormContainer'; -import { useStudioUrlParams } from 'app-shared/hooks/useStudioUrlParams'; +import { useStudioEnvironmentParams } from 'app-shared/hooks/useStudioEnvironmentParams'; import { useAppContext } from '../../hooks/useAppContext'; import { ComponentTypeV3 } from 'app-shared/types/ComponentTypeV3'; @@ -42,7 +42,7 @@ export const EditFormContainer = ({ }: IEditFormContainerProps) => { const t = useText(); - const { org, app } = useStudioUrlParams(); + const { org, app } = useStudioEnvironmentParams(); const { selectedLayoutSet } = useAppContext(); const { data: formLayouts } = useFormLayoutsQuery(org, app, selectedLayoutSet); diff --git a/frontend/packages/ux-editor-v3/src/components/config/Expressions/ExpressionContent/ExpressionEditMode/SimpleExpression/DataSourceValue.tsx b/frontend/packages/ux-editor-v3/src/components/config/Expressions/ExpressionContent/ExpressionEditMode/SimpleExpression/DataSourceValue.tsx index f2723ed813f..f15e8122113 100644 --- a/frontend/packages/ux-editor-v3/src/components/config/Expressions/ExpressionContent/ExpressionEditMode/SimpleExpression/DataSourceValue.tsx +++ b/frontend/packages/ux-editor-v3/src/components/config/Expressions/ExpressionContent/ExpressionEditMode/SimpleExpression/DataSourceValue.tsx @@ -15,7 +15,7 @@ import { getDataModelElementNames, } from '../../../../../../utils/expressionsUtils'; import { useText } from '../../../../../../hooks'; -import { useStudioUrlParams } from 'app-shared/hooks/useStudioUrlParams'; +import { useStudioEnvironmentParams } from 'app-shared/hooks/useStudioEnvironmentParams'; import { useAppContext } from '../../../../../../hooks/useAppContext'; export interface DataSourceValueProps { @@ -31,7 +31,7 @@ export const DataSourceValue = ({ specifyDataSourceValue, isComparableValue, }: DataSourceValueProps) => { - const { org, app } = useStudioUrlParams(); + const { org, app } = useStudioEnvironmentParams(); const { selectedLayoutSet } = useAppContext(); // TODO: Show spinner when isLoading const dataModelQuery = useDataModelMetadataQuery(org, app, selectedLayoutSet, undefined); diff --git a/frontend/packages/ux-editor-v3/src/components/config/SelectDataModelComponent.tsx b/frontend/packages/ux-editor-v3/src/components/config/SelectDataModelComponent.tsx index 5ae573487b4..734a551ebf1 100644 --- a/frontend/packages/ux-editor-v3/src/components/config/SelectDataModelComponent.tsx +++ b/frontend/packages/ux-editor-v3/src/components/config/SelectDataModelComponent.tsx @@ -3,7 +3,7 @@ import { LegacySelect } from '@digdir/design-system-react'; import { useDataModelMetadataQuery } from '../../hooks/queries/useDataModelMetadataQuery'; import { FormField } from '../FormField'; import type { Option } from '@altinn/text-editor/types'; -import { useStudioUrlParams } from 'app-shared/hooks/useStudioUrlParams'; +import { useStudioEnvironmentParams } from 'app-shared/hooks/useStudioEnvironmentParams'; import { useAppContext } from '../../hooks/useAppContext'; export interface ISelectDataModelProps { @@ -30,7 +30,7 @@ export const SelectDataModelComponent = ({ helpText, propertyPath, }: ISelectDataModelProps) => { - const { org, app } = useStudioUrlParams(); + const { org, app } = useStudioEnvironmentParams(); const { selectedLayoutSet } = useAppContext(); const { data } = useDataModelMetadataQuery(org, app, selectedLayoutSet, undefined); const [dataModelElementNames, setDataModelElementNames] = React.useState([]); diff --git a/frontend/packages/ux-editor-v3/src/components/config/editModal/EditCodeList.tsx b/frontend/packages/ux-editor-v3/src/components/config/editModal/EditCodeList.tsx index bfd5a7cf58a..6bb473b74ed 100644 --- a/frontend/packages/ux-editor-v3/src/components/config/editModal/EditCodeList.tsx +++ b/frontend/packages/ux-editor-v3/src/components/config/editModal/EditCodeList.tsx @@ -7,11 +7,11 @@ import { StudioButton, StudioSpinner } from '@studio/components'; import { altinnDocsUrl } from 'app-shared/ext-urls'; import { FormField } from '../../FormField'; -import { useStudioUrlParams } from 'app-shared/hooks/useStudioUrlParams'; +import { useStudioEnvironmentParams } from 'app-shared/hooks/useStudioEnvironmentParams'; export function EditCodeList({ component, handleComponentChange }: IGenericEditComponent) { const { t } = useTranslation(); - const { org, app } = useStudioUrlParams(); + const { org, app } = useStudioEnvironmentParams(); const { data: optionListIds, isPending, isError, error } = useOptionListIdsQuery(org, app); const [useCustomCodeList, setUseCustomCodeList] = useState(optionListIds?.length === 0); diff --git a/frontend/packages/ux-editor-v3/src/components/config/editModal/EditDataModelBindings.tsx b/frontend/packages/ux-editor-v3/src/components/config/editModal/EditDataModelBindings.tsx index 7406ceea7c6..94069b70a3e 100644 --- a/frontend/packages/ux-editor-v3/src/components/config/editModal/EditDataModelBindings.tsx +++ b/frontend/packages/ux-editor-v3/src/components/config/editModal/EditDataModelBindings.tsx @@ -5,7 +5,7 @@ import React, { useEffect, useState } from 'react'; import { useText } from '../../../hooks'; import { SelectDataModelComponent } from '../SelectDataModelComponent'; import { useDataModelMetadataQuery } from '../../../hooks/queries/useDataModelMetadataQuery'; -import { useStudioUrlParams } from 'app-shared/hooks/useStudioUrlParams'; +import { useStudioEnvironmentParams } from 'app-shared/hooks/useStudioEnvironmentParams'; import { LinkIcon } from '@studio/icons'; import { StudioButton } from '@studio/components'; import classes from './EditDataModelBindings.module.css'; @@ -28,7 +28,7 @@ export const EditDataModelBindings = ({ renderOptions, helpText, }: EditDataModelBindingsProps) => { - const { org, app } = useStudioUrlParams(); + const { org, app } = useStudioEnvironmentParams(); const { selectedLayoutSet } = useAppContext(); const { data } = useDataModelMetadataQuery(org, app, selectedLayoutSet, undefined); const t = useText(); diff --git a/frontend/packages/ux-editor-v3/src/components/toolbar/ConditionalRenderingModal.tsx b/frontend/packages/ux-editor-v3/src/components/toolbar/ConditionalRenderingModal.tsx index 3241bb22125..1b737dbd8fa 100644 --- a/frontend/packages/ux-editor-v3/src/components/toolbar/ConditionalRenderingModal.tsx +++ b/frontend/packages/ux-editor-v3/src/components/toolbar/ConditionalRenderingModal.tsx @@ -18,7 +18,7 @@ import { addConditionalRenderingConnection, deleteConditionalRenderingConnection, } from '../../utils/ruleConfigUtils'; -import { useStudioUrlParams } from 'app-shared/hooks/useStudioUrlParams'; +import { useStudioEnvironmentParams } from 'app-shared/hooks/useStudioEnvironmentParams'; import { useFormLayoutsQuery } from '../../hooks/queries/useFormLayoutsQuery'; import { useAppContext } from '../../hooks/useAppContext'; @@ -29,7 +29,7 @@ export interface IConditionalRenderingModalProps { } export function ConditionalRenderingModal(props: IConditionalRenderingModalProps) { - const { org, app } = useStudioUrlParams(); + const { org, app } = useStudioEnvironmentParams(); const [selectedConnectionId, setSelectedConnectionId] = React.useState(null); const { selectedLayoutSet } = useAppContext(); const { data: ruleModel } = useRuleModelQuery(org, app, selectedLayoutSet); diff --git a/frontend/packages/ux-editor-v3/src/components/toolbar/RuleModal.tsx b/frontend/packages/ux-editor-v3/src/components/toolbar/RuleModal.tsx index ab8fab7a035..d95788cb2f9 100644 --- a/frontend/packages/ux-editor-v3/src/components/toolbar/RuleModal.tsx +++ b/frontend/packages/ux-editor-v3/src/components/toolbar/RuleModal.tsx @@ -9,7 +9,7 @@ import type { RuleConnection } from 'app-shared/types/RuleConfig'; import { useRuleConfigQuery } from '../../hooks/queries/useRuleConfigQuery'; import { useRuleConfigMutation } from '../../hooks/mutations/useRuleConfigMutation'; import { addRuleConnection, deleteRuleConnection } from '../../utils/ruleConfigUtils'; -import { useStudioUrlParams } from 'app-shared/hooks/useStudioUrlParams'; +import { useStudioEnvironmentParams } from 'app-shared/hooks/useStudioEnvironmentParams'; import { useAppContext } from '../../hooks/useAppContext'; export interface IRuleModalProps { @@ -19,7 +19,7 @@ export interface IRuleModalProps { } export function RuleModal(props: IRuleModalProps) { - const { org, app } = useStudioUrlParams(); + const { org, app } = useStudioEnvironmentParams(); const [selectedConnectionId, setSelectedConnectionId] = React.useState(null); const { selectedLayoutSet } = useAppContext(); const { data: ruleConfig } = useRuleConfigQuery(org, app, selectedLayoutSet); diff --git a/frontend/packages/ux-editor-v3/src/containers/DesignView/DesignView.tsx b/frontend/packages/ux-editor-v3/src/containers/DesignView/DesignView.tsx index 09faedd0d6a..3b61368ea5c 100644 --- a/frontend/packages/ux-editor-v3/src/containers/DesignView/DesignView.tsx +++ b/frontend/packages/ux-editor-v3/src/containers/DesignView/DesignView.tsx @@ -4,7 +4,7 @@ import { useDispatch } from 'react-redux'; import { useFormLayoutsQuery } from '../../hooks/queries/useFormLayoutsQuery'; import classes from './DesignView.module.css'; import { useTranslation } from 'react-i18next'; -import { useStudioUrlParams } from 'app-shared/hooks/useStudioUrlParams'; +import { useStudioEnvironmentParams } from 'app-shared/hooks/useStudioEnvironmentParams'; import { Accordion } from '@digdir/design-system-react'; import type { IFormLayouts } from '../../types/global'; import type { FormLayoutPage } from '../../types/FormLayoutPage'; @@ -39,7 +39,7 @@ const mapFormLayoutsToFormLayoutPages = (formLayouts: IFormLayouts): FormLayoutP */ export const DesignView = (): ReactNode => { const dispatch = useDispatch(); - const { org, app } = useStudioUrlParams(); + const { org, app } = useStudioEnvironmentParams(); const { selectedLayoutSet } = useAppContext(); const { mutate: addLayoutMutation, isPending } = useAddLayoutMutation( org, diff --git a/frontend/packages/ux-editor-v3/src/containers/DesignView/FormTree/FormItem/FormItemTitle/useDeleteItem.ts b/frontend/packages/ux-editor-v3/src/containers/DesignView/FormTree/FormItem/FormItemTitle/useDeleteItem.ts index 9bc8ca04f6b..2871c57e2bc 100644 --- a/frontend/packages/ux-editor-v3/src/containers/DesignView/FormTree/FormItem/FormItemTitle/useDeleteItem.ts +++ b/frontend/packages/ux-editor-v3/src/containers/DesignView/FormTree/FormItem/FormItemTitle/useDeleteItem.ts @@ -1,4 +1,4 @@ -import { useStudioUrlParams } from 'app-shared/hooks/useStudioUrlParams'; +import { useStudioEnvironmentParams } from 'app-shared/hooks/useStudioEnvironmentParams'; import { useDeleteFormContainerMutation } from '../../../../../hooks/mutations/useDeleteFormContainerMutation'; import { useDeleteFormComponentMutation } from '../../../../../hooks/mutations/useDeleteFormComponentMutation'; import { useMemo } from 'react'; @@ -8,7 +8,7 @@ import type { FormContainer } from '../../../../../types/FormContainer'; import { useAppContext } from '../../../../../hooks/useAppContext'; export const useDeleteItem = (formItem: FormComponent | FormContainer) => { - const { org, app } = useStudioUrlParams(); + const { org, app } = useStudioEnvironmentParams(); const { selectedLayoutSet } = useAppContext(); const { mutate: deleteContainer } = useDeleteFormContainerMutation(org, app, selectedLayoutSet); const { mutate: deleteComponent } = useDeleteFormComponentMutation(org, app, selectedLayoutSet); diff --git a/frontend/packages/ux-editor-v3/src/containers/DesignView/FormTree/UnknownReferencedItem/useDeleteUnknownComponentReference.ts b/frontend/packages/ux-editor-v3/src/containers/DesignView/FormTree/UnknownReferencedItem/useDeleteUnknownComponentReference.ts index 7b45abb6eee..608b3ec7dbe 100644 --- a/frontend/packages/ux-editor-v3/src/containers/DesignView/FormTree/UnknownReferencedItem/useDeleteUnknownComponentReference.ts +++ b/frontend/packages/ux-editor-v3/src/containers/DesignView/FormTree/UnknownReferencedItem/useDeleteUnknownComponentReference.ts @@ -1,4 +1,4 @@ -import { useStudioUrlParams } from 'app-shared/hooks/useStudioUrlParams'; +import { useStudioEnvironmentParams } from 'app-shared/hooks/useStudioEnvironmentParams'; import { useAppContext } from '../../../../hooks/useAppContext'; import { useSelectedFormLayoutWithName } from '../../../../hooks'; import { useFormLayoutMutation } from '../../../../hooks/mutations/useFormLayoutMutation'; @@ -6,7 +6,7 @@ import { removeComponent } from '../../../../utils/formLayoutUtils'; import type { IInternalLayout } from '../../../../types/global'; export const useDeleteUnknownComponentReference = () => { - const { org, app } = useStudioUrlParams(); + const { org, app } = useStudioEnvironmentParams(); const { selectedLayoutSet } = useAppContext(); const { layoutName } = useSelectedFormLayoutWithName(); const { mutateAsync: updateFormLayoutMutation } = useFormLayoutMutation( diff --git a/frontend/packages/ux-editor-v3/src/containers/DesignView/PageAccordion/NavigationMenu/NavigationMenu.tsx b/frontend/packages/ux-editor-v3/src/containers/DesignView/PageAccordion/NavigationMenu/NavigationMenu.tsx index 6d0993c50a7..40c23a7edaf 100644 --- a/frontend/packages/ux-editor-v3/src/containers/DesignView/PageAccordion/NavigationMenu/NavigationMenu.tsx +++ b/frontend/packages/ux-editor-v3/src/containers/DesignView/PageAccordion/NavigationMenu/NavigationMenu.tsx @@ -5,7 +5,7 @@ import { MenuElipsisVerticalIcon, ArrowUpIcon, ArrowDownIcon } from '@studio/ico import { useFormLayoutSettingsQuery } from '../../../../hooks/queries/useFormLayoutSettingsQuery'; import { useUpdateLayoutOrderMutation } from '../../../../hooks/mutations/useUpdateLayoutOrderMutation'; import { useUpdateLayoutNameMutation } from '../../../../hooks/mutations/useUpdateLayoutNameMutation'; -import { useStudioUrlParams } from 'app-shared/hooks/useStudioUrlParams'; +import { useStudioEnvironmentParams } from 'app-shared/hooks/useStudioEnvironmentParams'; import { useSelector } from 'react-redux'; import type { IAppState } from '../../../../types/global'; import { useSearchParams } from 'react-router-dom'; @@ -31,7 +31,7 @@ export type NavigationMenuProps = { export const NavigationMenu = ({ pageName, pageIsReceipt }: NavigationMenuProps): JSX.Element => { const { t } = useTranslation(); - const { org, app } = useStudioUrlParams(); + const { org, app } = useStudioEnvironmentParams(); const { selectedLayoutSet } = useAppContext(); const invalidLayouts: string[] = useSelector( diff --git a/frontend/packages/ux-editor-v3/src/containers/DesignView/PageAccordion/PageAccordion.tsx b/frontend/packages/ux-editor-v3/src/containers/DesignView/PageAccordion/PageAccordion.tsx index 4541f9909c0..c424751e483 100644 --- a/frontend/packages/ux-editor-v3/src/containers/DesignView/PageAccordion/PageAccordion.tsx +++ b/frontend/packages/ux-editor-v3/src/containers/DesignView/PageAccordion/PageAccordion.tsx @@ -8,7 +8,7 @@ import { pageAccordionContentId } from '@studio/testing/testids'; import { TrashIcon } from '@studio/icons'; import { useTranslation } from 'react-i18next'; import { useSearchParams } from 'react-router-dom'; -import { useStudioUrlParams } from 'app-shared/hooks/useStudioUrlParams'; +import { useStudioEnvironmentParams } from 'app-shared/hooks/useStudioEnvironmentParams'; import { useAppContext } from '../../../hooks/useAppContext'; import { firstAvailableLayout } from '../../../utils/formLayoutsUtils'; import { useFormLayoutSettingsQuery } from '../../../hooks/queries/useFormLayoutSettingsQuery'; @@ -44,7 +44,7 @@ export const PageAccordion = ({ pageIsReceipt, }: PageAccordionProps): ReactNode => { const { t } = useTranslation(); - const { org, app } = useStudioUrlParams(); + const { org, app } = useStudioEnvironmentParams(); const { selectedLayoutSet } = useAppContext(); const [searchParams, setSearchParams] = useSearchParams(); const selectedLayout = searchParams.get('layout'); diff --git a/frontend/packages/ux-editor-v3/src/containers/DesignView/PageAccordion/useDeleteLayout.ts b/frontend/packages/ux-editor-v3/src/containers/DesignView/PageAccordion/useDeleteLayout.ts index 2c16facd5ce..ed66a068251 100644 --- a/frontend/packages/ux-editor-v3/src/containers/DesignView/PageAccordion/useDeleteLayout.ts +++ b/frontend/packages/ux-editor-v3/src/containers/DesignView/PageAccordion/useDeleteLayout.ts @@ -1,9 +1,9 @@ import { useDeleteLayoutMutation } from '../../../hooks/mutations/useDeleteLayoutMutation'; -import { useStudioUrlParams } from 'app-shared/hooks/useStudioUrlParams'; +import { useStudioEnvironmentParams } from 'app-shared/hooks/useStudioEnvironmentParams'; import { useAppContext } from '../../../hooks/useAppContext'; export const useDeleteLayout = () => { - const { org, app } = useStudioUrlParams(); + const { org, app } = useStudioEnvironmentParams(); const { selectedLayoutSet } = useAppContext(); return useDeleteLayoutMutation(org, app, selectedLayoutSet); }; diff --git a/frontend/packages/ux-editor-v3/src/containers/FormDesigner.tsx b/frontend/packages/ux-editor-v3/src/containers/FormDesigner.tsx index 43735f2f388..1992ff48f50 100644 --- a/frontend/packages/ux-editor-v3/src/containers/FormDesigner.tsx +++ b/frontend/packages/ux-editor-v3/src/containers/FormDesigner.tsx @@ -14,7 +14,7 @@ import { StudioPageSpinner } from '@studio/components'; import { BASE_CONTAINER_ID } from 'app-shared/constants'; import { useRuleConfigQuery } from '../hooks/queries/useRuleConfigQuery'; import { useInstanceIdQuery } from 'app-shared/hooks/queries'; -import { useStudioUrlParams } from 'app-shared/hooks/useStudioUrlParams'; +import { useStudioEnvironmentParams } from 'app-shared/hooks/useStudioEnvironmentParams'; import type { HandleAdd, HandleMove } from 'app-shared/types/dndTypes'; import type { ComponentTypeV3 } from 'app-shared/types/ComponentTypeV3'; import { generateComponentId } from '../utils/generateId'; @@ -43,7 +43,7 @@ export const FormDesigner = ({ selectedLayoutSet, }: FormDesignerProps): JSX.Element => { const dispatch = useDispatch(); - const { org, app } = useStudioUrlParams(); + const { org, app } = useStudioEnvironmentParams(); const { data: instanceId } = useInstanceIdQuery(org, app); const { data: formLayouts, isError: layoutFetchedError } = useFormLayoutsQuery( org, diff --git a/frontend/packages/ux-editor-v3/src/containers/FormItemContext.tsx b/frontend/packages/ux-editor-v3/src/containers/FormItemContext.tsx index 0ed5e2eb583..fbad095d18c 100644 --- a/frontend/packages/ux-editor-v3/src/containers/FormItemContext.tsx +++ b/frontend/packages/ux-editor-v3/src/containers/FormItemContext.tsx @@ -16,7 +16,7 @@ import { useUpdateFormComponentMutation } from '../hooks/mutations/useUpdateForm import { selectedLayoutNameSelector } from '../selectors/formLayoutSelectors'; import { AUTOSAVE_DEBOUNCE_INTERVAL_MILLISECONDS } from 'app-shared/constants'; import { LayoutItemType } from '../types/global'; -import { useStudioUrlParams } from 'app-shared/hooks/useStudioUrlParams'; +import { useStudioEnvironmentParams } from 'app-shared/hooks/useStudioEnvironmentParams'; import { useAppContext } from '../hooks/useAppContext'; export type FormItemContext = { @@ -55,7 +55,7 @@ export const FormItemContextProvider = ({ children, }: FormItemContextProviderProps): JSX.Element => { const dispatch = useDispatch(); - const { org, app } = useStudioUrlParams(); + const { org, app } = useStudioEnvironmentParams(); const { selectedLayoutSet } = useAppContext(); const selectedLayoutName = useSelector(selectedLayoutNameSelector); const prevSelectedLayoutSetNameRef = useRef(selectedLayoutSet); diff --git a/frontend/packages/ux-editor-v3/src/hooks/useFormLayoutsSelector.ts b/frontend/packages/ux-editor-v3/src/hooks/useFormLayoutsSelector.ts index dfd6010adcb..514f5dbdc61 100644 --- a/frontend/packages/ux-editor-v3/src/hooks/useFormLayoutsSelector.ts +++ b/frontend/packages/ux-editor-v3/src/hooks/useFormLayoutsSelector.ts @@ -3,11 +3,11 @@ import { useSelector } from 'react-redux'; import type { IFormLayouts, IInternalLayout, IInternalLayoutWithName } from '../types/global'; import { selectedLayoutNameSelector } from '../selectors/formLayoutSelectors'; import { createEmptyLayout } from '../utils/formLayoutUtils'; -import { useStudioUrlParams } from 'app-shared/hooks/useStudioUrlParams'; +import { useStudioEnvironmentParams } from 'app-shared/hooks/useStudioEnvironmentParams'; import { useAppContext } from './useAppContext'; export const useFormLayouts = (): IFormLayouts => { - const { org, app } = useStudioUrlParams(); + const { org, app } = useStudioEnvironmentParams(); const { selectedLayoutSet } = useAppContext(); const formLayoutsQuery = useFormLayoutsQuery(org, app, selectedLayoutSet); const { data } = formLayoutsQuery; diff --git a/frontend/packages/ux-editor-v3/src/hooks/useTextResourcesSelector.ts b/frontend/packages/ux-editor-v3/src/hooks/useTextResourcesSelector.ts index fc2ceac88f7..bc901aa41a6 100644 --- a/frontend/packages/ux-editor-v3/src/hooks/useTextResourcesSelector.ts +++ b/frontend/packages/ux-editor-v3/src/hooks/useTextResourcesSelector.ts @@ -1,9 +1,9 @@ import type { TextResourcesSelector } from '../types/global'; import { useTextResourcesQuery } from 'app-shared/hooks/queries'; -import { useStudioUrlParams } from 'app-shared/hooks/useStudioUrlParams'; +import { useStudioEnvironmentParams } from 'app-shared/hooks/useStudioEnvironmentParams'; export const useTextResourcesSelector = (selector: TextResourcesSelector): T => { - const { org, app } = useStudioUrlParams(); + const { org, app } = useStudioEnvironmentParams(); const { data: textResources } = useTextResourcesQuery(org, app); return selector(textResources); }; diff --git a/frontend/packages/ux-editor-v3/src/hooks/useValidateComponent.ts b/frontend/packages/ux-editor-v3/src/hooks/useValidateComponent.ts index 93bf1458ad3..627551f3c3e 100644 --- a/frontend/packages/ux-editor-v3/src/hooks/useValidateComponent.ts +++ b/frontend/packages/ux-editor-v3/src/hooks/useValidateComponent.ts @@ -6,7 +6,7 @@ import type { FormRadioButtonsComponent, } from '../types/FormComponent'; import { useOptionListIdsQuery } from './queries/useOptionListIdsQuery'; -import { useStudioUrlParams } from 'app-shared/hooks/useStudioUrlParams'; +import { useStudioEnvironmentParams } from 'app-shared/hooks/useStudioEnvironmentParams'; export enum ErrorCode { NoOptions = 'NoOptions', @@ -48,7 +48,7 @@ const validateOptionGroup = ( }; export const useValidateComponent = (component: FormComponent): ComponentValidationResult => { - const { org, app } = useStudioUrlParams(); + const { org, app } = useStudioEnvironmentParams(); const { data: optionListIds } = useOptionListIdsQuery(org, app); switch (component.type) { diff --git a/frontend/packages/ux-editor/src/App.tsx b/frontend/packages/ux-editor/src/App.tsx index efc9a08b547..0d95c703cb7 100644 --- a/frontend/packages/ux-editor/src/App.tsx +++ b/frontend/packages/ux-editor/src/App.tsx @@ -6,7 +6,7 @@ import { ErrorPage } from './components/ErrorPage'; import { useDataModelMetadataQuery } from './hooks/queries/useDataModelMetadataQuery'; import { useWidgetsQuery } from './hooks/queries/useWidgetsQuery'; import { useTextResourcesQuery } from 'app-shared/hooks/queries/useTextResourcesQuery'; -import { useStudioUrlParams } from 'app-shared/hooks/useStudioUrlParams'; +import { useStudioEnvironmentParams } from 'app-shared/hooks/useStudioEnvironmentParams'; import { FormItemContextProvider } from './containers/FormItemContext'; /** @@ -17,7 +17,7 @@ import { FormItemContextProvider } from './containers/FormItemContext'; export function App() { const t = useText(); - const { org, app } = useStudioUrlParams(); + const { org, app } = useStudioEnvironmentParams(); const { selectedFormLayoutSetName } = useAppContext(); const { isSuccess: areWidgetsFetched, isError: widgetFetchedError } = useWidgetsQuery(org, app); const { isSuccess: isDataModelFetched, isError: dataModelFetchedError } = diff --git a/frontend/packages/ux-editor/src/components/Elements/Elements.tsx b/frontend/packages/ux-editor/src/components/Elements/Elements.tsx index 62962b36d94..640758e1714 100644 --- a/frontend/packages/ux-editor/src/components/Elements/Elements.tsx +++ b/frontend/packages/ux-editor/src/components/Elements/Elements.tsx @@ -5,13 +5,13 @@ import { Heading, Paragraph } from '@digdir/design-system-react'; import { useText, useAppContext } from '../../hooks'; import { LayoutSetsContainer } from './LayoutSetsContainer'; -import { useStudioUrlParams } from 'app-shared/hooks/useStudioUrlParams'; +import { useStudioEnvironmentParams } from 'app-shared/hooks/useStudioEnvironmentParams'; import classes from './Elements.module.css'; import { useCustomReceiptLayoutSetName } from 'app-shared/hooks/useCustomReceiptLayoutSetName'; export const Elements = () => { - const { org, app } = useStudioUrlParams(); + const { org, app } = useStudioEnvironmentParams(); const { selectedFormLayoutSetName, selectedFormLayoutName } = useAppContext(); const existingCustomReceiptName: string | undefined = useCustomReceiptLayoutSetName(org, app); diff --git a/frontend/packages/ux-editor/src/components/Elements/LayoutSetsContainer.tsx b/frontend/packages/ux-editor/src/components/Elements/LayoutSetsContainer.tsx index 4cc9c97b2d7..3fb79388dba 100644 --- a/frontend/packages/ux-editor/src/components/Elements/LayoutSetsContainer.tsx +++ b/frontend/packages/ux-editor/src/components/Elements/LayoutSetsContainer.tsx @@ -1,12 +1,12 @@ import React from 'react'; import { useLayoutSetsQuery } from 'app-shared/hooks/queries/useLayoutSetsQuery'; import { NativeSelect } from '@digdir/design-system-react'; -import { useStudioUrlParams } from 'app-shared/hooks/useStudioUrlParams'; +import { useStudioEnvironmentParams } from 'app-shared/hooks/useStudioEnvironmentParams'; import { useText, useAppContext } from '../../hooks'; import classes from './LayoutSetsContainer.module.css'; export function LayoutSetsContainer() { - const { org, app } = useStudioUrlParams(); + const { org, app } = useStudioEnvironmentParams(); const layoutSetsQuery = useLayoutSetsQuery(org, app); const layoutSetNames = layoutSetsQuery.data?.sets?.map((set) => set.id); const t = useText(); diff --git a/frontend/packages/ux-editor/src/components/FormComponent/FormComponent.tsx b/frontend/packages/ux-editor/src/components/FormComponent/FormComponent.tsx index f52d3f25270..42581e5bf90 100644 --- a/frontend/packages/ux-editor/src/components/FormComponent/FormComponent.tsx +++ b/frontend/packages/ux-editor/src/components/FormComponent/FormComponent.tsx @@ -16,7 +16,7 @@ import { useDeleteFormComponentMutation } from '../../hooks/mutations/useDeleteF import { useTextResourcesSelector, useAppContext } from '../../hooks'; import { useTranslation } from 'react-i18next'; import { AltinnConfirmDialog } from 'app-shared/components'; -import { useStudioUrlParams } from 'app-shared/hooks/useStudioUrlParams'; +import { useStudioEnvironmentParams } from 'app-shared/hooks/useStudioEnvironmentParams'; export interface IFormComponentProps { component: IFormComponent; @@ -39,7 +39,7 @@ export const FormComponent = memo(function FormComponent({ isEditMode, }: IFormComponentProps) { const { t } = useTranslation(); - const { org, app } = useStudioUrlParams(); + const { org, app } = useStudioEnvironmentParams(); const textResources: ITextResource[] = useTextResourcesSelector( textResourcesByLanguageSelector(DEFAULT_LANGUAGE), diff --git a/frontend/packages/ux-editor/src/components/Preview/Preview.tsx b/frontend/packages/ux-editor/src/components/Preview/Preview.tsx index dd336be708e..cf4df33dcb7 100644 --- a/frontend/packages/ux-editor/src/components/Preview/Preview.tsx +++ b/frontend/packages/ux-editor/src/components/Preview/Preview.tsx @@ -1,6 +1,6 @@ import React, { useEffect, useState } from 'react'; import classes from './Preview.module.css'; -import { useStudioUrlParams } from 'app-shared/hooks/useStudioUrlParams'; +import { useStudioEnvironmentParams } from 'app-shared/hooks/useStudioEnvironmentParams'; import cn from 'classnames'; import { useTranslation } from 'react-i18next'; import { useAppContext, useSelectedTaskId } from '../../hooks'; @@ -58,7 +58,7 @@ const NoSelectedPageMessage = () => { // The actual preview frame that displays the selected page const PreviewFrame = () => { - const { org, app } = useStudioUrlParams(); + const { org, app } = useStudioEnvironmentParams(); const [viewportToSimulate, setViewportToSimulate] = useState('desktop'); const { previewIframeRef, selectedFormLayoutSetName, selectedFormLayoutName } = useAppContext(); const taskId = useSelectedTaskId(selectedFormLayoutSetName); diff --git a/frontend/packages/ux-editor/src/components/Properties/OldDynamicsInfo.tsx b/frontend/packages/ux-editor/src/components/Properties/OldDynamicsInfo.tsx index 91385ac2201..fa8538b1318 100644 --- a/frontend/packages/ux-editor/src/components/Properties/OldDynamicsInfo.tsx +++ b/frontend/packages/ux-editor/src/components/Properties/OldDynamicsInfo.tsx @@ -3,14 +3,14 @@ import classes from './OldDynamicsInfo.module.css'; import { ExternalLinkIcon } from '@studio/icons'; import { useTranslation } from 'react-i18next'; import { giteaEditLink, altinnDocsUrl } from 'app-shared/ext-urls'; -import { useStudioUrlParams } from 'app-shared/hooks/useStudioUrlParams'; +import { useStudioEnvironmentParams } from 'app-shared/hooks/useStudioEnvironmentParams'; import { useAppContext } from '../../hooks'; import { Link } from '@digdir/design-system-react'; export const OldDynamicsInfo = () => { const { t } = useTranslation(); const { selectedFormLayoutSetName } = useAppContext(); - const { app, org } = useStudioUrlParams(); + const { app, org } = useStudioEnvironmentParams(); const dynamicLocation = selectedFormLayoutSetName ? `App/ui/${selectedFormLayoutSetName}/RuleHandler.js` : 'App/ui/RuleHandler.js'; diff --git a/frontend/packages/ux-editor/src/components/Properties/PageConfigPanel/EditPageId.tsx b/frontend/packages/ux-editor/src/components/Properties/PageConfigPanel/EditPageId.tsx index 03d9e013821..af95de0c609 100644 --- a/frontend/packages/ux-editor/src/components/Properties/PageConfigPanel/EditPageId.tsx +++ b/frontend/packages/ux-editor/src/components/Properties/PageConfigPanel/EditPageId.tsx @@ -5,7 +5,7 @@ import { getPageNameErrorKey } from '../../../utils/designViewUtils'; import { useUpdateLayoutNameMutation } from '../../../hooks/mutations/useUpdateLayoutNameMutation'; import { StudioToggleableTextfield } from '@studio/components'; import { useTextIdMutation } from 'app-development/hooks/mutations'; -import { useStudioUrlParams } from 'app-shared/hooks/useStudioUrlParams'; +import { useStudioEnvironmentParams } from 'app-shared/hooks/useStudioEnvironmentParams'; import { useText, useAppContext } from '../../../hooks'; import { useFormLayoutSettingsQuery } from '../../../hooks/queries/useFormLayoutSettingsQuery'; import { Trans } from 'react-i18next'; @@ -14,7 +14,7 @@ export interface EditPageIdProps { layoutName: string; } export const EditPageId = ({ layoutName }: EditPageIdProps) => { - const { app, org } = useStudioUrlParams(); + const { app, org } = useStudioEnvironmentParams(); const { selectedFormLayoutSetName, refetchLayouts } = useAppContext(); const { mutate: mutateTextId } = useTextIdMutation(org, app); const { mutate: updateLayoutName } = useUpdateLayoutNameMutation( diff --git a/frontend/packages/ux-editor/src/components/Properties/PageConfigPanel/HiddenExpressionOnLayout.tsx b/frontend/packages/ux-editor/src/components/Properties/PageConfigPanel/HiddenExpressionOnLayout.tsx index 43b37c919ab..37a4bc41ac8 100644 --- a/frontend/packages/ux-editor/src/components/Properties/PageConfigPanel/HiddenExpressionOnLayout.tsx +++ b/frontend/packages/ux-editor/src/components/Properties/PageConfigPanel/HiddenExpressionOnLayout.tsx @@ -4,14 +4,14 @@ import type { Expression } from '@studio/components'; import type { IInternalLayout } from '../../../types/global'; import { ObjectUtils } from '@studio/pure-functions'; import { useFormLayoutMutation } from '../../../hooks/mutations/useFormLayoutMutation'; -import { useStudioUrlParams } from 'app-shared/hooks/useStudioUrlParams'; +import { useStudioEnvironmentParams } from 'app-shared/hooks/useStudioEnvironmentParams'; import { useSelectedFormLayoutWithName, useAppContext } from '../../../hooks'; import { Trans } from 'react-i18next'; import { AUTOSAVE_DEBOUNCE_INTERVAL_MILLISECONDS } from 'app-shared/constants'; import { useDebounce } from 'app-shared/hooks/useDebounce'; export const HiddenExpressionOnLayout = () => { - const { app, org } = useStudioUrlParams(); + const { app, org } = useStudioEnvironmentParams(); const { layout, layoutName } = useSelectedFormLayoutWithName(); const { selectedFormLayoutSetName, refetchLayouts } = useAppContext(); const { mutate: saveLayout } = useFormLayoutMutation( diff --git a/frontend/packages/ux-editor/src/components/Properties/PageConfigPanel/PageConfigWarning.tsx b/frontend/packages/ux-editor/src/components/Properties/PageConfigPanel/PageConfigWarning.tsx index 915a9e0ec98..91a69ac5f6a 100644 --- a/frontend/packages/ux-editor/src/components/Properties/PageConfigPanel/PageConfigWarning.tsx +++ b/frontend/packages/ux-editor/src/components/Properties/PageConfigPanel/PageConfigWarning.tsx @@ -1,7 +1,7 @@ import React from 'react'; import { List, Link, Heading } from '@digdir/design-system-react'; import { repositoryLayoutPath } from 'app-shared/api/paths'; -import { useStudioUrlParams } from 'app-shared/hooks/useStudioUrlParams'; +import { useStudioEnvironmentParams } from 'app-shared/hooks/useStudioEnvironmentParams'; import { getDuplicatedIds } from '../../../utils/formLayoutUtils'; import type { IInternalLayout } from '../../../types/global'; import { useTranslation } from 'react-i18next'; @@ -15,7 +15,7 @@ type PageConfigWarningProps = { }; export const PageConfigWarning = ({ layout, selectedFormLayoutName }: PageConfigWarningProps) => { - const { org, app } = useStudioUrlParams(); + const { org, app } = useStudioEnvironmentParams(); const { t } = useTranslation(); const duplicatedIds = getDuplicatedIds(layout) .map((id) => `<${id}>`) diff --git a/frontend/packages/ux-editor/src/components/TextResource/TextResourceEditor/TextResourceValueEditor/TextResourceValueEditor.tsx b/frontend/packages/ux-editor/src/components/TextResource/TextResourceEditor/TextResourceValueEditor/TextResourceValueEditor.tsx index df14947997c..1e12c6f5357 100644 --- a/frontend/packages/ux-editor/src/components/TextResource/TextResourceEditor/TextResourceValueEditor/TextResourceValueEditor.tsx +++ b/frontend/packages/ux-editor/src/components/TextResource/TextResourceEditor/TextResourceValueEditor/TextResourceValueEditor.tsx @@ -1,7 +1,7 @@ import type { ChangeEvent } from 'react'; import React, { useCallback, useEffect, useState } from 'react'; import { StudioCodeFragment, StudioTextarea } from '@studio/components'; -import { useStudioUrlParams } from 'app-shared/hooks/useStudioUrlParams'; +import { useStudioEnvironmentParams } from 'app-shared/hooks/useStudioEnvironmentParams'; import { useTextResourcesQuery } from 'app-shared/hooks/queries'; import { DEFAULT_LANGUAGE } from 'app-shared/constants'; import type { ITextResources } from 'app-shared/types/global'; @@ -22,7 +22,7 @@ const getTextResourceValue = (textResources: ITextResources, id: string) => findTextResource(textResources, id)?.value || ''; export const TextResourceValueEditor = ({ textResourceId }: TextResourceValueEditorProps) => { - const { org, app } = useStudioUrlParams(); + const { org, app } = useStudioEnvironmentParams(); const { data: textResources } = useTextResourcesQuery(org, app); const { mutate } = useUpsertTextResourceMutation(org, app); const value = getTextResourceValue(textResources, textResourceId); diff --git a/frontend/packages/ux-editor/src/components/config/ExpressionContent/ExpressionContent.tsx b/frontend/packages/ux-editor/src/components/config/ExpressionContent/ExpressionContent.tsx index c490a515cb9..c5c1e1c8949 100644 --- a/frontend/packages/ux-editor/src/components/config/ExpressionContent/ExpressionContent.tsx +++ b/frontend/packages/ux-editor/src/components/config/ExpressionContent/ExpressionContent.tsx @@ -4,7 +4,7 @@ import { getComponentIds, getDataModelElementNames } from '../../../utils/expres import type { Expression, DataLookupOptions } from '@studio/components'; import { DataLookupFuncName, StudioDeleteButton } from '@studio/components'; import { useFormLayoutsQuery } from '../../../hooks/queries/useFormLayoutsQuery'; -import { useStudioUrlParams } from 'app-shared/hooks/useStudioUrlParams'; +import { useStudioEnvironmentParams } from 'app-shared/hooks/useStudioEnvironmentParams'; import { useDataModelMetadataQuery } from '../../../hooks/queries/useDataModelMetadataQuery'; import { Paragraph } from '@digdir/design-system-react'; import classes from './ExpressionContent.module.css'; @@ -25,7 +25,7 @@ export const ExpressionContent = ({ heading, }: ExpressionContentProps) => { const t = useText(); - const { org, app } = useStudioUrlParams(); + const { org, app } = useStudioEnvironmentParams(); const { selectedFormLayoutSetName } = useAppContext(); const { data: formLayoutsData } = useFormLayoutsQuery(org, app, selectedFormLayoutSetName); const { data: dataModelMetadata } = useDataModelMetadataQuery( diff --git a/frontend/packages/ux-editor/src/components/config/SelectDataModelComponent.tsx b/frontend/packages/ux-editor/src/components/config/SelectDataModelComponent.tsx index ae6da8afa74..da7373e6c78 100644 --- a/frontend/packages/ux-editor/src/components/config/SelectDataModelComponent.tsx +++ b/frontend/packages/ux-editor/src/components/config/SelectDataModelComponent.tsx @@ -3,7 +3,7 @@ import { LegacySelect } from '@digdir/design-system-react'; import { useDataModelMetadataQuery } from '../../hooks/queries/useDataModelMetadataQuery'; import { FormField } from '../FormField'; import type { Option } from '@altinn/text-editor/types'; -import { useStudioUrlParams } from 'app-shared/hooks/useStudioUrlParams'; +import { useStudioEnvironmentParams } from 'app-shared/hooks/useStudioEnvironmentParams'; import type { DataModelFieldElement } from 'app-shared/types/DataModelFieldElement'; import { useAppContext } from '../../hooks'; @@ -31,7 +31,7 @@ export const SelectDataModelComponent = ({ helpText, propertyPath, }: ISelectDataModelProps) => { - const { org, app } = useStudioUrlParams(); + const { org, app } = useStudioEnvironmentParams(); const { selectedFormLayoutSetName } = useAppContext(); const { data } = useDataModelMetadataQuery(org, app, selectedFormLayoutSetName, undefined); const [dataModelElementNames, setDataModelElementNames] = React.useState([]); diff --git a/frontend/packages/ux-editor/src/components/config/componentSpecificContent/AttachmentList/AttachmentListComponent.tsx b/frontend/packages/ux-editor/src/components/config/componentSpecificContent/AttachmentList/AttachmentListComponent.tsx index b4bef12a4c1..ea7cd67e9e1 100644 --- a/frontend/packages/ux-editor/src/components/config/componentSpecificContent/AttachmentList/AttachmentListComponent.tsx +++ b/frontend/packages/ux-editor/src/components/config/componentSpecificContent/AttachmentList/AttachmentListComponent.tsx @@ -1,7 +1,7 @@ import React from 'react'; import type { IGenericEditComponent } from '../../componentConfig'; import { useAppMetadataQuery } from 'app-development/hooks/queries'; -import { useStudioUrlParams } from 'app-shared/hooks/useStudioUrlParams'; +import { useStudioEnvironmentParams } from 'app-shared/hooks/useStudioEnvironmentParams'; import { useLayoutSetsQuery } from 'app-shared/hooks/queries/useLayoutSetsQuery'; import { useAppContext } from '../../../../hooks/useAppContext'; import type { ComponentType } from 'app-shared/types/ComponentType'; @@ -20,7 +20,7 @@ export const AttachmentListComponent = ({ handleComponentChange, }: IGenericEditComponent) => { const { t } = useTranslation(); - const { org, app } = useStudioUrlParams(); + const { org, app } = useStudioEnvironmentParams(); const { data: layoutSets } = useLayoutSetsQuery(org, app); const { data: appMetadata, isPending: appMetadataPending } = useAppMetadataQuery(org, app); const { selectedFormLayoutSetName } = useAppContext(); diff --git a/frontend/packages/ux-editor/src/components/config/componentSpecificContent/RepeatingGroup/RepeatingGroupComponent.tsx b/frontend/packages/ux-editor/src/components/config/componentSpecificContent/RepeatingGroup/RepeatingGroupComponent.tsx index f00529834aa..8d5b0d829fb 100644 --- a/frontend/packages/ux-editor/src/components/config/componentSpecificContent/RepeatingGroup/RepeatingGroupComponent.tsx +++ b/frontend/packages/ux-editor/src/components/config/componentSpecificContent/RepeatingGroup/RepeatingGroupComponent.tsx @@ -9,7 +9,7 @@ import { useTextResourcesSelector, useAppContext, } from '../../../../hooks'; -import { useStudioUrlParams } from 'app-shared/hooks/useStudioUrlParams'; +import { useStudioEnvironmentParams } from 'app-shared/hooks/useStudioEnvironmentParams'; import { useFormLayoutsQuery } from '../../../../hooks/queries/useFormLayoutsQuery'; import type { ITextResource } from 'app-shared/types/global'; import { textResourcesByLanguageSelector } from '../../../../selectors/textResourceSelectors'; @@ -23,7 +23,7 @@ export const RepeatingGroupComponent = ({ }: IEditFormComponentProps) => { const t = useText(); - const { org, app } = useStudioUrlParams(); + const { org, app } = useStudioEnvironmentParams(); const { selectedFormLayoutSetName, selectedFormLayoutName } = useAppContext(); const { data: formLayouts } = useFormLayoutsQuery(org, app, selectedFormLayoutSetName); diff --git a/frontend/packages/ux-editor/src/components/config/editModal/EditCodeList/EditCodeList.tsx b/frontend/packages/ux-editor/src/components/config/editModal/EditCodeList/EditCodeList.tsx index c357134f39d..b653e6d6c1b 100644 --- a/frontend/packages/ux-editor/src/components/config/editModal/EditCodeList/EditCodeList.tsx +++ b/frontend/packages/ux-editor/src/components/config/editModal/EditCodeList/EditCodeList.tsx @@ -7,7 +7,7 @@ import { StudioButton, StudioSpinner } from '@studio/components'; import { altinnDocsUrl } from 'app-shared/ext-urls'; import { FormField } from '../../../FormField'; -import { useStudioUrlParams } from 'app-shared/hooks/useStudioUrlParams'; +import { useStudioEnvironmentParams } from 'app-shared/hooks/useStudioEnvironmentParams'; import classes from './EditCodeList.module.css'; import type { ComponentType } from 'app-shared/types/ComponentType'; @@ -15,7 +15,7 @@ export function EditCodeList< T extends ComponentType.Checkboxes | ComponentType.RadioButtons | ComponentType.Dropdown, >({ component, handleComponentChange }: IGenericEditComponent) { const { t } = useTranslation(); - const { org, app } = useStudioUrlParams(); + const { org, app } = useStudioEnvironmentParams(); const { data: optionListIds, isPending, isError, error } = useOptionListIdsQuery(org, app); const [useCustomCodeList, setUseCustomCodeList] = useState(optionListIds?.length === 0); diff --git a/frontend/packages/ux-editor/src/components/config/editModal/EditDataModelBindings/EditDataModelBindings.tsx b/frontend/packages/ux-editor/src/components/config/editModal/EditDataModelBindings/EditDataModelBindings.tsx index 96bfb6fec4b..7866eaf7162 100644 --- a/frontend/packages/ux-editor/src/components/config/editModal/EditDataModelBindings/EditDataModelBindings.tsx +++ b/frontend/packages/ux-editor/src/components/config/editModal/EditDataModelBindings/EditDataModelBindings.tsx @@ -7,7 +7,7 @@ import { import { ComponentType } from 'app-shared/types/ComponentType'; import React, { useEffect, useState } from 'react'; import { useDataModelMetadataQuery } from '../../../../hooks/queries/useDataModelMetadataQuery'; -import { useStudioUrlParams } from 'app-shared/hooks/useStudioUrlParams'; +import { useStudioEnvironmentParams } from 'app-shared/hooks/useStudioEnvironmentParams'; import classes from './EditDataModelBindings.module.css'; import { useTranslation } from 'react-i18next'; import { UndefinedBinding } from './UndefinedBinding'; @@ -33,7 +33,7 @@ export const EditDataModelBindings = ({ renderOptions, helpText, }: EditDataModelBindingsProps) => { - const { org, app } = useStudioUrlParams(); + const { org, app } = useStudioEnvironmentParams(); const { selectedFormLayoutSetName } = useAppContext(); const { data } = useDataModelMetadataQuery(org, app, selectedFormLayoutSetName, undefined); const { t } = useTranslation(); diff --git a/frontend/packages/ux-editor/src/components/toolbar/ConditionalRenderingModal.tsx b/frontend/packages/ux-editor/src/components/toolbar/ConditionalRenderingModal.tsx index 2377d57b785..b85eb35a2de 100644 --- a/frontend/packages/ux-editor/src/components/toolbar/ConditionalRenderingModal.tsx +++ b/frontend/packages/ux-editor/src/components/toolbar/ConditionalRenderingModal.tsx @@ -18,7 +18,7 @@ import { addConditionalRenderingConnection, deleteConditionalRenderingConnection, } from '../../utils/ruleConfigUtils'; -import { useStudioUrlParams } from 'app-shared/hooks/useStudioUrlParams'; +import { useStudioEnvironmentParams } from 'app-shared/hooks/useStudioEnvironmentParams'; import { useFormLayoutsQuery } from '../../hooks/queries/useFormLayoutsQuery'; import { useAppContext } from '../../hooks'; @@ -29,7 +29,7 @@ export interface IConditionalRenderingModalProps { } export function ConditionalRenderingModal(props: IConditionalRenderingModalProps) { - const { org, app } = useStudioUrlParams(); + const { org, app } = useStudioEnvironmentParams(); const [selectedConnectionId, setSelectedConnectionId] = React.useState(null); const { selectedFormLayoutSetName } = useAppContext(); const { data: ruleModel } = useRuleModelQuery(org, app, selectedFormLayoutSetName); diff --git a/frontend/packages/ux-editor/src/components/toolbar/RuleModal.tsx b/frontend/packages/ux-editor/src/components/toolbar/RuleModal.tsx index 39957f51491..d89de1e1ad1 100644 --- a/frontend/packages/ux-editor/src/components/toolbar/RuleModal.tsx +++ b/frontend/packages/ux-editor/src/components/toolbar/RuleModal.tsx @@ -9,7 +9,7 @@ import type { RuleConnection } from 'app-shared/types/RuleConfig'; import { useRuleConfigQuery } from '../../hooks/queries/useRuleConfigQuery'; import { useRuleConfigMutation } from '../../hooks/mutations/useRuleConfigMutation'; import { addRuleConnection, deleteRuleConnection } from '../../utils/ruleConfigUtils'; -import { useStudioUrlParams } from 'app-shared/hooks/useStudioUrlParams'; +import { useStudioEnvironmentParams } from 'app-shared/hooks/useStudioEnvironmentParams'; import { useAppContext } from '../../hooks'; export interface IRuleModalProps { @@ -19,7 +19,7 @@ export interface IRuleModalProps { } export function RuleModal(props: IRuleModalProps) { - const { org, app } = useStudioUrlParams(); + const { org, app } = useStudioEnvironmentParams(); const [selectedConnectionId, setSelectedConnectionId] = React.useState(null); const { selectedFormLayoutSetName } = useAppContext(); const { data: ruleConfig } = useRuleConfigQuery(org, app, selectedFormLayoutSetName); diff --git a/frontend/packages/ux-editor/src/containers/DesignView/DesignView.tsx b/frontend/packages/ux-editor/src/containers/DesignView/DesignView.tsx index 0ed5915a0d9..94927789fdf 100644 --- a/frontend/packages/ux-editor/src/containers/DesignView/DesignView.tsx +++ b/frontend/packages/ux-editor/src/containers/DesignView/DesignView.tsx @@ -2,7 +2,7 @@ import type { ReactNode } from 'react'; import React from 'react'; import classes from './DesignView.module.css'; import { useTranslation } from 'react-i18next'; -import { useStudioUrlParams } from 'app-shared/hooks/useStudioUrlParams'; +import { useStudioEnvironmentParams } from 'app-shared/hooks/useStudioEnvironmentParams'; import { Accordion } from '@digdir/design-system-react'; import type { IFormLayouts } from '../../types/global'; import type { FormLayoutPage } from '../../types/FormLayoutPage'; @@ -33,7 +33,7 @@ const mapFormLayoutsToFormLayoutPages = (formLayouts: IFormLayouts): FormLayoutP * @returns {ReactNode} - The rendered component */ export const DesignView = (): ReactNode => { - const { org, app } = useStudioUrlParams(); + const { org, app } = useStudioEnvironmentParams(); const { selectedFormLayoutSetName, selectedFormLayoutName, diff --git a/frontend/packages/ux-editor/src/containers/DesignView/FormTree/FormItem/FormItemTitle/useDeleteItem.ts b/frontend/packages/ux-editor/src/containers/DesignView/FormTree/FormItem/FormItemTitle/useDeleteItem.ts index c94715c8c2c..8d8b519e00a 100644 --- a/frontend/packages/ux-editor/src/containers/DesignView/FormTree/FormItem/FormItemTitle/useDeleteItem.ts +++ b/frontend/packages/ux-editor/src/containers/DesignView/FormTree/FormItem/FormItemTitle/useDeleteItem.ts @@ -1,4 +1,4 @@ -import { useStudioUrlParams } from 'app-shared/hooks/useStudioUrlParams'; +import { useStudioEnvironmentParams } from 'app-shared/hooks/useStudioEnvironmentParams'; import { useDeleteFormContainerMutation } from '../../../../../hooks/mutations/useDeleteFormContainerMutation'; import { useDeleteFormComponentMutation } from '../../../../../hooks/mutations/useDeleteFormComponentMutation'; import { useMemo } from 'react'; @@ -8,7 +8,7 @@ import type { FormContainer } from '../../../../../types/FormContainer'; import { useAppContext } from '../../../../../hooks'; export const useDeleteItem = (formItem: FormComponent | FormContainer) => { - const { org, app } = useStudioUrlParams(); + const { org, app } = useStudioEnvironmentParams(); const { selectedFormLayoutSetName } = useAppContext(); const { mutate: deleteContainer } = useDeleteFormContainerMutation( org, diff --git a/frontend/packages/ux-editor/src/containers/DesignView/FormTree/UnknownReferencedItem/useDeleteUnknownComponentReference.ts b/frontend/packages/ux-editor/src/containers/DesignView/FormTree/UnknownReferencedItem/useDeleteUnknownComponentReference.ts index 1f58ade5254..0ff61f4f7bb 100644 --- a/frontend/packages/ux-editor/src/containers/DesignView/FormTree/UnknownReferencedItem/useDeleteUnknownComponentReference.ts +++ b/frontend/packages/ux-editor/src/containers/DesignView/FormTree/UnknownReferencedItem/useDeleteUnknownComponentReference.ts @@ -1,11 +1,11 @@ -import { useStudioUrlParams } from 'app-shared/hooks/useStudioUrlParams'; +import { useStudioEnvironmentParams } from 'app-shared/hooks/useStudioEnvironmentParams'; import { useSelectedFormLayoutWithName, useAppContext } from '../../../../hooks'; import { useFormLayoutMutation } from '../../../../hooks/mutations/useFormLayoutMutation'; import { removeComponent } from '../../../../utils/formLayoutUtils'; import type { IInternalLayout } from '../../../../types/global'; export const useDeleteUnknownComponentReference = () => { - const { org, app } = useStudioUrlParams(); + const { org, app } = useStudioEnvironmentParams(); const { selectedFormLayoutSetName, refetchLayouts } = useAppContext(); const { layoutName } = useSelectedFormLayoutWithName(); const { mutateAsync: updateFormLayoutMutation } = useFormLayoutMutation( diff --git a/frontend/packages/ux-editor/src/containers/DesignView/PageAccordion/NavigationMenu/NavigationMenu.tsx b/frontend/packages/ux-editor/src/containers/DesignView/PageAccordion/NavigationMenu/NavigationMenu.tsx index 92331301952..8ec2cd66083 100644 --- a/frontend/packages/ux-editor/src/containers/DesignView/PageAccordion/NavigationMenu/NavigationMenu.tsx +++ b/frontend/packages/ux-editor/src/containers/DesignView/PageAccordion/NavigationMenu/NavigationMenu.tsx @@ -4,7 +4,7 @@ import { DropdownMenu } from '@digdir/design-system-react'; import { MenuElipsisVerticalIcon, ArrowUpIcon, ArrowDownIcon } from '@studio/icons'; import { useFormLayoutSettingsQuery } from '../../../../hooks/queries/useFormLayoutSettingsQuery'; import { useUpdateLayoutOrderMutation } from '../../../../hooks/mutations/useUpdateLayoutOrderMutation'; -import { useStudioUrlParams } from 'app-shared/hooks/useStudioUrlParams'; +import { useStudioEnvironmentParams } from 'app-shared/hooks/useStudioEnvironmentParams'; import { useAppContext } from '../../../../hooks'; import { StudioButton } from '@studio/components'; @@ -25,7 +25,7 @@ export type NavigationMenuProps = { export const NavigationMenu = ({ pageName, pageIsReceipt }: NavigationMenuProps): JSX.Element => { const { t } = useTranslation(); - const { org, app } = useStudioUrlParams(); + const { org, app } = useStudioEnvironmentParams(); const { selectedFormLayoutSetName } = useAppContext(); diff --git a/frontend/packages/ux-editor/src/containers/DesignView/PageAccordion/PageAccordion.tsx b/frontend/packages/ux-editor/src/containers/DesignView/PageAccordion/PageAccordion.tsx index 839591d5da6..699db73c1c4 100644 --- a/frontend/packages/ux-editor/src/containers/DesignView/PageAccordion/PageAccordion.tsx +++ b/frontend/packages/ux-editor/src/containers/DesignView/PageAccordion/PageAccordion.tsx @@ -7,7 +7,7 @@ import { NavigationMenu } from './NavigationMenu'; import { pageAccordionContentId } from '@studio/testing/testids'; import { TrashIcon } from '@studio/icons'; import { useTranslation } from 'react-i18next'; -import { useStudioUrlParams } from 'app-shared/hooks/useStudioUrlParams'; +import { useStudioEnvironmentParams } from 'app-shared/hooks/useStudioEnvironmentParams'; import { useAppContext } from '../../../hooks'; import { StudioButton } from '@studio/components'; import { useDeleteLayoutMutation } from '../../../hooks/mutations/useDeleteLayoutMutation'; @@ -43,7 +43,7 @@ export const PageAccordion = ({ isValid, }: PageAccordionProps): ReactNode => { const { t } = useTranslation(); - const { org, app } = useStudioUrlParams(); + const { org, app } = useStudioEnvironmentParams(); const { selectedFormLayoutSetName, refetchLayouts } = useAppContext(); const { mutate: deleteLayout, isPending } = useDeleteLayoutMutation( diff --git a/frontend/packages/ux-editor/src/containers/FormDesigner.tsx b/frontend/packages/ux-editor/src/containers/FormDesigner.tsx index 84e95515b85..ca8e4a889f3 100644 --- a/frontend/packages/ux-editor/src/containers/FormDesigner.tsx +++ b/frontend/packages/ux-editor/src/containers/FormDesigner.tsx @@ -13,7 +13,7 @@ import { StudioPageSpinner } from '@studio/components'; import { BASE_CONTAINER_ID } from 'app-shared/constants'; import { useRuleConfigQuery } from '../hooks/queries/useRuleConfigQuery'; import { useInstanceIdQuery } from 'app-shared/hooks/queries'; -import { useStudioUrlParams } from 'app-shared/hooks/useStudioUrlParams'; +import { useStudioEnvironmentParams } from 'app-shared/hooks/useStudioEnvironmentParams'; import type { HandleAdd, HandleMove } from 'app-shared/types/dndTypes'; import type { ComponentType } from 'app-shared/types/ComponentType'; import { generateComponentId } from '../utils/generateId'; @@ -30,7 +30,7 @@ import { Preview } from '../components/Preview'; import { DragAndDropTree } from 'app-shared/components/DragAndDropTree'; export const FormDesigner = (): JSX.Element => { - const { org, app } = useStudioUrlParams(); + const { org, app } = useStudioEnvironmentParams(); const { data: instanceId } = useInstanceIdQuery(org, app); const { selectedFormLayoutSetName, selectedFormLayoutName, refetchLayouts } = useAppContext(); const { data: formLayouts, isError: layoutFetchedError } = useFormLayoutsQuery( diff --git a/frontend/packages/ux-editor/src/containers/FormItemContext.tsx b/frontend/packages/ux-editor/src/containers/FormItemContext.tsx index 8a9901cba63..40e753ef726 100644 --- a/frontend/packages/ux-editor/src/containers/FormItemContext.tsx +++ b/frontend/packages/ux-editor/src/containers/FormItemContext.tsx @@ -15,7 +15,7 @@ import type { UpdateFormComponentMutationArgs } from '../hooks/mutations/useUpda import { useUpdateFormComponentMutation } from '../hooks/mutations/useUpdateFormComponentMutation'; import { AUTOSAVE_DEBOUNCE_INTERVAL_MILLISECONDS } from 'app-shared/constants'; import { LayoutItemType } from '../types/global'; -import { useStudioUrlParams } from 'app-shared/hooks/useStudioUrlParams'; +import { useStudioEnvironmentParams } from 'app-shared/hooks/useStudioEnvironmentParams'; import { useAppContext } from '../hooks'; import type { MutateOptions } from '@tanstack/react-query'; @@ -69,7 +69,7 @@ type FormItemContextProviderProps = { export const FormItemContextProvider = ({ children, }: FormItemContextProviderProps): React.JSX.Element => { - const { org, app } = useStudioUrlParams(); + const { org, app } = useStudioEnvironmentParams(); const { selectedFormLayoutSetName, selectedFormLayoutName, refetchLayouts } = useAppContext(); const prevSelectedFormLayoutSetNameRef = useRef(selectedFormLayoutSetName); const prevSelectedFormLayoutNameRef = useRef(selectedFormLayoutName); diff --git a/frontend/packages/ux-editor/src/hooks/useFormLayouts.ts b/frontend/packages/ux-editor/src/hooks/useFormLayouts.ts index 336c36187ee..bff344d58bd 100644 --- a/frontend/packages/ux-editor/src/hooks/useFormLayouts.ts +++ b/frontend/packages/ux-editor/src/hooks/useFormLayouts.ts @@ -1,10 +1,10 @@ import { useFormLayoutsQuery } from './queries/useFormLayoutsQuery'; import type { IFormLayouts } from '../types/global'; -import { useStudioUrlParams } from 'app-shared/hooks/useStudioUrlParams'; +import { useStudioEnvironmentParams } from 'app-shared/hooks/useStudioEnvironmentParams'; import { useAppContext } from './'; export const useFormLayouts = (): IFormLayouts => { - const { org, app } = useStudioUrlParams(); + const { org, app } = useStudioEnvironmentParams(); const { selectedFormLayoutSetName } = useAppContext(); const formLayoutsQuery = useFormLayoutsQuery(org, app, selectedFormLayoutSetName); const { data } = formLayoutsQuery; diff --git a/frontend/packages/ux-editor/src/hooks/useSelectedFormLayoutName.ts b/frontend/packages/ux-editor/src/hooks/useSelectedFormLayoutName.ts index efc669e9b67..98f254b6588 100644 --- a/frontend/packages/ux-editor/src/hooks/useSelectedFormLayoutName.ts +++ b/frontend/packages/ux-editor/src/hooks/useSelectedFormLayoutName.ts @@ -1,6 +1,6 @@ import { useSearchParamsState } from 'app-shared/hooks/useSearchParamsState'; import { useFormLayoutSettingsQuery } from './queries/useFormLayoutSettingsQuery'; -import { useStudioUrlParams } from 'app-shared/hooks/useStudioUrlParams'; +import { useStudioEnvironmentParams } from 'app-shared/hooks/useStudioEnvironmentParams'; export type UseSelectedFormLayoutNameResult = { selectedFormLayoutName: string; @@ -10,7 +10,7 @@ export type UseSelectedFormLayoutNameResult = { export const useSelectedFormLayoutName = ( selectedFormLayoutSetName: string, ): UseSelectedFormLayoutNameResult => { - const { org, app } = useStudioUrlParams(); + const { org, app } = useStudioEnvironmentParams(); const { data: formLayoutSettings } = useFormLayoutSettingsQuery( org, app, diff --git a/frontend/packages/ux-editor/src/hooks/useSelectedFormLayoutSetName.ts b/frontend/packages/ux-editor/src/hooks/useSelectedFormLayoutSetName.ts index 82661ce910b..f5b4f1ccfa1 100644 --- a/frontend/packages/ux-editor/src/hooks/useSelectedFormLayoutSetName.ts +++ b/frontend/packages/ux-editor/src/hooks/useSelectedFormLayoutSetName.ts @@ -1,4 +1,4 @@ -import { useStudioUrlParams } from 'app-shared/hooks/useStudioUrlParams'; +import { useStudioEnvironmentParams } from 'app-shared/hooks/useStudioEnvironmentParams'; import { useLayoutSetsQuery } from 'app-shared/hooks/queries/useLayoutSetsQuery'; import { useEffect, useState } from 'react'; import { typedLocalStorage } from 'app-shared/utils/webStorage'; @@ -9,7 +9,7 @@ export type UseSelectedFormLayoutSetNameResult = { }; export const useSelectedFormLayoutSetName = (): UseSelectedFormLayoutSetNameResult => { - const { org, app } = useStudioUrlParams(); + const { org, app } = useStudioEnvironmentParams(); const { data: layoutSets } = useLayoutSetsQuery(org, app); const storageKey: string = 'selectedFormLayoutSetName'; diff --git a/frontend/packages/ux-editor/src/hooks/useSelectedTaskId.ts b/frontend/packages/ux-editor/src/hooks/useSelectedTaskId.ts index 5b0ef7962d7..7b79a9b45d3 100644 --- a/frontend/packages/ux-editor/src/hooks/useSelectedTaskId.ts +++ b/frontend/packages/ux-editor/src/hooks/useSelectedTaskId.ts @@ -1,9 +1,9 @@ -import { useStudioUrlParams } from 'app-shared/hooks/useStudioUrlParams'; +import { useStudioEnvironmentParams } from 'app-shared/hooks/useStudioEnvironmentParams'; import { useLayoutSetsQuery } from 'app-shared/hooks/queries/useLayoutSetsQuery'; import { TASKID_FOR_STATELESS_APPS } from 'app-shared/constants'; export const useSelectedTaskId = (selectedFormLayoutSetName: string): string => { - const { org, app } = useStudioUrlParams(); + const { org, app } = useStudioEnvironmentParams(); const { data: layoutSets } = useLayoutSetsQuery(org, app); return ( diff --git a/frontend/packages/ux-editor/src/hooks/useTextResourcesSelector.ts b/frontend/packages/ux-editor/src/hooks/useTextResourcesSelector.ts index fc2ceac88f7..bc901aa41a6 100644 --- a/frontend/packages/ux-editor/src/hooks/useTextResourcesSelector.ts +++ b/frontend/packages/ux-editor/src/hooks/useTextResourcesSelector.ts @@ -1,9 +1,9 @@ import type { TextResourcesSelector } from '../types/global'; import { useTextResourcesQuery } from 'app-shared/hooks/queries'; -import { useStudioUrlParams } from 'app-shared/hooks/useStudioUrlParams'; +import { useStudioEnvironmentParams } from 'app-shared/hooks/useStudioEnvironmentParams'; export const useTextResourcesSelector = (selector: TextResourcesSelector): T => { - const { org, app } = useStudioUrlParams(); + const { org, app } = useStudioEnvironmentParams(); const { data: textResources } = useTextResourcesQuery(org, app); return selector(textResources); }; diff --git a/frontend/packages/ux-editor/src/hooks/useValidateComponent.ts b/frontend/packages/ux-editor/src/hooks/useValidateComponent.ts index 70c3004741b..2951134c6f3 100644 --- a/frontend/packages/ux-editor/src/hooks/useValidateComponent.ts +++ b/frontend/packages/ux-editor/src/hooks/useValidateComponent.ts @@ -6,7 +6,7 @@ import type { FormRadioButtonsComponent, } from '../types/FormComponent'; import { useOptionListIdsQuery } from './queries/useOptionListIdsQuery'; -import { useStudioUrlParams } from 'app-shared/hooks/useStudioUrlParams'; +import { useStudioEnvironmentParams } from 'app-shared/hooks/useStudioEnvironmentParams'; export enum ErrorCode { NoOptions = 'NoOptions', @@ -48,7 +48,7 @@ const validateOptionGroup = ( }; export const useValidateComponent = (component: FormComponent): ComponentValidationResult => { - const { org, app } = useStudioUrlParams(); + const { org, app } = useStudioEnvironmentParams(); const { data: optionListIds } = useOptionListIdsQuery(org, app); switch (component.type) { From 389c15fb4da8b3b74c6b1b17c69236056e9f2f2f Mon Sep 17 00:00:00 2001 From: Michael Date: Thu, 30 May 2024 09:00:33 +0200 Subject: [PATCH 04/27] Force update of preview when updating the datamodel bindings (#12863) * Force update of preview when updating the datamodel bindings * Fix EditDataModelBindings tests * Fix DataModelBindings tests * Fix DataModelBindings tests --- .../Properties/DataModelBindings.test.tsx | 49 +++++- .../Properties/DataModelBindings.tsx | 4 +- .../EditDataModelBindings.test.tsx | 140 +++++++++++------- .../EditDataModelBindings.tsx | 39 +++-- 4 files changed, 157 insertions(+), 75 deletions(-) diff --git a/frontend/packages/ux-editor/src/components/Properties/DataModelBindings.test.tsx b/frontend/packages/ux-editor/src/components/Properties/DataModelBindings.test.tsx index b8d9339d522..2858b69dd1b 100644 --- a/frontend/packages/ux-editor/src/components/Properties/DataModelBindings.test.tsx +++ b/frontend/packages/ux-editor/src/components/Properties/DataModelBindings.test.tsx @@ -15,14 +15,37 @@ import { componentMocks } from '../../testing/componentMocks'; import { component3IdMock, component3Mock, layoutMock } from '@altinn/ux-editor/testing/layoutMock'; import { layoutSet1NameMock } from '@altinn/ux-editor/testing/layoutSetsMock'; import { app, org } from '@studio/testing/testids'; +import type { DataModelMetadataResponse } from 'app-shared/types/api'; -const user = userEvent.setup(); +const dataModelMetadata: DataModelMetadataResponse = { + elements: { + testModel: { + id: 'testModel', + type: 'ComplexType', + dataBindingName: 'testModel', + displayString: 'testModel', + isReadOnly: false, + isTagContent: false, + jsonSchemaPointer: '#/definitions/testModel', + maxOccurs: 1, + minOccurs: 1, + name: 'testModel', + parentElement: null, + restrictions: [], + texts: [], + xmlSchemaXPath: '/testModel', + xPath: '/testModel', + }, + }, +}; + +const getDataModelMetadata = () => Promise.resolve(dataModelMetadata); describe('DataModelBindings', () => { afterEach(jest.clearAllMocks); it('renders EditDataModelBindings component when schema is present', () => { - render({}); + render(); const dataModelButton = screen.getByRole('button', { name: textMock(`ux_editor.component_title.Input`), @@ -186,6 +209,7 @@ describe('DataModelBindings', () => { }); it('should toggle multiple attachment switch when clicked', async () => { + const user = userEvent.setup(); render({ props: { formItem: componentMocks[ComponentType.FileUpload], @@ -202,6 +226,7 @@ describe('DataModelBindings', () => { }); it('toggling ON multiple attachment switch should call handleUpdate with expected values', async () => { + const user = userEvent.setup(); const handleUpdate = jest.fn(); render({ props: { @@ -223,6 +248,7 @@ describe('DataModelBindings', () => { }); it('toggling OFF multiple attachment switch should call handleUpdate with expected values', async () => { + const user = userEvent.setup(); const handleUpdate = jest.fn(); render({ props: { @@ -245,6 +271,21 @@ describe('DataModelBindings', () => { dataModelBindings: { list: undefined, simpleBinding: '' }, }); }); + + it('checks that handleComponentChange is called', async () => { + const user = userEvent.setup(); + + render(); + + const dataModelButton = screen.getByRole('button', { + name: textMock(`ux_editor.component_title.Input`), + }); + await user.click(dataModelButton); + const option = screen.getByText('testModel'); + await user.click(option); + expect(formItemContextProviderMock.handleUpdate).toHaveBeenCalledTimes(1); + expect(formItemContextProviderMock.debounceSave).toHaveBeenCalledTimes(1); + }); }); const defaultProps = { @@ -256,8 +297,7 @@ const render = async ({ props = defaultProps, }: { props?: Partial; - editId?: string; -}) => { +} = {}) => { queryClientMock.setQueryData([QueryKey.FormLayouts, org, app, layoutSet1NameMock], { default: layoutMock, }); @@ -278,6 +318,7 @@ const render = async ({ appContextProps: { selectedFormLayoutName: 'default', }, + queries: { getDataModelMetadata }, }, ); }; diff --git a/frontend/packages/ux-editor/src/components/Properties/DataModelBindings.tsx b/frontend/packages/ux-editor/src/components/Properties/DataModelBindings.tsx index 3cb39fc153a..87ef49d5505 100644 --- a/frontend/packages/ux-editor/src/components/Properties/DataModelBindings.tsx +++ b/frontend/packages/ux-editor/src/components/Properties/DataModelBindings.tsx @@ -89,9 +89,9 @@ export const DataModelBindings = (): React.JSX.Element => { > { + handleComponentChange={async (updatedComponent, mutateOptions) => { handleUpdate(updatedComponent); - debounceSave(formItemId, updatedComponent); + debounceSave(formItemId, updatedComponent, mutateOptions); }} editFormId={formItemId} helpText={dataModelBindingsProperties[propertyKey]?.description} diff --git a/frontend/packages/ux-editor/src/components/config/editModal/EditDataModelBindings/EditDataModelBindings.test.tsx b/frontend/packages/ux-editor/src/components/config/editModal/EditDataModelBindings/EditDataModelBindings.test.tsx index a7f76f17486..507057ae183 100644 --- a/frontend/packages/ux-editor/src/components/config/editModal/EditDataModelBindings/EditDataModelBindings.test.tsx +++ b/frontend/packages/ux-editor/src/components/config/editModal/EditDataModelBindings/EditDataModelBindings.test.tsx @@ -1,6 +1,6 @@ import React from 'react'; import { screen } from '@testing-library/react'; -import { renderWithProviders } from '../../../../testing/mocks'; +import { renderHookWithProviders, renderWithProviders } from '../../../../testing/mocks'; import { EditDataModelBindings } from './EditDataModelBindings'; import { textMock } from '@studio/testing/mocks/i18nMock'; import { ComponentType } from 'app-shared/types/ComponentType'; @@ -12,6 +12,8 @@ import { componentMocks } from '../../../../testing/componentMocks'; import type { FormItem } from '../../../../types/FormItem'; import { app, org } from '@studio/testing/testids'; import { layoutSet1NameMock } from '@altinn/ux-editor/testing/layoutSetsMock'; +import { useMutation } from '@tanstack/react-query'; +import { appContextMock } from '@altinn/ux-editor/testing/appContextMock'; const dataModelName = undefined; @@ -82,23 +84,35 @@ const defaultRenderOptions = { const render = ({ component = defaultComponent, - handleComponentChange = jest.fn(), renderOptions = defaultRenderOptions, }: { component?: FormItem; handleComponentChange?: () => void; renderOptions?: { uniqueKey: string; key: string; label: string }; -}) => { - return renderWithProviders( - , - { - queries: { getDataModelMetadata }, - }, - ); +} = {}) => { + const handleComponentMutation = renderHookWithProviders(() => + useMutation({ + mutationFn: () => Promise.resolve(), + }), + ).result; + const mockhHandleComponentChange = jest + .fn() + .mockImplementation(async (mutationArgs, mutateOptions) => { + await handleComponentMutation.current.mutateAsync(mutationArgs, mutateOptions); + }); + return { + mockhHandleComponentChange, + ...renderWithProviders( + , + { + queries: { getDataModelMetadata }, + }, + ), + }; }; describe('EditDataModelBindings', () => { @@ -124,7 +138,7 @@ describe('EditDataModelBindings', () => { it('should show select with provided data model binding', async () => { const user = userEvent.setup(); - render({}); + render(); const linkIcon = screen.getByRole('button', { name: textMock('ux_editor.component_title.Input'), }); @@ -134,7 +148,7 @@ describe('EditDataModelBindings', () => { }); it('should render link icon', () => { - render({}); + render(); const linkIcon = screen.getByRole('button', { name: textMock('ux_editor.component_title.Input'), }); @@ -143,7 +157,7 @@ describe('EditDataModelBindings', () => { it('should show select when link icon is clicked', async () => { const user = userEvent.setup(); - render({}); + render(); const linkIcon = screen.getByRole('button', { name: textMock('ux_editor.component_title.Input'), }); @@ -154,7 +168,7 @@ describe('EditDataModelBindings', () => { it('should toggle select on link icon click', async () => { const user = userEvent.setup(); - render({}); + render(); expect(screen.queryByRole('combobox')).not.toBeInTheDocument(); const linkIcon = screen.getByRole('button', { name: textMock('ux_editor.component_title.Input'), @@ -165,28 +179,33 @@ describe('EditDataModelBindings', () => { it('check that handleComponentChange is called', async () => { const user = userEvent.setup(); - const handleComponentChange = jest.fn(); - render({ handleComponentChange }); + + const { mockhHandleComponentChange } = render(); const linkIcon = screen.getByRole('button', { name: textMock('ux_editor.component_title.Input'), }); await user.click(linkIcon); const option = screen.getByText('testModel'); await user.click(option); - expect(handleComponentChange).toHaveBeenCalledWith({ - ...defaultComponent, - dataModelBindings: { simpleBinding: 'testModel' }, - maxCount: undefined, - required: true, - timeStamp: undefined, - }); + expect(mockhHandleComponentChange).toHaveBeenCalledWith( + { + ...defaultComponent, + dataModelBindings: { simpleBinding: 'testModel' }, + maxCount: undefined, + required: true, + timeStamp: undefined, + }, + { + onSuccess: expect.any(Function), + }, + ); + expect(appContextMock.refetchLayouts).toHaveBeenCalledTimes(1); + expect(appContextMock.refetchLayouts).toHaveBeenCalledWith(layoutSet1NameMock, true); }); it('check that handleComponentChange is called with timestamp for DatePicker component', async () => { const user = userEvent.setup(); - const handleComponentChange = jest.fn(); - render({ - handleComponentChange, + const { mockhHandleComponentChange } = render({ component: { ...defaultComponent, type: ComponentType.Datepicker }, }); const linkIcon = screen.getByRole('button', { @@ -195,19 +214,26 @@ describe('EditDataModelBindings', () => { await user.click(linkIcon); const option = screen.getByText('datePickerField'); await user.click(option); - expect(handleComponentChange).toHaveBeenCalledWith({ - ...defaultComponent, - type: ComponentType.Datepicker, - dataModelBindings: { simpleBinding: 'datePickerField' }, - maxCount: undefined, - required: true, - timeStamp: true, - }); + expect(mockhHandleComponentChange).toHaveBeenCalledWith( + { + ...defaultComponent, + type: ComponentType.Datepicker, + dataModelBindings: { simpleBinding: 'datePickerField' }, + maxCount: undefined, + required: true, + timeStamp: true, + }, + { + onSuccess: expect.any(Function), + }, + ); + expect(appContextMock.refetchLayouts).toHaveBeenCalledTimes(1); + expect(appContextMock.refetchLayouts).toHaveBeenCalledWith(layoutSet1NameMock, true); }); it('should render close icon', async () => { const user = userEvent.setup(); - render({}); + render(); const linkIcon = screen.getByRole('button', { name: textMock('ux_editor.component_title.Input'), }); @@ -218,7 +244,7 @@ describe('EditDataModelBindings', () => { it('should render delete icon', async () => { const user = userEvent.setup(); - render({}); + render(); const linkIcon = screen.getByRole('button', { name: textMock('ux_editor.component_title.Input'), }); @@ -229,7 +255,7 @@ describe('EditDataModelBindings', () => { it('show link data model again when the user clicks on save button and no data model binding is selected', async () => { const user = userEvent.setup(); - render({}); + render(); const linkIcon = screen.getByRole('button', { name: textMock('ux_editor.component_title.Input'), }); @@ -250,11 +276,9 @@ describe('EditDataModelBindings', () => { it('deletes existing data model link', async () => { const user = userEvent.setup(); jest.spyOn(window, 'confirm').mockImplementation(() => true); - const handleComponentChange = jest.fn(); const dataModelBindingKey = 'testModel.field1'; - render({ - handleComponentChange, + const { mockhHandleComponentChange } = render({ component: { ...defaultComponent, dataModelBindings: { @@ -273,11 +297,18 @@ describe('EditDataModelBindings', () => { screen.getByText(dataModelBindingKey); const deleteButton = screen.getByRole('button', { name: textMock('general.delete') }); await user.click(deleteButton); - expect(handleComponentChange).toHaveBeenCalledWith({ - ...defaultComponent, - dataModelBindings: { simpleBinding: '' }, - timeStamp: undefined, - }); + expect(mockhHandleComponentChange).toHaveBeenCalledWith( + { + ...defaultComponent, + dataModelBindings: { simpleBinding: '' }, + timeStamp: undefined, + }, + { + onSuccess: expect.any(Function), + }, + ); + expect(appContextMock.refetchLayouts).toHaveBeenCalledTimes(1); + expect(appContextMock.refetchLayouts).toHaveBeenCalledWith(layoutSet1NameMock, true); }); it('shows edit fieldset when the user clicks on a binding button', async () => { @@ -303,16 +334,14 @@ describe('EditDataModelBindings', () => { it('should call "handleComponentUpdate" with maxCount when dataModelBinding is clicked for RepeatingGroup', async () => { const user = userEvent.setup(); - const mockHandleComponentUpdate = jest.fn(); const dataBindingNameMock = 'element'; const maxCountMock = 2; queryClientMock.setQueryData( [QueryKey.DataModelMetadata, org, app, layoutSet1NameMock, dataModelName], [{ dataBindingName: dataBindingNameMock, maxOccurs: maxCountMock }], ); - render({ + const { mockhHandleComponentChange } = render({ component: componentMocks[ComponentType.RepeatingGroup], - handleComponentChange: mockHandleComponentUpdate, renderOptions: { uniqueKey: 'some-key', key: 'group', @@ -331,14 +360,19 @@ describe('EditDataModelBindings', () => { const dataModelOption = screen.getByRole('option', { name: dataBindingNameMock }); await user.click(dataModelOption); - expect(mockHandleComponentUpdate).toHaveBeenCalled(); - expect(mockHandleComponentUpdate).toHaveBeenCalledWith( + expect(mockhHandleComponentChange).toHaveBeenCalled(); + expect(mockhHandleComponentChange).toHaveBeenCalledWith( expect.objectContaining({ ...componentMocks[ComponentType.RepeatingGroup], maxCount: maxCountMock, dataModelBindings: { group: dataBindingNameMock }, }), + { + onSuccess: expect.any(Function), + }, ); + expect(appContextMock.refetchLayouts).toHaveBeenCalledTimes(1); + expect(appContextMock.refetchLayouts).toHaveBeenCalledWith(layoutSet1NameMock, true); }); it('show right data model when switching component', () => { diff --git a/frontend/packages/ux-editor/src/components/config/editModal/EditDataModelBindings/EditDataModelBindings.tsx b/frontend/packages/ux-editor/src/components/config/editModal/EditDataModelBindings/EditDataModelBindings.tsx index 7866eaf7162..cf7b666017a 100644 --- a/frontend/packages/ux-editor/src/components/config/editModal/EditDataModelBindings/EditDataModelBindings.tsx +++ b/frontend/packages/ux-editor/src/components/config/editModal/EditDataModelBindings/EditDataModelBindings.tsx @@ -34,7 +34,7 @@ export const EditDataModelBindings = ({ helpText, }: EditDataModelBindingsProps) => { const { org, app } = useStudioEnvironmentParams(); - const { selectedFormLayoutSetName } = useAppContext(); + const { selectedFormLayoutSetName, refetchLayouts } = useAppContext(); const { data } = useDataModelMetadataQuery(org, app, selectedFormLayoutSetName, undefined); const { t } = useTranslation(); const [dataModelSelectVisible, setDataModelSelectVisible] = useState(false); @@ -47,22 +47,29 @@ export const EditDataModelBindings = ({ const bindingKey = key || 'simpleBinding'; const handleBindingChange = (selectedDataModelElement: string) => { - handleComponentChange({ - ...component, - dataModelBindings: { - ...component.dataModelBindings, - [bindingKey]: selectedDataModelElement, + handleComponentChange( + { + ...component, + dataModelBindings: { + ...component.dataModelBindings, + [bindingKey]: selectedDataModelElement, + }, + required: getMinOccursFromDataModel(selectedDataModelElement, data) > 0 || undefined, + timeStamp: + component.type === ComponentType.Datepicker + ? getXsdDataTypeFromDataModel(selectedDataModelElement, data) === 'DateTime' + : undefined, + maxCount: + component.type === ComponentType.RepeatingGroup + ? getMaxOccursFromDataModel(selectedDataModelElement, data) + : undefined, + } as FormItem, + { + onSuccess: async () => { + await refetchLayouts(selectedFormLayoutSetName, true); + }, }, - required: getMinOccursFromDataModel(selectedDataModelElement, data) > 0 || undefined, - timeStamp: - component.type === ComponentType.Datepicker - ? getXsdDataTypeFromDataModel(selectedDataModelElement, data) === 'DateTime' - : undefined, - maxCount: - component.type === ComponentType.RepeatingGroup - ? getMaxOccursFromDataModel(selectedDataModelElement, data) - : undefined, - } as FormItem); + ); }; const handleDelete = () => { From 7ae5737011e64804a3f3ec8f62ff5023561057e5 Mon Sep 17 00:00:00 2001 From: WilliamThorenfeldt <133344438+WilliamThorenfeldt@users.noreply.github.com> Date: Thu, 30 May 2024 10:11:45 +0200 Subject: [PATCH 05/27] Refactor policy editor (#12867) * Implementing context * refactor policy editor alert ! * Refactor logic to delete rules * fixing some tests * fixing some tests * clean up * removing comments * refactoring expandable card * refactor subjects * Refactor error logic * refactor policy description * Moving PolicyRuleError * refacor more * adding context tests * adding css cariables * fixing some feedback from PR * Fixing PR feedback --- .../policy-editor/src/PolicyEditor.module.css | 31 +- .../policy-editor/src/PolicyEditor.test.tsx | 138 +---- .../policy-editor/src/PolicyEditor.tsx | 205 ++----- .../AddPolicyRuleButton.module.css} | 8 +- .../AddPolicyRuleButton.test.tsx | 49 ++ .../AddPolicyRuleButton.tsx | 45 ++ .../components/AddPolicyRuleButton/index.ts | 1 + .../components/CardButton/CardButton.test.tsx | 29 - .../src/components/CardButton/CardButton.tsx | 34 -- .../src/components/CardButton/index.ts | 1 - .../ActionAndSubjectListItem.module.css | 5 - .../ActionAndSubjectListItem.test.tsx | 28 - .../ActionAndSubjectListItem.tsx | 49 -- .../ActionAndSubjectListItem/index.ts | 1 - .../ExpandablePolicyCard.module.css | 39 -- .../ExpandablePolicyCard.test.tsx | 285 ---------- .../ExpandablePolicyCard.tsx | 530 ------------------ .../PolicyResourceFields.tsx | 122 ---- .../ResourceNarrowingList.module.css | 8 - .../ResourceNarrowingList.tsx | 132 ----- .../components/ExpandablePolicyCard/index.ts | 1 - .../PolicyCardRules.module.css | 3 + .../PolicyCardRules/PolicyCardRules.test.tsx | 56 ++ .../PolicyCardRules/PolicyCardRules.tsx | 26 + .../ExpandablePolicyElement.module.css | 30 +- .../ExpandablePolicyElement.test.tsx | 0 .../ExpandablePolicyElement.tsx | 25 - .../PolicyEditorDropdownMenu.module.css | 2 +- .../PolicyEditorDropdownMenu.test.tsx | 0 .../PolicyEditorDropdownMenu.tsx | 13 - .../PolicyEditorDropdownMenu/index.ts | 0 .../ExpandablePolicyElement/index.ts | 0 .../PolicyActions/PolicyActions.module.css | 23 + .../PolicyActions/PolicyActions.test.tsx | 115 ++++ .../PolicyActions/PolicyActions.tsx | 108 ++++ .../PolicyRule/PolicyActions/index.ts | 1 + .../PolicyDescription.module.css | 7 + .../PolicyDescription.test.tsx | 35 ++ .../PolicyDescription/PolicyDescription.tsx | 38 ++ .../PolicyRule/PolicyDescription/index.ts | 1 + .../PolicyRule/PolicyRule.test.tsx | 106 ++++ .../PolicyCardRules/PolicyRule/PolicyRule.tsx | 92 +++ .../PolicyRuleErrorMessage.test.tsx | 86 +++ .../PolicyRuleErrorMessage.tsx | 42 ++ .../PolicyRuleErrorMessage/index.ts | 1 + .../PolicySubjects/PolicySubjects.module.css | 23 + .../PolicySubjects/PolicySubjects.test.tsx | 104 ++++ .../PolicySubjects/PolicySubjects.tsx | 100 ++++ .../PolicyRule/PolicySubjects/index.ts | 1 + .../PolicyResourceFields.module.css | 8 +- .../PolicyResourceFields.test.tsx | 76 +-- .../PolicyResourceFields.tsx | 113 ++++ .../PolicyResourceFields/index.ts | 0 .../ResourceNarrowingList.module.css | 8 + .../ResourceNarrowingList.test.tsx | 103 ++-- .../ResourceNarrowingList.tsx | 104 ++++ .../ResourceNarrowingList/index.ts | 0 .../SubResources/SubResources.module.css | 9 + .../SubResources/SubResources.test.tsx | 48 ++ .../PolicyRule/SubResources/SubResources.tsx | 74 +++ .../PolicyRule/SubResources/index.ts | 1 + .../PolicyCardRules/PolicyRule/index.ts | 1 + .../src/components/PolicyCardRules/index.ts | 1 + .../PolicyEditorAlert.module.css | 4 + .../PolicyEditorAlert.test.tsx | 60 ++ .../PolicyEditorAlert/PolicyEditorAlert.tsx | 21 + .../src/components/PolicyEditorAlert/index.ts | 1 + .../SecurityLevelSelect.module.css | 14 +- .../SecurityLevelSelect.tsx | 13 +- .../VerificationModal.module.css | 21 - .../VerificationModal.test.tsx | 68 --- .../VerificationModal/VerificationModal.tsx | 68 --- .../src/components/VerificationModal/index.ts | 1 - .../PolicyEditorContext.test.tsx | 45 ++ .../PolicyEditorContext.tsx | 43 ++ .../src/contexts/PolicyEditorContext/index.ts | 6 + .../PolicyRuleContext.test.tsx | 45 ++ .../PolicyRuleContext/PolicyRuleContext.tsx | 39 ++ .../src/contexts/PolicyRuleContext/index.ts | 6 + .../policy-editor/src/data-mocks/index.ts | 4 - .../packages/policy-editor/src/types/index.ts | 6 + .../src/utils/PolicyEditorUtils.test.ts | 18 +- .../PolicyRuleUtils.test.ts} | 8 +- .../index.ts | 0 .../packages/policy-editor/src/utils/index.ts | 5 + .../mocks}/policyActionMocks.ts | 2 +- .../test/mocks/policyEditorContextMock.ts | 21 + .../test/mocks/policyRuleContextMock.ts | 17 + .../mocks}/policyRuleMocks.ts | 2 +- .../mocks}/policySubResourceMocks.ts | 2 +- .../mocks}/policySubjectMocks.ts | 2 +- 91 files changed, 1964 insertions(+), 1903 deletions(-) rename frontend/packages/policy-editor/src/components/{CardButton/CardButton.module.css => AddPolicyRuleButton/AddPolicyRuleButton.module.css} (86%) create mode 100644 frontend/packages/policy-editor/src/components/AddPolicyRuleButton/AddPolicyRuleButton.test.tsx create mode 100644 frontend/packages/policy-editor/src/components/AddPolicyRuleButton/AddPolicyRuleButton.tsx create mode 100644 frontend/packages/policy-editor/src/components/AddPolicyRuleButton/index.ts delete mode 100644 frontend/packages/policy-editor/src/components/CardButton/CardButton.test.tsx delete mode 100644 frontend/packages/policy-editor/src/components/CardButton/CardButton.tsx delete mode 100644 frontend/packages/policy-editor/src/components/CardButton/index.ts delete mode 100644 frontend/packages/policy-editor/src/components/ExpandablePolicyCard/ActionAndSubjectListItem/ActionAndSubjectListItem.module.css delete mode 100644 frontend/packages/policy-editor/src/components/ExpandablePolicyCard/ActionAndSubjectListItem/ActionAndSubjectListItem.test.tsx delete mode 100644 frontend/packages/policy-editor/src/components/ExpandablePolicyCard/ActionAndSubjectListItem/ActionAndSubjectListItem.tsx delete mode 100644 frontend/packages/policy-editor/src/components/ExpandablePolicyCard/ActionAndSubjectListItem/index.ts delete mode 100644 frontend/packages/policy-editor/src/components/ExpandablePolicyCard/ExpandablePolicyCard.module.css delete mode 100644 frontend/packages/policy-editor/src/components/ExpandablePolicyCard/ExpandablePolicyCard.test.tsx delete mode 100644 frontend/packages/policy-editor/src/components/ExpandablePolicyCard/ExpandablePolicyCard.tsx delete mode 100644 frontend/packages/policy-editor/src/components/ExpandablePolicyCard/ResourceNarrowingList/PolicyResourceFields/PolicyResourceFields.tsx delete mode 100644 frontend/packages/policy-editor/src/components/ExpandablePolicyCard/ResourceNarrowingList/ResourceNarrowingList.module.css delete mode 100644 frontend/packages/policy-editor/src/components/ExpandablePolicyCard/ResourceNarrowingList/ResourceNarrowingList.tsx delete mode 100644 frontend/packages/policy-editor/src/components/ExpandablePolicyCard/index.ts create mode 100644 frontend/packages/policy-editor/src/components/PolicyCardRules/PolicyCardRules.module.css create mode 100644 frontend/packages/policy-editor/src/components/PolicyCardRules/PolicyCardRules.test.tsx create mode 100644 frontend/packages/policy-editor/src/components/PolicyCardRules/PolicyCardRules.tsx rename frontend/packages/policy-editor/src/components/{ExpandablePolicyCard => PolicyCardRules/PolicyRule}/ExpandablePolicyElement/ExpandablePolicyElement.module.css (75%) rename frontend/packages/policy-editor/src/components/{ExpandablePolicyCard => PolicyCardRules/PolicyRule}/ExpandablePolicyElement/ExpandablePolicyElement.test.tsx (100%) rename frontend/packages/policy-editor/src/components/{ExpandablePolicyCard => PolicyCardRules/PolicyRule}/ExpandablePolicyElement/ExpandablePolicyElement.tsx (76%) rename frontend/packages/policy-editor/src/components/{ExpandablePolicyCard => PolicyCardRules/PolicyRule}/ExpandablePolicyElement/PolicyEditorDropdownMenu/PolicyEditorDropdownMenu.module.css (73%) rename frontend/packages/policy-editor/src/components/{ExpandablePolicyCard => PolicyCardRules/PolicyRule}/ExpandablePolicyElement/PolicyEditorDropdownMenu/PolicyEditorDropdownMenu.test.tsx (100%) rename frontend/packages/policy-editor/src/components/{ExpandablePolicyCard => PolicyCardRules/PolicyRule}/ExpandablePolicyElement/PolicyEditorDropdownMenu/PolicyEditorDropdownMenu.tsx (74%) rename frontend/packages/policy-editor/src/components/{ExpandablePolicyCard => PolicyCardRules/PolicyRule}/ExpandablePolicyElement/PolicyEditorDropdownMenu/index.ts (100%) rename frontend/packages/policy-editor/src/components/{ExpandablePolicyCard => PolicyCardRules/PolicyRule}/ExpandablePolicyElement/index.ts (100%) create mode 100644 frontend/packages/policy-editor/src/components/PolicyCardRules/PolicyRule/PolicyActions/PolicyActions.module.css create mode 100644 frontend/packages/policy-editor/src/components/PolicyCardRules/PolicyRule/PolicyActions/PolicyActions.test.tsx create mode 100644 frontend/packages/policy-editor/src/components/PolicyCardRules/PolicyRule/PolicyActions/PolicyActions.tsx create mode 100644 frontend/packages/policy-editor/src/components/PolicyCardRules/PolicyRule/PolicyActions/index.ts create mode 100644 frontend/packages/policy-editor/src/components/PolicyCardRules/PolicyRule/PolicyDescription/PolicyDescription.module.css create mode 100644 frontend/packages/policy-editor/src/components/PolicyCardRules/PolicyRule/PolicyDescription/PolicyDescription.test.tsx create mode 100644 frontend/packages/policy-editor/src/components/PolicyCardRules/PolicyRule/PolicyDescription/PolicyDescription.tsx create mode 100644 frontend/packages/policy-editor/src/components/PolicyCardRules/PolicyRule/PolicyDescription/index.ts create mode 100644 frontend/packages/policy-editor/src/components/PolicyCardRules/PolicyRule/PolicyRule.test.tsx create mode 100644 frontend/packages/policy-editor/src/components/PolicyCardRules/PolicyRule/PolicyRule.tsx create mode 100644 frontend/packages/policy-editor/src/components/PolicyCardRules/PolicyRule/PolicyRuleErrorMessage/PolicyRuleErrorMessage.test.tsx create mode 100644 frontend/packages/policy-editor/src/components/PolicyCardRules/PolicyRule/PolicyRuleErrorMessage/PolicyRuleErrorMessage.tsx create mode 100644 frontend/packages/policy-editor/src/components/PolicyCardRules/PolicyRule/PolicyRuleErrorMessage/index.ts create mode 100644 frontend/packages/policy-editor/src/components/PolicyCardRules/PolicyRule/PolicySubjects/PolicySubjects.module.css create mode 100644 frontend/packages/policy-editor/src/components/PolicyCardRules/PolicyRule/PolicySubjects/PolicySubjects.test.tsx create mode 100644 frontend/packages/policy-editor/src/components/PolicyCardRules/PolicyRule/PolicySubjects/PolicySubjects.tsx create mode 100644 frontend/packages/policy-editor/src/components/PolicyCardRules/PolicyRule/PolicySubjects/index.ts rename frontend/packages/policy-editor/src/components/{ExpandablePolicyCard => PolicyCardRules/PolicyRule/SubResources}/ResourceNarrowingList/PolicyResourceFields/PolicyResourceFields.module.css (59%) rename frontend/packages/policy-editor/src/components/{ExpandablePolicyCard => PolicyCardRules/PolicyRule/SubResources}/ResourceNarrowingList/PolicyResourceFields/PolicyResourceFields.test.tsx (52%) create mode 100644 frontend/packages/policy-editor/src/components/PolicyCardRules/PolicyRule/SubResources/ResourceNarrowingList/PolicyResourceFields/PolicyResourceFields.tsx rename frontend/packages/policy-editor/src/components/{ExpandablePolicyCard => PolicyCardRules/PolicyRule/SubResources}/ResourceNarrowingList/PolicyResourceFields/index.ts (100%) create mode 100644 frontend/packages/policy-editor/src/components/PolicyCardRules/PolicyRule/SubResources/ResourceNarrowingList/ResourceNarrowingList.module.css rename frontend/packages/policy-editor/src/components/{ExpandablePolicyCard => PolicyCardRules/PolicyRule/SubResources}/ResourceNarrowingList/ResourceNarrowingList.test.tsx (55%) create mode 100644 frontend/packages/policy-editor/src/components/PolicyCardRules/PolicyRule/SubResources/ResourceNarrowingList/ResourceNarrowingList.tsx rename frontend/packages/policy-editor/src/components/{ExpandablePolicyCard => PolicyCardRules/PolicyRule/SubResources}/ResourceNarrowingList/index.ts (100%) create mode 100644 frontend/packages/policy-editor/src/components/PolicyCardRules/PolicyRule/SubResources/SubResources.module.css create mode 100644 frontend/packages/policy-editor/src/components/PolicyCardRules/PolicyRule/SubResources/SubResources.test.tsx create mode 100644 frontend/packages/policy-editor/src/components/PolicyCardRules/PolicyRule/SubResources/SubResources.tsx create mode 100644 frontend/packages/policy-editor/src/components/PolicyCardRules/PolicyRule/SubResources/index.ts create mode 100644 frontend/packages/policy-editor/src/components/PolicyCardRules/PolicyRule/index.ts create mode 100644 frontend/packages/policy-editor/src/components/PolicyCardRules/index.ts create mode 100644 frontend/packages/policy-editor/src/components/PolicyEditorAlert/PolicyEditorAlert.module.css create mode 100644 frontend/packages/policy-editor/src/components/PolicyEditorAlert/PolicyEditorAlert.test.tsx create mode 100644 frontend/packages/policy-editor/src/components/PolicyEditorAlert/PolicyEditorAlert.tsx create mode 100644 frontend/packages/policy-editor/src/components/PolicyEditorAlert/index.ts delete mode 100644 frontend/packages/policy-editor/src/components/VerificationModal/VerificationModal.module.css delete mode 100644 frontend/packages/policy-editor/src/components/VerificationModal/VerificationModal.test.tsx delete mode 100644 frontend/packages/policy-editor/src/components/VerificationModal/VerificationModal.tsx delete mode 100644 frontend/packages/policy-editor/src/components/VerificationModal/index.ts create mode 100644 frontend/packages/policy-editor/src/contexts/PolicyEditorContext/PolicyEditorContext.test.tsx create mode 100644 frontend/packages/policy-editor/src/contexts/PolicyEditorContext/PolicyEditorContext.tsx create mode 100644 frontend/packages/policy-editor/src/contexts/PolicyEditorContext/index.ts create mode 100644 frontend/packages/policy-editor/src/contexts/PolicyRuleContext/PolicyRuleContext.test.tsx create mode 100644 frontend/packages/policy-editor/src/contexts/PolicyRuleContext/PolicyRuleContext.tsx create mode 100644 frontend/packages/policy-editor/src/contexts/PolicyRuleContext/index.ts delete mode 100644 frontend/packages/policy-editor/src/data-mocks/index.ts rename frontend/packages/policy-editor/src/utils/{ExpandablePolicyCardUtils/ExpandablePolicyCardUtils.test.ts => PolicyRuleUtils/PolicyRuleUtils.test.ts} (94%) rename frontend/packages/policy-editor/src/utils/{ExpandablePolicyCardUtils => PolicyRuleUtils}/index.ts (100%) rename frontend/packages/policy-editor/{src/data-mocks => test/mocks}/policyActionMocks.ts (94%) create mode 100644 frontend/packages/policy-editor/test/mocks/policyEditorContextMock.ts create mode 100644 frontend/packages/policy-editor/test/mocks/policyRuleContextMock.ts rename frontend/packages/policy-editor/{src/data-mocks => test/mocks}/policyRuleMocks.ts (95%) rename frontend/packages/policy-editor/{src/data-mocks => test/mocks}/policySubResourceMocks.ts (97%) rename frontend/packages/policy-editor/{src/data-mocks => test/mocks}/policySubjectMocks.ts (95%) diff --git a/frontend/packages/policy-editor/src/PolicyEditor.module.css b/frontend/packages/policy-editor/src/PolicyEditor.module.css index 6c985c13e2a..e865f36e6a4 100644 --- a/frontend/packages/policy-editor/src/PolicyEditor.module.css +++ b/frontend/packages/policy-editor/src/PolicyEditor.module.css @@ -1,30 +1,19 @@ -.alertWrapper { - margin-bottom: 20px; - max-width: 650px; -} +.policyEditor { + --policy-editor-width: 595px; -.alert { - display: flex; - align-items: center; + width: var(--policy-editor-width); + min-width: var(--policy-editor-width); } -.addCardButtonWrapper { - margin-block: 20px; - width: 595px; - min-width: 595px; -} - -.space { - margin-block: 20px; +.alertWrapper { + margin-bottom: var(--fds-spacing-5); } -.policyEditorHeader { - margin-bottom: 40px; - font-weight: 400; - font-size: 30px; +.addCardButtonWrapper { + margin-block: var(--fds-spacing-5); } .heading { - margin-top: 30px; - margin-bottom: 10px; + margin-top: var(--fds-spacing-7); + margin-bottom: var(--fds-spacing-2); } diff --git a/frontend/packages/policy-editor/src/PolicyEditor.test.tsx b/frontend/packages/policy-editor/src/PolicyEditor.test.tsx index dd499dcaabe..0b114f6403e 100644 --- a/frontend/packages/policy-editor/src/PolicyEditor.test.tsx +++ b/frontend/packages/policy-editor/src/PolicyEditor.test.tsx @@ -1,12 +1,14 @@ import React from 'react'; import { render, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; -import type { PolicyEditorProps } from './PolicyEditor'; -import { PolicyEditor } from './PolicyEditor'; +import { PolicyEditor, type PolicyEditorProps } from './PolicyEditor'; import { textMock } from '@studio/testing/mocks/i18nMock'; import type { Policy, RequiredAuthLevel, PolicyEditorUsage } from './types'; -import { mockActions, mockPolicyRules, mockResourecId1, mockSubjects } from './data-mocks'; import { authlevelOptions } from './components/SecurityLevelSelect/SecurityLevelSelect'; +import { mockActions } from '../test/mocks/policyActionMocks'; +import { mockSubjects } from '../test/mocks/policySubjectMocks'; +import { mockPolicyRules } from '../test/mocks/policyRuleMocks'; +import { mockResourecId1 } from '../test/mocks/policySubResourceMocks'; const mockRequiredAuthLevel: RequiredAuthLevel = '3'; const mockRequiredAuthLevelLabel: string = textMock(authlevelOptions[3].label); @@ -19,58 +21,24 @@ const mockPolicy: Policy = { const mockUsageType: PolicyEditorUsage = 'app'; -describe('PolicyEditor', () => { - afterEach(jest.clearAllMocks); - - const mockOnSave = jest.fn(); - - const defaultProps: PolicyEditorProps = { - policy: mockPolicy, - actions: mockActions, - subjects: mockSubjects, - resourceId: mockResourecId1, - onSave: mockOnSave, - showAllErrors: false, - usageType: mockUsageType, - }; - - it('displays the alert title for app when usagetype is app', async () => { - const user = userEvent.setup(); - render(); - - const alertTextApp = screen.getByText( - textMock('policy_editor.alert', { usageType: textMock('policy_editor.alert_app') }), - ); - const alertTextResource = screen.queryByText( - textMock('policy_editor.alert', { usageType: textMock('policy_editor.alert_resource') }), - ); - - await user.tab(); - - expect(alertTextApp).toBeInTheDocument(); - expect(alertTextResource).not.toBeInTheDocument(); - }); - - it('displays the alert title for resource when usagetype is not app', async () => { - const user = userEvent.setup(); - render(); - - const alertTextApp = screen.queryByText( - textMock('policy_editor.alert', { usageType: textMock('policy_editor.alert_app') }), - ); - const alertTextResource = screen.getByText( - textMock('policy_editor.alert', { usageType: textMock('policy_editor.alert_resource') }), - ); +const mockOnSave = jest.fn(); - await user.tab(); +const defaultProps: PolicyEditorProps = { + policy: mockPolicy, + actions: mockActions, + subjects: mockSubjects, + resourceId: mockResourecId1, + onSave: mockOnSave, + showAllErrors: false, + usageType: mockUsageType, +}; - expect(alertTextApp).not.toBeInTheDocument(); - expect(alertTextResource).toBeInTheDocument(); - }); +describe('PolicyEditor', () => { + afterEach(jest.clearAllMocks); it('changes the auth level when the user selects a different auth level', async () => { const user = userEvent.setup(); - render(); + renderPolicyEditor(); const [selectElement] = screen.getAllByLabelText( textMock('policy_editor.select_auth_level_label'), @@ -90,7 +58,7 @@ describe('PolicyEditor', () => { it('calls "onSave" when the auth level changes', async () => { const user = userEvent.setup(); - render(); + renderPolicyEditor(); const [selectElement] = screen.getAllByLabelText( textMock('policy_editor.select_auth_level_label'), @@ -104,35 +72,9 @@ describe('PolicyEditor', () => { expect(mockOnSave).toHaveBeenCalledTimes(1); }); - it('displays the rules when there are more than 0 rules', async () => { - const user = userEvent.setup(); - render(); - - const aLabelFromPolicyCard = screen.getAllByText( - textMock('policy_editor.rule_card_sub_resource_title'), - ); - - await user.tab(); - - expect(aLabelFromPolicyCard.length).toEqual(mockPolicy.rules.length); - }); - - it('displays no rules when the policy has no rules', async () => { - const user = userEvent.setup(); - render(); - - const aLabelFromPolicyCard = screen.queryAllByText( - textMock('policy_editor.rule_card_sub_resource_title'), - ); - - await user.tab(); - - expect(aLabelFromPolicyCard.length).toEqual(0); - }); - it('increases the rule list length when add rule button is clicked', async () => { const user = userEvent.setup(); - render(); + renderPolicyEditor(); const originalLength = mockPolicy.rules.length; @@ -148,40 +90,8 @@ describe('PolicyEditor', () => { expect(aLabelFromPolicyCard.length).toEqual(originalLength + 1); }); - - it('calls "onSave" when a new rule is added', async () => { - const user = userEvent.setup(); - render(); - - const addButton = screen.getByRole('button', { - name: textMock('policy_editor.card_button_text'), - }); - - await user.click(addButton); - - expect(mockOnSave).toHaveBeenCalledTimes(1); - }); - - it('hides verification modal when initially rendering the page, and opens it on click', async () => { - const user = userEvent.setup(); - render(); - - const modalTitle = screen.queryByRole('heading', { - name: textMock('policy_editor.verification_modal_heading'), - level: 1, - }); - expect(modalTitle).not.toBeInTheDocument(); - - const [moreButton] = screen.getAllByRole('button', { name: textMock('policy_editor.more') }); - await user.click(moreButton); - - const deleteButton = screen.getByRole('menuitem', { name: textMock('general.delete') }); - await user.click(deleteButton); - - const modalTitleAfter = screen.getByRole('heading', { - name: textMock('policy_editor.verification_modal_heading'), - level: 1, - }); - expect(modalTitleAfter).toBeInTheDocument(); - }); }); + +const renderPolicyEditor = (policyEditorProps: Partial = {}) => { + return render(); +}; diff --git a/frontend/packages/policy-editor/src/PolicyEditor.tsx b/frontend/packages/policy-editor/src/PolicyEditor.tsx index e83e7234009..c5d5dec630e 100644 --- a/frontend/packages/policy-editor/src/PolicyEditor.tsx +++ b/frontend/packages/policy-editor/src/PolicyEditor.tsx @@ -1,52 +1,36 @@ import React, { useState } from 'react'; -import { Alert, Heading, Paragraph } from '@digdir/design-system-react'; +import { Heading } from '@digdir/design-system-react'; import type { PolicyAction, Policy, PolicyRule, PolicyRuleCard, - PolicyRuleResource, PolicySubject, RequiredAuthLevel, PolicyEditorUsage, } from './types'; import { mapPolicyRulesBackendObjectToPolicyRuleCard, - emptyPolicyRule, mapPolicyRuleToPolicyRuleBackendObject, - createNewPolicyResource, } from './utils'; import classes from './PolicyEditor.module.css'; -import { VerificationModal } from './components/VerificationModal'; -import { ExpandablePolicyCard } from './components/ExpandablePolicyCard'; -import { CardButton } from './components/CardButton'; -import { ObjectUtils } from '@studio/pure-functions'; +import { AddPolicyRuleButton } from './components/AddPolicyRuleButton'; +import { PolicyEditorAlert } from './components/PolicyEditorAlert'; import { useTranslation } from 'react-i18next'; import { SecurityLevelSelect } from './components/SecurityLevelSelect'; +import { PolicyEditorContextProvider } from './contexts/PolicyEditorContext'; +import { PolicyCardRules } from './components/PolicyCardRules'; export type PolicyEditorProps = { policy: Policy; actions: PolicyAction[]; subjects: PolicySubject[]; resourceId?: string; - onSave: (policy: Policy) => void; + onSave: (policy: Policy) => void; // MAYBE MOVE TO CONTEXT showAllErrors: boolean; usageType: PolicyEditorUsage; }; -/** - * @component - * Displays the content where a user can add and edit a policy - * - * @property {Policy}[policy] - The policy to edit - * @property {PolicyAction[]}[actions] - A list of actions that can be used in the rules - * @property {PolicySubject[]}[subjects] - A list of subjects that be can selected in the rules - * @property {string}[resourceId] - (Optional) The ID of the resource so that it can fill the autogenerated field for the first resource - * @property {function}[onSave] - Function that saves the policy - * @property {boolean}[showAllErrors] - Flag to decide if errors should be shown or not - * @property {PolicyEditorUsage}[usageType] - The usage type of the policy editor - * - * @returns {React.ReactNode} - The rendered component - */ + export const PolicyEditor = ({ policy, actions, @@ -58,119 +42,14 @@ export const PolicyEditor = ({ }: PolicyEditorProps): React.ReactNode => { const { t } = useTranslation(); - // TODO - Find out how this should be set. Issue: #10880 - const resourceType = usageType === 'app' ? 'urn:altinn' : 'urn:altinn:resource'; + const resourceType = getResourceType(usageType); const [policyRules, setPolicyRules] = useState( mapPolicyRulesBackendObjectToPolicyRuleCard(policy?.rules ?? []), ); - // Handle the new updated IDs of the rules when a rule is deleted / duplicated - const [lastRuleId, setLastRuleId] = useState((policy?.rules?.length ?? 0) + 1); - - const [verificationModalOpen, setVerificationModalOpen] = useState(false); - - // To keep track of which rule to delete - const [ruleIdToDelete, setRuleIdToDelete] = useState('0'); const [showErrorsOnAllRulesAboveNew, setShowErrorsOnAllRulesAboveNew] = useState(false); - const displayRules = policyRules.map((pr, i) => { - return ( -
- handleCloneRule(i)} - handleDeleteRule={() => { - setVerificationModalOpen(true); - setRuleIdToDelete(pr.ruleId); - }} - showErrors={ - showAllErrors || (showErrorsOnAllRulesAboveNew && policyRules.length - 1 !== i) - } - savePolicy={(rules: PolicyRuleCard[]) => handleSavePolicy(rules)} - usageType={usageType} - /> -
- ); - }); - - /** - * Returns the rule ID to be used on the new element, and - * updates the store of the next rule id - */ - const getRuleId = () => { - const idTaken: boolean = policyRules.map((p) => p.ruleId).includes(lastRuleId.toString()); - - const currentRuleId = idTaken ? lastRuleId + 1 : lastRuleId; - setLastRuleId(currentRuleId + 1); - return currentRuleId; - }; - - /** - * Handles adding of more cards - */ - const handleAddCardClick = () => { - setShowErrorsOnAllRulesAboveNew(true); - - const newResource: PolicyRuleResource[][] = [ - createNewPolicyResource(usageType, resourceType, resourceId), - ]; - - const newRule: PolicyRuleCard = { - ...emptyPolicyRule, - ruleId: getRuleId().toString(), - resources: newResource, - }; - - const updatedRules: PolicyRuleCard[] = [...policyRules, ...[newRule]]; - - setPolicyRules(updatedRules); - handleSavePolicy(updatedRules); - }; - - /** - * Duplicates a rule with all the content in it - * - * @param index the index of the rule to duplicate - */ - const handleCloneRule = (index: number) => { - const ruleToDuplicate: PolicyRuleCard = { - ...policyRules[index], - ruleId: getRuleId().toString(), - }; - - // Create a deep copy of the object so the objects don't share same object reference - const deepCopiedRuleToDuplicate: PolicyRuleCard = ObjectUtils.deepCopy(ruleToDuplicate); - - const updatedRules = [...policyRules, deepCopiedRuleToDuplicate]; - setPolicyRules(updatedRules); - handleSavePolicy(updatedRules); - }; - - /** - * Deletes a rule from the list - * - * @param index the index of the rule to delete - */ - const handleDeleteRule = (ruleId: string) => { - const updatedRules = [...policyRules]; - const indexToRemove = updatedRules.findIndex((a) => a.ruleId === ruleId); - updatedRules.splice(indexToRemove, 1); - setPolicyRules(updatedRules); - - // Reset - setVerificationModalOpen(false); - setRuleIdToDelete('0'); - - handleSavePolicy(updatedRules); - }; - const handleSavePolicy = (rules: PolicyRuleCard[]) => { const policyEditorRules: PolicyRule[] = rules.map((pr) => mapPolicyRuleToPolicyRuleBackendObject( @@ -186,39 +65,43 @@ export const PolicyEditor = ({ onSave({ ...policy, requiredAuthenticationLevelEndUser: authLevel }); }; + const handleClickAddButton = () => { + setShowErrorsOnAllRulesAboveNew(true); + }; + return ( -
- - - {t('policy_editor.rules')} - -
- - - {t('policy_editor.alert', { - usageType: - usageType === 'app' - ? t('policy_editor.alert_app') - : t('policy_editor.alert_resource'), - })} - - -
- {displayRules} -
- + +
+ + + {t('policy_editor.rules')} + +
+ +
+ +
+ +
- setVerificationModalOpen(false)} - text={t('policy_editor.verification_modal_text')} - closeButtonText={t('policy_editor.verification_modal_close_button')} - actionButtonText={t('policy_editor.verification_modal_action_button')} - onPerformAction={() => handleDeleteRule(ruleIdToDelete)} - /> -
+ ); }; + +// TODO - Find out how this should be set. Issue: #10880 +const getResourceType = (usageType: PolicyEditorUsage): string => { + return usageType === 'app' ? 'urn:altinn' : 'urn:altinn:resource'; +}; diff --git a/frontend/packages/policy-editor/src/components/CardButton/CardButton.module.css b/frontend/packages/policy-editor/src/components/AddPolicyRuleButton/AddPolicyRuleButton.module.css similarity index 86% rename from frontend/packages/policy-editor/src/components/CardButton/CardButton.module.css rename to frontend/packages/policy-editor/src/components/AddPolicyRuleButton/AddPolicyRuleButton.module.css index dc1dba661bf..ce247a80bce 100644 --- a/frontend/packages/policy-editor/src/components/CardButton/CardButton.module.css +++ b/frontend/packages/policy-editor/src/components/AddPolicyRuleButton/AddPolicyRuleButton.module.css @@ -3,10 +3,10 @@ display: flex; align-items: center; justify-content: space-between; - padding: 20px; + padding: var(--fds-spacing-5); margin: 0; background-color: var(--fds-semantic-surface-neutral-default); - border-radius: 12px; + border-radius: var(--fds-sizing-3); border: solid 1px var(--fds-semantic-border-divider-default); cursor: pointer; } @@ -23,3 +23,7 @@ outline-offset: var(--focus-border-width); box-shadow: 0 0 0 var(--focus-border-width) var(--focus-border-inner-color); } + +.icon { + font-size: var(--fds-sizing-6); +} diff --git a/frontend/packages/policy-editor/src/components/AddPolicyRuleButton/AddPolicyRuleButton.test.tsx b/frontend/packages/policy-editor/src/components/AddPolicyRuleButton/AddPolicyRuleButton.test.tsx new file mode 100644 index 00000000000..a9aade3a396 --- /dev/null +++ b/frontend/packages/policy-editor/src/components/AddPolicyRuleButton/AddPolicyRuleButton.test.tsx @@ -0,0 +1,49 @@ +import React from 'react'; +import { render, screen } from '@testing-library/react'; +import { AddPolicyRuleButton, type AddPolicyRuleButtonProps } from './AddPolicyRuleButton'; +import { textMock } from '@studio/testing/mocks/i18nMock'; +import userEvent from '@testing-library/user-event'; +import { PolicyEditorContext } from '../../contexts/PolicyEditorContext'; +import { mockPolicyEditorContextValue } from '../../../test/mocks/policyEditorContextMock'; + +const mockOnClick = jest.fn(); +const defaultProps: AddPolicyRuleButtonProps = { + onClick: mockOnClick, +}; + +describe('AddPolicyRuleButton', () => { + afterEach(jest.clearAllMocks); + + it('calls the onClick function when clicked', async () => { + const user = userEvent.setup(); + renderAddPolicyRuleButton(); + + const buttonElement = screen.getByRole('button', { + name: textMock('policy_editor.card_button_text'), + }); + await user.click(buttonElement); + + expect(mockOnClick).toHaveBeenCalledTimes(1); + }); + + it('calls "savePolicy" when a new rule is added', async () => { + const user = userEvent.setup(); + renderAddPolicyRuleButton(); + + const addButton = screen.getByRole('button', { + name: textMock('policy_editor.card_button_text'), + }); + + await user.click(addButton); + + expect(mockPolicyEditorContextValue.savePolicy).toHaveBeenCalledTimes(1); + }); +}); + +const renderAddPolicyRuleButton = () => { + return render( + + + , + ); +}; diff --git a/frontend/packages/policy-editor/src/components/AddPolicyRuleButton/AddPolicyRuleButton.tsx b/frontend/packages/policy-editor/src/components/AddPolicyRuleButton/AddPolicyRuleButton.tsx new file mode 100644 index 00000000000..a8c3af05f41 --- /dev/null +++ b/frontend/packages/policy-editor/src/components/AddPolicyRuleButton/AddPolicyRuleButton.tsx @@ -0,0 +1,45 @@ +import React from 'react'; +import classes from './AddPolicyRuleButton.module.css'; +import { PlusIcon } from '@studio/icons'; +import { Paragraph } from '@digdir/design-system-react'; +import { usePolicyEditorContext } from '../../contexts/PolicyEditorContext'; +import type { PolicyRuleResource, PolicyRuleCard } from '../../types'; +import { emptyPolicyRule, createNewPolicyResource, getNewRuleId } from '../../utils'; +import { useTranslation } from 'react-i18next'; + +export type AddPolicyRuleButtonProps = { + onClick: () => void; +}; + +export const AddPolicyRuleButton = ({ onClick }: AddPolicyRuleButtonProps): React.ReactNode => { + const { policyRules, setPolicyRules, savePolicy, usageType, resourceId, resourceType } = + usePolicyEditorContext(); + const { t } = useTranslation(); + + const handleAddCardClick = () => { + onClick(); + + const newResource: PolicyRuleResource[][] = [ + createNewPolicyResource(usageType, resourceType, resourceId), + ]; + const newRuleId: string = getNewRuleId(policyRules); + + const newRule: PolicyRuleCard = { + ...emptyPolicyRule, + ruleId: newRuleId, + resources: newResource, + }; + + const updatedRules: PolicyRuleCard[] = [...policyRules, ...[newRule]]; + + setPolicyRules(updatedRules); + savePolicy(updatedRules); + }; + + return ( + + ); +}; diff --git a/frontend/packages/policy-editor/src/components/AddPolicyRuleButton/index.ts b/frontend/packages/policy-editor/src/components/AddPolicyRuleButton/index.ts new file mode 100644 index 00000000000..ead818f34b6 --- /dev/null +++ b/frontend/packages/policy-editor/src/components/AddPolicyRuleButton/index.ts @@ -0,0 +1 @@ +export { AddPolicyRuleButton } from './AddPolicyRuleButton'; diff --git a/frontend/packages/policy-editor/src/components/CardButton/CardButton.test.tsx b/frontend/packages/policy-editor/src/components/CardButton/CardButton.test.tsx deleted file mode 100644 index ff098b632c8..00000000000 --- a/frontend/packages/policy-editor/src/components/CardButton/CardButton.test.tsx +++ /dev/null @@ -1,29 +0,0 @@ -import React from 'react'; -import { render, screen } from '@testing-library/react'; -import type { CardButtonProps } from './CardButton'; -import { CardButton } from './CardButton'; -import { textMock } from '@studio/testing/mocks/i18nMock'; -import userEvent from '@testing-library/user-event'; - -const mockButtonText = textMock('policy_editor.card_button_text'); - -describe('CardButton', () => { - afterEach(jest.clearAllMocks); - - const mockOnClick = jest.fn(); - - const defaultProps: CardButtonProps = { - buttonText: mockButtonText, - onClick: mockOnClick, - }; - - it('calls the onClick function when clicked', async () => { - const user = userEvent.setup(); - render(); - - const buttonElement = screen.getByRole('button', { name: mockButtonText }); - await user.click(buttonElement); - - expect(mockOnClick).toHaveBeenCalledTimes(1); - }); -}); diff --git a/frontend/packages/policy-editor/src/components/CardButton/CardButton.tsx b/frontend/packages/policy-editor/src/components/CardButton/CardButton.tsx deleted file mode 100644 index 2ccd9488cb1..00000000000 --- a/frontend/packages/policy-editor/src/components/CardButton/CardButton.tsx +++ /dev/null @@ -1,34 +0,0 @@ -import React from 'react'; -import classes from './CardButton.module.css'; -import { PlusIcon } from '@studio/icons'; -import { Paragraph } from '@digdir/design-system-react'; - -export type CardButtonProps = { - /** - * The text to display on the button - */ - buttonText: string; - /** - * Function to handle buttonclick - * @returns void - */ - onClick: () => void; -}; - -/** - * @component - * Button component that displays a text and a plus icon. - * - * @property {string}[buttonText] - The text to display on the button - * @property {function}[onClick] - Function to handle buttonclick - * - * @returns {React.ReactNode} - The rendered component - */ -export const CardButton = ({ buttonText, onClick }: CardButtonProps): React.ReactNode => { - return ( - - ); -}; diff --git a/frontend/packages/policy-editor/src/components/CardButton/index.ts b/frontend/packages/policy-editor/src/components/CardButton/index.ts deleted file mode 100644 index 38a74ae5245..00000000000 --- a/frontend/packages/policy-editor/src/components/CardButton/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { CardButton } from './CardButton'; diff --git a/frontend/packages/policy-editor/src/components/ExpandablePolicyCard/ActionAndSubjectListItem/ActionAndSubjectListItem.module.css b/frontend/packages/policy-editor/src/components/ExpandablePolicyCard/ActionAndSubjectListItem/ActionAndSubjectListItem.module.css deleted file mode 100644 index 4a5b86e1a8f..00000000000 --- a/frontend/packages/policy-editor/src/components/ExpandablePolicyCard/ActionAndSubjectListItem/ActionAndSubjectListItem.module.css +++ /dev/null @@ -1,5 +0,0 @@ -.wrapper { - margin: 0; - margin-right: 5px; - margin-top: 5px; -} diff --git a/frontend/packages/policy-editor/src/components/ExpandablePolicyCard/ActionAndSubjectListItem/ActionAndSubjectListItem.test.tsx b/frontend/packages/policy-editor/src/components/ExpandablePolicyCard/ActionAndSubjectListItem/ActionAndSubjectListItem.test.tsx deleted file mode 100644 index 7e2259cf56f..00000000000 --- a/frontend/packages/policy-editor/src/components/ExpandablePolicyCard/ActionAndSubjectListItem/ActionAndSubjectListItem.test.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import React from 'react'; -import { render, screen } from '@testing-library/react'; -import type { ActionAndSubjectListItemProps } from './ActionAndSubjectListItem'; -import { ActionAndSubjectListItem } from './ActionAndSubjectListItem'; -import userEvent from '@testing-library/user-event'; - -const mockChipTitle: string = 'Test'; - -describe('ActionAndSubjectListItem', () => { - afterEach(jest.clearAllMocks); - - const mockOnRemove = jest.fn(); - - const defaultProps: ActionAndSubjectListItemProps = { - title: mockChipTitle, - onRemove: mockOnRemove, - }; - - it('calls the onRemove function when the chip is clicked', async () => { - const user = userEvent.setup(); - render(); - - const chipElement = screen.getByText(mockChipTitle); - await user.click(chipElement); - - expect(mockOnRemove).toHaveBeenCalledTimes(1); - }); -}); diff --git a/frontend/packages/policy-editor/src/components/ExpandablePolicyCard/ActionAndSubjectListItem/ActionAndSubjectListItem.tsx b/frontend/packages/policy-editor/src/components/ExpandablePolicyCard/ActionAndSubjectListItem/ActionAndSubjectListItem.tsx deleted file mode 100644 index 0cf00f60f5d..00000000000 --- a/frontend/packages/policy-editor/src/components/ExpandablePolicyCard/ActionAndSubjectListItem/ActionAndSubjectListItem.tsx +++ /dev/null @@ -1,49 +0,0 @@ -import React from 'react'; -import classes from './ActionAndSubjectListItem.module.css'; -import { Chip } from '@digdir/design-system-react'; -import { useTranslation } from 'react-i18next'; - -export type ActionAndSubjectListItemProps = { - /** - * The title to display - */ - title: string; - /** - * Function that removes the element from the list - */ - onRemove: () => void; -}; - -/** - * @component - * Displays the list of subjects that belongs to a rule in a card in the policy editor. - * - * @example - * - * - * @property {string}[title] - The title to display - * @property {function}[onRemove] - Function that removes the element from the list - * - * @returns {React.ReactNode} - The rendered Chip element - */ -export const ActionAndSubjectListItem = ({ - title, - onRemove, -}: ActionAndSubjectListItemProps): React.ReactNode => { - const { t } = useTranslation(); - - return ( -
- - {title} - -
- ); -}; diff --git a/frontend/packages/policy-editor/src/components/ExpandablePolicyCard/ActionAndSubjectListItem/index.ts b/frontend/packages/policy-editor/src/components/ExpandablePolicyCard/ActionAndSubjectListItem/index.ts deleted file mode 100644 index 76dcd5512f4..00000000000 --- a/frontend/packages/policy-editor/src/components/ExpandablePolicyCard/ActionAndSubjectListItem/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { ActionAndSubjectListItem } from './ActionAndSubjectListItem'; diff --git a/frontend/packages/policy-editor/src/components/ExpandablePolicyCard/ExpandablePolicyCard.module.css b/frontend/packages/policy-editor/src/components/ExpandablePolicyCard/ExpandablePolicyCard.module.css deleted file mode 100644 index 412f416d4f1..00000000000 --- a/frontend/packages/policy-editor/src/components/ExpandablePolicyCard/ExpandablePolicyCard.module.css +++ /dev/null @@ -1,39 +0,0 @@ -.cardWrapper { - width: 595px; - min-width: 595px; -} - -.chipWrapper { - display: flex; - flex-wrap: wrap; -} - -.textAreaWrapper { - margin-top: 10px; -} - -.addResourceButton { - width: 100%; - margin-bottom: 10px; -} - -.label { - margin-top: 30px; - margin-bottom: 5px; -} - -.label:first-child { - margin-top: 10px; -} - -.dropdownWrapper { - margin-bottom: 10px; -} - -.inputParagraph { - margin-bottom: 5px; -} - -.descriptionInput { - margin-top: 30px; -} diff --git a/frontend/packages/policy-editor/src/components/ExpandablePolicyCard/ExpandablePolicyCard.test.tsx b/frontend/packages/policy-editor/src/components/ExpandablePolicyCard/ExpandablePolicyCard.test.tsx deleted file mode 100644 index a22ce730a3b..00000000000 --- a/frontend/packages/policy-editor/src/components/ExpandablePolicyCard/ExpandablePolicyCard.test.tsx +++ /dev/null @@ -1,285 +0,0 @@ -import React from 'react'; -import { render, screen } from '@testing-library/react'; -import userEvent from '@testing-library/user-event'; -import type { ExpandablePolicyCardProps } from './ExpandablePolicyCard'; -import { ExpandablePolicyCard } from './ExpandablePolicyCard'; -import { textMock } from '@studio/testing/mocks/i18nMock'; -import type { PolicyEditorUsage } from '../../types'; -import { - mockActionId1, - mockActionId2, - mockActionId3, - mockActionId4, - mockActions, - mockPolicyRuleCard1, - mockPolicyRuleCards, - mockResourceType1, - mockResourecId1, - mockSubjectTitle1, - mockSubjectTitle2, - mockSubjectTitle3, - mockSubjects, -} from '../../data-mocks'; - -const mockUsageType: PolicyEditorUsage = 'app'; - -const mockActionOption1: string = textMock(`policy_editor.action_${mockActionId1}`); -const mockActionOption2: string = textMock(`policy_editor.action_${mockActionId2}`); -const mockActionOption3: string = textMock(`policy_editor.action_${mockActionId3}`); -const mockActionOption4: string = mockActionId4; - -describe('ExpandablePolicyCard', () => { - afterEach(jest.clearAllMocks); - - const mockSetPolicyRules = jest.fn(); - const mockHandleCloneRule = jest.fn(); - const mockHandleDeleteRule = jest.fn(); - const mockSavePolicy = jest.fn(); - - const defaultProps: ExpandablePolicyCardProps = { - policyRule: mockPolicyRuleCard1, - actions: mockActions, - subjects: mockSubjects, - rules: mockPolicyRuleCards, - setPolicyRules: mockSetPolicyRules, - resourceId: mockResourecId1, - resourceType: mockResourceType1, - handleCloneRule: mockHandleCloneRule, - handleDeleteRule: mockHandleDeleteRule, - showErrors: false, - savePolicy: mockSavePolicy, - usageType: mockUsageType, - }; - - it('calls "handleCloneRule" when the clone button is clicked', async () => { - const user = userEvent.setup(); - render(); - - const [moreButton] = screen.getAllByRole('button', { name: textMock('policy_editor.more') }); - await user.click(moreButton); - - const [cloneButton] = screen.getAllByRole('menuitem', { - name: textMock('policy_editor.expandable_card_dropdown_copy'), - }); - await user.click(cloneButton); - - expect(mockHandleCloneRule).toHaveBeenCalledTimes(1); - }); - - it('calls "handleDeleteRule" when the delete button is clicked', async () => { - const user = userEvent.setup(); - render(); - - const [moreButton] = screen.getAllByRole('button', { name: textMock('policy_editor.more') }); - await user.click(moreButton); - - const [deleteButton] = screen.getAllByRole('menuitem', { name: textMock('general.delete') }); - await user.click(deleteButton); - - expect(mockHandleDeleteRule).toHaveBeenCalledTimes(1); - }); - - it('calls "setPolicyRules" when sub-resource fields are edited', async () => { - const user = userEvent.setup(); - render(); - - const [typeInput] = screen.getAllByLabelText( - textMock('policy_editor.narrowing_list_field_type'), - ); - const [idInput] = screen.getAllByLabelText(textMock('policy_editor.narrowing_list_field_id')); - - const newWord: string = 'test'; - - await user.type(typeInput, newWord); - expect(mockSetPolicyRules).toHaveBeenCalledTimes(newWord.length); - - mockSetPolicyRules.mockClear(); - - await user.type(idInput, newWord); - expect(mockSetPolicyRules).toHaveBeenCalledTimes(newWord.length); - }); - - it('displays the selected actions as Chips', async () => { - const user = userEvent.setup(); - render(); - - // Check that the selected actions are present - const selectedAction1 = screen.getByLabelText( - `${textMock('general.delete')} ${mockActionOption1}`, - ); - const selectedAction2 = screen.getByLabelText( - `${textMock('general.delete')} ${mockActionOption2}`, - ); - const selectedAction3 = screen.queryByLabelText( - `${textMock('general.delete')} ${mockActionOption3}`, - ); - const selectedAction4 = screen.getByLabelText( - `${textMock('general.delete')} ${mockActionOption4}`, - ); - expect(selectedAction1).toBeInTheDocument(); - expect(selectedAction2).toBeInTheDocument(); - expect(selectedAction3).not.toBeInTheDocument(); // 3 is not in the resource - expect(selectedAction4).toBeInTheDocument(); - - // Open the select - const [actionSelect] = screen.getAllByLabelText( - textMock('policy_editor.rule_card_actions_title'), - ); - await user.click(actionSelect); - - // Check that the selected actions are not in the document - const optionAction1 = screen.queryByRole('option', { name: mockActionOption1 }); - const optionAction2 = screen.queryByRole('option', { name: mockActionOption2 }); - const optionAction3 = screen.getByRole('option', { name: mockActionOption3 }); - const optionAction4 = screen.queryByRole('option', { name: mockActionOption4 }); - - expect(optionAction1).not.toBeInTheDocument(); - expect(optionAction2).not.toBeInTheDocument(); - expect(optionAction3).toBeInTheDocument(); // 3 is in the resource - expect(optionAction4).not.toBeInTheDocument(); - - // Click the final action - await user.click(screen.getByRole('option', { name: mockActionOption3 })); - - expect(mockSetPolicyRules).toHaveBeenCalledTimes(1); - - // Expect the option clicked to be removed from the screen - expect( - screen.queryByLabelText(`${textMock('general.delete')} ${mockActionOption3}`), - ).not.toBeInTheDocument(); - - // Expect the label with all selected to be present - const [inputAllSelected] = screen.getAllByText( - textMock('policy_editor.rule_card_actions_select_all_selected'), - ); - expect(inputAllSelected).toBeInTheDocument(); - }); - - it('calls "setPolicyRules" when subjects are edited', async () => { - const user = userEvent.setup(); - render(); - - // Check that the selected subjects are present - const selectedSubject1 = screen.getByLabelText( - `${textMock('general.delete')} ${mockSubjectTitle1}`, - ); - const selectedSubject2 = screen.queryByLabelText( - `${textMock('general.delete')} ${mockSubjectTitle2}`, - ); - const selectedSubject3 = screen.getByLabelText( - `${textMock('general.delete')} ${mockSubjectTitle3}`, - ); - expect(selectedSubject1).toBeInTheDocument(); - expect(selectedSubject2).not.toBeInTheDocument(); // 2 is not in the resource - expect(selectedSubject3).toBeInTheDocument(); - - // Open the select - const [subjectSelect] = screen.getAllByLabelText( - textMock('policy_editor.rule_card_subjects_title'), - ); - await user.click(subjectSelect); - - // Check that the selected subjects are not in the document - const optionSubject1 = screen.queryByRole('option', { name: mockSubjectTitle1 }); - const optionSubject2 = screen.getByRole('option', { name: mockSubjectTitle2 }); - const optionSubject3 = screen.queryByRole('option', { name: mockSubjectTitle3 }); - - expect(optionSubject1).not.toBeInTheDocument(); - expect(optionSubject2).toBeInTheDocument(); // 2 is in the resource - expect(optionSubject3).not.toBeInTheDocument(); - - // Click the final subject - await user.click(screen.getByRole('option', { name: mockSubjectTitle2 })); - - expect(mockSetPolicyRules).toHaveBeenCalledTimes(1); - - // Expect the option clicked to be removed from the screen - expect( - screen.queryByLabelText(`${textMock('general.delete')} ${mockSubjectTitle2}`), - ).not.toBeInTheDocument(); - - // Expect the label with all selected to be present - const [inputAllSelected] = screen.getAllByText( - textMock('policy_editor.rule_card_subjects_select_all_selected'), - ); - expect(inputAllSelected).toBeInTheDocument(); - }); - - it('should append subject to selectable subject options list when selected subject is removed', async () => { - const user = userEvent.setup(); - render(); - - const [subjectSelect] = screen.getAllByLabelText( - textMock('policy_editor.rule_card_subjects_title'), - ); - await user.click(subjectSelect); - - // Check that already selected options does not be included within selectable list. - expect(screen.queryByRole('option', { name: mockSubjectTitle1 })).toBeNull(); - - // Remove the selected subject - const selectedSubject = screen.getByLabelText( - `${textMock('general.delete')} ${mockSubjectTitle1}`, - ); - await user.click(selectedSubject); - - // Open the select and verify that the removed subject is now appended to the selectable list - await user.click(subjectSelect); - expect(screen.getByRole('option', { name: mockSubjectTitle1 })).toBeInTheDocument(); - }); - - it('calls "setPolicyRules" when description field is edited', async () => { - const user = userEvent.setup(); - render(); - - const [descriptionField] = screen.getAllByLabelText( - textMock('policy_editor.rule_card_description_title'), - ); - expect(descriptionField).toHaveValue(mockPolicyRuleCard1.description); - await user.type(descriptionField, '1'); - - expect(mockSetPolicyRules).toHaveBeenCalledTimes(1); - }); - - it('calls "savePolicy" when input fields are blurred', async () => { - const user = userEvent.setup(); - render(); - - const [typeInput] = screen.getAllByLabelText( - textMock('policy_editor.narrowing_list_field_type'), - ); - const [idInput] = screen.getAllByLabelText(textMock('policy_editor.narrowing_list_field_id')); - - const newWord: string = 'test'; - await user.type(typeInput, newWord); - await user.tab(); - await user.type(idInput, newWord); - await user.tab(); - - const [actionSelect] = screen.getAllByLabelText( - textMock('policy_editor.rule_card_actions_title'), - ); - await user.click(actionSelect); - - const actionOption: string = textMock(`policy_editor.action_${mockActionId3}`); - await user.click(screen.getByRole('option', { name: actionOption })); - await user.tab(); - - const [subjectSelect] = screen.getAllByLabelText( - textMock('policy_editor.rule_card_subjects_title'), - ); - await user.click(subjectSelect); - await user.click(screen.getByRole('option', { name: mockSubjectTitle2 })); - await user.tab(); - - const [descriptionField] = screen.getAllByLabelText( - textMock('policy_editor.rule_card_description_title'), - ); - expect(descriptionField).toHaveValue(mockPolicyRuleCard1.description); - await user.type(descriptionField, newWord); - await user.tab(); - - const numFields = 5; - expect(mockSavePolicy).toHaveBeenCalledTimes(numFields); - }); -}); diff --git a/frontend/packages/policy-editor/src/components/ExpandablePolicyCard/ExpandablePolicyCard.tsx b/frontend/packages/policy-editor/src/components/ExpandablePolicyCard/ExpandablePolicyCard.tsx deleted file mode 100644 index 2a8ebb09b4e..00000000000 --- a/frontend/packages/policy-editor/src/components/ExpandablePolicyCard/ExpandablePolicyCard.tsx +++ /dev/null @@ -1,530 +0,0 @@ -import React, { useState, useId } from 'react'; -import { - Label, - ErrorMessage, - Paragraph, - Textarea, - LegacySelect, -} from '@digdir/design-system-react'; -import { PlusIcon } from '@studio/icons'; -import classes from './ExpandablePolicyCard.module.css'; -import { ActionAndSubjectListItem } from './ActionAndSubjectListItem'; -import { ResourceNarrowingList } from './ResourceNarrowingList'; -import { ExpandablePolicyElement } from './ExpandablePolicyElement'; -import type { - PolicyAction, - PolicyRuleCard, - PolicyRuleResource, - PolicySubject, - PolicyEditorUsage, -} from '../../types'; -import { createNewPolicyResource, findSubjectByPolicyRuleSubject } from '../../utils'; -import { - getActionOptions, - getPolicyRuleIdString, - getSubjectOptions, - getUpdatedRules, -} from '../../utils/ExpandablePolicyCardUtils'; -import { useTranslation } from 'react-i18next'; -import { StudioButton, StudioLabelAsParagraph } from '@studio/components'; - -const wellKnownActionsIds: string[] = [ - 'complete', - 'confirm', - 'delete', - 'instantiate', - 'read', - 'sign', - 'write', -]; - -export type ExpandablePolicyCardProps = { - policyRule: PolicyRuleCard; - actions: PolicyAction[]; - subjects: PolicySubject[]; - rules: PolicyRuleCard[]; - setPolicyRules: React.Dispatch>; - resourceId: string; - resourceType: string; - handleCloneRule: () => void; - handleDeleteRule: () => void; - showErrors: boolean; - savePolicy: (rules: PolicyRuleCard[]) => void; - usageType: PolicyEditorUsage; -}; - -/** - * @component - * Component that displays a card where a user can view and update a policy rule - * for a resource. - * - * @property {PolicyRuleCard}[policyRule] - The rule to display in the card - * @property {PolicyAction[]}[actions] - The possible actions to select from - * @property {PolicySubject[]}[subjects] - The possible subjects to select from - * @property {PolicyRuleCard[]}[rules] - The list of all the rules - * @property {React.Dispatch>}[setPolicyRules] - useState function to update the list of rules - * @property {string}[resourceId] - The ID of the resource - * @property {string}[resourceType] - The type of the resource - * @property {function}[handleCloneRule] - Function to be executed when clicking clone rule - * @property {function}[handleDeleteRule] - Function to be executed when clicking delete rule - * @property {boolean}[showErrors] - Flag to decide if errors should be shown or not - * @property {function}[savePolicy] - Function to save the policy - * @property {PolicyEditorUsage}[usageType] - The usage type of the policy editor - * - * @returns {React.ReactNode} - The rendered component - */ -export const ExpandablePolicyCard = ({ - policyRule, - actions, - subjects, - rules, - setPolicyRules, - resourceId, - resourceType, - handleCloneRule, - handleDeleteRule, - showErrors, - savePolicy, - usageType, -}: ExpandablePolicyCardProps): React.ReactNode => { - const { t } = useTranslation(); - - const uniqueId = useId(); - - const [hasResourceError, setHasResourceError] = useState(policyRule.resources.length === 0); - const [hasRightsError, setHasRightsErrors] = useState(policyRule.actions.length === 0); - const [hasSubjectsError, setHasSubjectsError] = useState(policyRule.subject.length === 0); - const [subjectOptions, setSubjectOptions] = useState(getSubjectOptions(subjects, policyRule)); - const [actionOptions, setActionOptions] = useState(getActionOptions(actions, policyRule)); - - /** - * Handles the changes in the input fields inside the resource blocks - * - * @param index the index of the element in the resource block - * @param field the type of textfield to update - * @param value the value types in the textfield - * @param ruleIndex the index of the rule - */ - const handleInputChange = ( - index: number, - field: 'id' | 'type', - value: string, - ruleIndex: number, - ) => { - const updatedResources = [...policyRule.resources]; - updatedResources[ruleIndex][index] = { - ...updatedResources[ruleIndex][index], - [field]: value, - }; - - const updatedRules = getUpdatedRules( - { ...policyRule, resources: updatedResources }, - policyRule.ruleId, - rules, - ); - setPolicyRules(updatedRules); - }; - - /** - * Adds a resource block to the list of resources. The first element in the - * resource block is set to the resource's ID and type. - */ - const handleClickAddResource = () => { - const newResource: PolicyRuleResource[] = createNewPolicyResource( - usageType, - resourceType, - resourceId, - ); - - const updatedResources = [...policyRule.resources, newResource]; - const updatedRules = getUpdatedRules( - { ...policyRule, resources: updatedResources }, - policyRule.ruleId, - rules, - ); - setPolicyRules(updatedRules); - savePolicy(updatedRules); - setHasResourceError(false); - }; - - /** - * Displays a list of resource blocks, which each contains a list of the resources - * and the list narrowing down the elements. - */ - const displayResources = policyRule.resources.map((r, i) => { - return ( - - handleInputChange(narrowResourceIndex, field, s, i) - } - handleRemoveResource={(narrowResourceIndex) => - handleRemoveNarrowingResource(narrowResourceIndex, i) - } - handleClickAddResource={() => handleClickAddResourceNarrowing(i)} - handleCloneElement={() => handleCloneResourceGroup(i)} - handleRemoveElement={() => handleDeleteResourceGroup(i)} - onBlur={() => savePolicy(rules)} - usageType={usageType} - /> - ); - }); - - /** - * Handles the addition of more resources - */ - const handleClickAddResourceNarrowing = (resourceIndex: number) => { - const newResource: PolicyRuleResource = { - type: '', - id: '', - }; - const updatedResources = [...policyRule.resources]; - updatedResources[resourceIndex].push(newResource); - - const updatedRules = getUpdatedRules( - { ...policyRule, resources: updatedResources }, - policyRule.ruleId, - rules, - ); - setPolicyRules(updatedRules); - savePolicy(updatedRules); - }; - - /** - * Handles the removal of the narrowed resources - */ - const handleRemoveNarrowingResource = (index: number, ruleIndex: number) => { - const updatedResources = [...policyRule.resources]; - updatedResources[ruleIndex].splice(index, 1); - const updatedRules = getUpdatedRules( - { ...policyRule, resources: updatedResources }, - policyRule.ruleId, - rules, - ); - setPolicyRules(updatedRules); - savePolicy(updatedRules); - }; - - const getTranslationByActionId = (actionId: string): string => { - return wellKnownActionsIds.includes(actionId) - ? t(`policy_editor.action_${actionId}`) - : actionId; - }; - - const displayActions = policyRule.actions.map((actionId, i) => { - return ( - handleRemoveAction(i, actionId)} - /> - ); - }); - - const handleRemoveAction = (index: number, actionTitle: string) => { - // Remove from selected list - const updatedActions = [...policyRule.actions]; - updatedActions.splice(index, 1); - - // Add to options list - setActionOptions([...actionOptions, { value: actionTitle, label: actionTitle }]); - - const updatedRules = getUpdatedRules( - { ...policyRule, actions: updatedActions }, - policyRule.ruleId, - rules, - ); - setPolicyRules(updatedRules); - savePolicy(updatedRules); - setHasRightsErrors(updatedActions.length === 0); - }; - - /** - * Displays the selected subjects - */ - const displaySubjects = policyRule.subject.map((s, i) => { - const subject: PolicySubject = findSubjectByPolicyRuleSubject(subjects, s); - return ( - handleRemoveSubject(i, subject)} - /> - ); - }); - - /** - * Handles the removal of subjects - */ - const handleRemoveSubject = (index: number, subject: PolicySubject): void => { - // Remove from selected list - const updatedSubjects = [...policyRule.subject]; - updatedSubjects.splice(index, 1); - - // Add to options list - setSubjectOptions((prevSubjectOptions) => [ - ...prevSubjectOptions, - { - value: subject.subjectId, - label: subject.subjectTitle, - }, - ]); - - const updatedRules = getUpdatedRules( - { ...policyRule, subject: updatedSubjects }, - policyRule.ruleId, - rules, - ); - - setPolicyRules(updatedRules); - savePolicy(updatedRules); - setHasSubjectsError(updatedSubjects.length === 0); - }; - - /** - * Handles the click on a subject in the select list. It removes the clicked element - * from the options list, and adds it to the selected subject title list. - */ - const handleClickSubjectInList = (option: string) => { - // As the input field is multiple, the onchance function uses string[], but - // we are removing the element from the options list before it is displayed, so - // it will only ever be a first value in the array. - const clickedOption = option; - - // Remove from options list - const index = subjectOptions.findIndex((o) => o.value === clickedOption); - const updatedOptions = [...subjectOptions]; - updatedOptions.splice(index, 1); - setSubjectOptions(updatedOptions); - - const updatedSubjectTitles = [...policyRule.subject, clickedOption]; - const updatedRules = getUpdatedRules( - { ...policyRule, subject: updatedSubjectTitles }, - policyRule.ruleId, - rules, - ); - setPolicyRules(updatedRules); - savePolicy(updatedRules); - setHasSubjectsError(false); - }; - - /** - * Handles the click on an action in the select list. It removes the clicked element - * from the options list, and adds it to the selected action title list. - */ - const handleClickActionInList = (option: string) => { - // As the input field is multiple, the onChange function uses string[], but - // we are removing the element from the options list before it is displayed, so - // it will only ever be a first value in the array. - const clickedOption = option; - - // Remove from options list - const index = actionOptions.findIndex((o) => o.value === clickedOption); - const updatedOptions = [...actionOptions]; - updatedOptions.splice(index, 1); - setActionOptions(updatedOptions); - - const updatedActionTitles = [...policyRule.actions, clickedOption]; - const updatedRules = getUpdatedRules( - { ...policyRule, actions: updatedActionTitles }, - policyRule.ruleId, - rules, - ); - setPolicyRules(updatedRules); - savePolicy(updatedRules); - setHasRightsErrors(false); - }; - - /** - * Updates the description of the rule - */ - const handleChangeDescription = (description: string) => { - const updatedRules = getUpdatedRules({ ...policyRule, description }, policyRule.ruleId, rules); - setPolicyRules(updatedRules); - }; - - /** - * Duplicates a resource group and all the content in it. - * - * @param resourceIndex the index of the resource group to duplicate - */ - const handleCloneResourceGroup = (resourceIndex: number) => { - const resourceGroupToDuplicate: PolicyRuleResource[] = policyRule.resources[resourceIndex]; - - // Create a deep copy of the object so the objects don't share same object reference - const deepCopiedResourceGroupToDuplicate: PolicyRuleResource[] = JSON.parse( - JSON.stringify(resourceGroupToDuplicate), - ); - - const updatedResources = [...policyRule.resources, deepCopiedResourceGroupToDuplicate]; - const updatedRules = getUpdatedRules( - { ...policyRule, resources: updatedResources }, - policyRule.ruleId, - rules, - ); - setPolicyRules(updatedRules); - savePolicy(updatedRules); - }; - - /** - * Removes a resource group and all the content in it. - * - * @param resourceIndex the index of the resource group to remove - */ - const handleDeleteResourceGroup = (resourceIndex: number) => { - const updatedResources = [...policyRule.resources]; - updatedResources.splice(resourceIndex, 1); - const updatedRules = getUpdatedRules( - { ...policyRule, resources: updatedResources }, - policyRule.ruleId, - rules, - ); - setPolicyRules(updatedRules); - savePolicy(updatedRules); - setHasResourceError(updatedResources.length === 0); - }; - - /** - * Displays the given text in a warning card - * - * @param text the text to display - */ - const displayWarningCard = (text: string) => { - return ( - -

{text}

-
- ); - }; - - /** - * Gets if there is an error in the rule card - */ - const getHasRuleError = () => { - return hasResourceError || hasRightsError || hasSubjectsError; - }; - - /** - * Gets the correct text to display for a rule with missing values - */ - const getRuleErrorText = (): string => { - const arr: string[] = []; - if (hasResourceError) arr.push(t('policy_editor.policy_rule_missing_sub_resource')); - if (hasRightsError) arr.push(t('policy_editor.policy_rule_missing_actions')); - if (hasSubjectsError) arr.push(t('policy_editor.policy_rule_missing_subjects')); - - if (arr.length === 1) { - return t('policy_editor.policy_rule_missing_1', { - ruleId: policyRule.ruleId, - missing: arr[0], - }); - } - if (arr.length === 2) { - return t('policy_editor.policy_rule_missing_2', { - ruleId: policyRule.ruleId, - missing1: arr[0], - missing2: arr[1], - }); - } - if (arr.length === 3) { - return t('policy_editor.policy_rule_missing_3', { - ruleId: policyRule.ruleId, - missing1: arr[0], - missing2: arr[1], - missing3: arr[2], - }); - } - return ''; - }; - - return ( -
- - - {t('policy_editor.rule_card_sub_resource_title')} - - {displayResources} -
- } - > - {t('policy_editor.rule_card_sub_resource_button')} - -
- {showErrors && - hasResourceError && - displayWarningCard(t('policy_editor.rule_card_sub_resource_error'))} - - - {actionOptions.length === 0 - ? t('policy_editor.rule_card_actions_select_all_selected') - : t('policy_editor.rule_card_actions_select_add')} - -
- ({ - ...option, - label: getTranslationByActionId(option.label), - }))} - onChange={(value: string) => value !== null && handleClickActionInList(value)} - disabled={actionOptions.length === 0} - error={showErrors && hasRightsError} - inputId={`selectAction-${uniqueId}`} - /> -
-
{displayActions}
- {showErrors && - hasRightsError && - displayWarningCard(t('policy_editor.rule_card_actions_error'))} - - - {subjectOptions.length === 0 - ? t('policy_editor.rule_card_subjects_select_all_selected') - : t('policy_editor.rule_card_subjects_select_add')} - -
- value !== null && handleClickSubjectInList(value)} - disabled={subjectOptions.length === 0} - error={showErrors && hasSubjectsError} - inputId={`selectSubject-${uniqueId}`} - /> -
-
{displaySubjects}
- {showErrors && - hasSubjectsError && - displayWarningCard(t('policy_editor.rule_card_subjects_error'))} -
-