From 9e70770944ff8034a3be159921022197c91bef29 Mon Sep 17 00:00:00 2001 From: Konrad-Simso Date: Mon, 4 Nov 2024 13:57:27 +0100 Subject: [PATCH] Updates from review --- frontend/language/src/nb.json | 2 +- frontend/packages/shared/src/api/mutations.ts | 2 +- frontend/packages/shared/src/mocks/mocks.ts | 9 -- .../packages/shared/src/mocks/queriesMock.ts | 3 +- frontend/packages/shared/src/types/Option.ts | 10 +- ...r.module.css => CodeListEditor.module.css} | 0 ...ditor.test.tsx => CodeListEditor.test.tsx} | 81 ++++++------- .../EditCodeList/CodeListEditor.tsx | 113 ++++++++++++++++++ .../EditCodeList/CodeListTableEditor.tsx | 74 ------------ .../EditCodeList/EditCodeList.test.tsx | 78 ++++-------- .../EditOptions/EditCodeList/EditCodeList.tsx | 6 +- .../hooks/useCodeListEditorTexts.ts | 2 +- .../utils/conversionUtils.test.ts | 44 ------- .../EditCodeList/utils/conversionUtils.ts | 38 ------ .../EditOptions/EditOptions.test.tsx | 49 +++----- .../mutations/useUpdateOptionListMutation.ts | 8 +- .../src/hooks/queries/useOptionListsQuery.ts | 10 +- .../packages/ux-editor/src/testing/mocks.tsx | 26 +++- 18 files changed, 228 insertions(+), 327 deletions(-) rename frontend/packages/ux-editor/src/components/config/editModal/EditOptions/EditCodeList/{CodeListTableEditor.module.css => CodeListEditor.module.css} (100%) rename frontend/packages/ux-editor/src/components/config/editModal/EditOptions/EditCodeList/{CodeListTableEditor.test.tsx => CodeListEditor.test.tsx} (59%) create mode 100644 frontend/packages/ux-editor/src/components/config/editModal/EditOptions/EditCodeList/CodeListEditor.tsx delete mode 100644 frontend/packages/ux-editor/src/components/config/editModal/EditOptions/EditCodeList/CodeListTableEditor.tsx delete mode 100644 frontend/packages/ux-editor/src/components/config/editModal/EditOptions/EditCodeList/utils/conversionUtils.test.ts delete mode 100644 frontend/packages/ux-editor/src/components/config/editModal/EditOptions/EditCodeList/utils/conversionUtils.ts diff --git a/frontend/language/src/nb.json b/frontend/language/src/nb.json index 14e1c144a34..59eaf73615a 100644 --- a/frontend/language/src/nb.json +++ b/frontend/language/src/nb.json @@ -1462,7 +1462,7 @@ "ux_editor.modal_properties_code_list_helper": "Velg kodeliste", "ux_editor.modal_properties_code_list_id": "Kodeliste-ID", "ux_editor.modal_properties_code_list_item_description": "Beskrivelse for alternativ {{number}}", - "ux_editor.modal_properties_code_list_item_helpText": "Hjelpetekst for alternativ {{number}}", + "ux_editor.modal_properties_code_list_item_help_text": "Hjelpetekst for alternativ {{number}}", "ux_editor.modal_properties_code_list_item_label": "Ledetekst for alternativ {{number}}", "ux_editor.modal_properties_code_list_item_value": "Verdi for alternativ {{number}}", "ux_editor.modal_properties_code_list_open_editor": "Åpne redigeringsverktøy", diff --git a/frontend/packages/shared/src/api/mutations.ts b/frontend/packages/shared/src/api/mutations.ts index 405f0b46f3a..48e721ebf0d 100644 --- a/frontend/packages/shared/src/api/mutations.ts +++ b/frontend/packages/shared/src/api/mutations.ts @@ -117,7 +117,7 @@ export const updateAppMetadata = (org: string, app: string, payload: Application export const updateAppConfig = (org: string, app: string, payload: AppConfig) => post(serviceConfigPath(org, app), payload); export const uploadDataModel = (org: string, app: string, form: FormData) => post(dataModelsUploadPath(org, app), form, { headers: { 'Content-Type': 'multipart/form-data' } }); export const uploadOptionList = (org: string, app: string, payload: FormData) => post(optionListUploadPath(org, app), payload, { headers: { 'Content-Type': 'multipart/form-data' } }); -export const updateOptionList = (org: string, app: string, optionsListId: string, payload: Option[]) => put(optionListUpdatePath(org, app, optionsListId), payload); +export const updateOptionList = (org: string, app: string, optionsListId: string, payload: Option[]) => put(optionListUpdatePath(org, app, optionsListId), payload); export const upsertTextResources = (org: string, app: string, language: string, payload: ITextResourcesObjectFormat) => put(textResourcesPath(org, app, language), payload); // Resourceadm diff --git a/frontend/packages/shared/src/mocks/mocks.ts b/frontend/packages/shared/src/mocks/mocks.ts index 1cc332ab505..380f5250760 100644 --- a/frontend/packages/shared/src/mocks/mocks.ts +++ b/frontend/packages/shared/src/mocks/mocks.ts @@ -26,7 +26,6 @@ import type { Organization } from 'app-shared/types/Organization'; import type { KubernetesDeployment } from 'app-shared/types/api/KubernetesDeployment'; import type { DeploymentsResponse } from 'app-shared/types/api/DeploymentsResponse'; import type { AppRelease } from 'app-shared/types/AppRelease'; -import type { Option } from 'app-shared/types/Option'; export const build: Build = { id: '', @@ -245,11 +244,3 @@ export const searchRepositoryResponse: SearchRepositoryResponse = { totalCount: 0, totalPages: 0, }; - -export const optionListResponse: Map = new Map([ - [ - 'key1', - [{ value: 'test', label: 'test label', description: 'description', helpText: 'help text' }], - ], - ['key2', [{ value: 'test2', label: 'test2 label' }]], -]); diff --git a/frontend/packages/shared/src/mocks/queriesMock.ts b/frontend/packages/shared/src/mocks/queriesMock.ts index 02c030c92d3..049baf027bb 100644 --- a/frontend/packages/shared/src/mocks/queriesMock.ts +++ b/frontend/packages/shared/src/mocks/queriesMock.ts @@ -52,7 +52,6 @@ import { createRepoCommitPayload, dataModelMetadataResponse, layoutSets, - optionListResponse, orgList, policy, repoStatus, @@ -106,7 +105,7 @@ export const queriesMock: ServicesContextProps = { getOptionListIds: jest.fn().mockImplementation(() => Promise.resolve([])), getOptionLists: jest .fn() - .mockImplementation(() => Promise.resolve>(optionListResponse)), + .mockImplementation(() => Promise.resolve>(new Map())), getOrgList: jest.fn().mockImplementation(() => Promise.resolve(orgList)), getOrganizations: jest.fn().mockImplementation(() => Promise.resolve([])), getRepoMetadata: jest.fn().mockImplementation(() => Promise.resolve(repository)), diff --git a/frontend/packages/shared/src/types/Option.ts b/frontend/packages/shared/src/types/Option.ts index 73cb228f2aa..2c9dc559281 100644 --- a/frontend/packages/shared/src/types/Option.ts +++ b/frontend/packages/shared/src/types/Option.ts @@ -1,6 +1,4 @@ -export type Option = { - label: string; - value: T; - description?: string; - helpText?: string; -}; +import type { CodeListItem } from '@studio/components'; + +export type Option = + CodeListItem; diff --git a/frontend/packages/ux-editor/src/components/config/editModal/EditOptions/EditCodeList/CodeListTableEditor.module.css b/frontend/packages/ux-editor/src/components/config/editModal/EditOptions/EditCodeList/CodeListEditor.module.css similarity index 100% rename from frontend/packages/ux-editor/src/components/config/editModal/EditOptions/EditCodeList/CodeListTableEditor.module.css rename to frontend/packages/ux-editor/src/components/config/editModal/EditOptions/EditCodeList/CodeListEditor.module.css diff --git a/frontend/packages/ux-editor/src/components/config/editModal/EditOptions/EditCodeList/CodeListTableEditor.test.tsx b/frontend/packages/ux-editor/src/components/config/editModal/EditOptions/EditCodeList/CodeListEditor.test.tsx similarity index 59% rename from frontend/packages/ux-editor/src/components/config/editModal/EditOptions/EditCodeList/CodeListTableEditor.test.tsx rename to frontend/packages/ux-editor/src/components/config/editModal/EditOptions/EditCodeList/CodeListEditor.test.tsx index 5de87f462c7..dd79334623f 100644 --- a/frontend/packages/ux-editor/src/components/config/editModal/EditOptions/EditCodeList/CodeListTableEditor.test.tsx +++ b/frontend/packages/ux-editor/src/components/config/editModal/EditOptions/EditCodeList/CodeListEditor.test.tsx @@ -1,34 +1,34 @@ import React from 'react'; -import { render, screen } from '@testing-library/react'; +import { screen, waitForElementToBeRemoved } from '@testing-library/react'; import { ComponentType } from 'app-shared/types/ComponentType'; import type { FormComponent } from '../../../../../types/FormComponent'; import { createQueryClientMock } from 'app-shared/mocks/queryClientMock'; -import { - type ServicesContextProps, - ServicesContextProvider, -} from 'app-shared/contexts/ServicesContext'; -import { CodeListTableEditor } from './CodeListTableEditor'; +import { CodeListEditor } from './CodeListEditor'; import { textMock } from '@studio/testing/mocks/i18nMock'; -import { PreviewContext, type PreviewContextProps } from 'app-development/contexts/PreviewContext'; -import { queriesMock } from 'app-shared/mocks/queriesMock'; import userEvent, { type UserEvent } from '@testing-library/user-event'; +import { componentMocks } from '@altinn/ux-editor/testing/componentMocks'; +import type { Option } from 'app-shared/types/Option'; +import { renderWithProviders } from '@altinn/ux-editor/testing/mocks'; // Test data: -const mockComponent: FormComponent = { - id: 'c24d0812-0c34-4582-8f31-ff4ce9795e96', - type: ComponentType.Dropdown, - itemType: 'COMPONENT', - dataModelBindings: { simpleBinding: 'some-path' }, - optionsId: 'test', +const mockComponent: FormComponent = componentMocks[ComponentType.Dropdown]; +mockComponent.optionsId = 'test'; + +const optionsList = new Map([ + [ + 'text', + [{ value: 'test', label: 'label text', description: 'description', helpText: 'help text' }], + ], + ['number', [{ value: 2, label: 'label number' }]], + ['boolean', [{ value: true, label: 'label boolean' }]], +]); +const queriesMock = { + getOptionLists: jest + .fn() + .mockImplementation(() => Promise.resolve>(optionsList)), }; - -const defaultPreviewContextProps: PreviewContextProps = { - shouldReloadPreview: false, - doReloadPreview: jest.fn(), - previewHasLoaded: jest.fn(), -}; - const queryClientMock = createQueryClientMock(); + describe('CodeListTableEditor', () => { afterEach(() => { queryClientMock.clear(); @@ -38,7 +38,7 @@ describe('CodeListTableEditor', () => { await renderCodeListTableEditor(); expect( - await screen.findByRole('button', { + screen.getByRole('button', { name: textMock('ux_editor.modal_properties_code_list_open_editor'), }), ).toBeInTheDocument(); @@ -76,32 +76,25 @@ describe('CodeListTableEditor', () => { }); const openModal = async (user: UserEvent) => { - const btnOpen = await screen.findByRole('button', { + const btnOpen = screen.getByRole('button', { name: textMock('ux_editor.modal_properties_code_list_open_editor'), }); await user.click(btnOpen); }; -const renderCodeListTableEditor = async ({ - queries = {}, - previewContextProps = {}, - componentProps = {}, -} = {}) => { - const allQueries: ServicesContextProps = { - ...queries, - ...queriesMock, - }; - - return render( - - - - - , +const renderCodeListTableEditor = async ({ previewContextProps = {} } = {}) => { + const view = renderWithProviders( + , + { + queries: queriesMock, + queryClient: queryClientMock, + previewContextProps: previewContextProps, + }, ); + await waitForElementToBeRemoved(screen.queryByTestId('studio-spinner-test-id')); + return view; }; diff --git a/frontend/packages/ux-editor/src/components/config/editModal/EditOptions/EditCodeList/CodeListEditor.tsx b/frontend/packages/ux-editor/src/components/config/editModal/EditOptions/EditCodeList/CodeListEditor.tsx new file mode 100644 index 00000000000..8050daacdb1 --- /dev/null +++ b/frontend/packages/ux-editor/src/components/config/editModal/EditOptions/EditCodeList/CodeListEditor.tsx @@ -0,0 +1,113 @@ +import React, { createRef, useEffect, useState } from 'react'; +import type { IGenericEditComponent } from '@altinn/ux-editor/components/config/componentConfig'; +import type { SelectionComponentType } from '@altinn/ux-editor/types/FormComponent'; +import type { Option } from 'app-shared/types/Option'; +import type { ApiError } from 'app-shared/types/api/ApiError'; +import type { AxiosError } from 'axios'; +import { useTranslation } from 'react-i18next'; +import { + StudioCodeListEditor, + StudioModal, + StudioSpinner, + type CodeList, +} from '@studio/components'; +import { TableIcon } from '@studio/icons'; +import { useStudioEnvironmentParams } from 'app-shared/hooks/useStudioEnvironmentParams'; +import { useUpdateOptionListMutation } from '../../../../../hooks/mutations/useUpdateOptionListMutation'; +import { useOptionListsQuery } from '../../../../../hooks/queries/useOptionListsQuery'; +import { useCodeListEditorTexts } from './hooks/useCodeListEditorTexts'; +import { usePreviewContext } from 'app-development/contexts/PreviewContext'; +import { ErrorMessage } from '@digdir/designsystemet-react'; +import classes from './CodeListEditor.module.css'; + +type CodeListEditorProps = Pick, 'component'>; + +export function CodeListEditor({ component }: CodeListEditorProps): React.ReactNode { + const { t } = useTranslation(); + const { org, app } = useStudioEnvironmentParams(); + const { data: optionsListMap, status, error } = useOptionListsQuery(org, app); + const [codeList, setCodeList] = useState([]); + + useEffect(() => { + if (status === 'pending') return; + handleOptionsChange(optionsListMap[component.optionsId]); + }, [optionsListMap, component.optionsId, status]); + + const handleOptionsChange = (options?: Option[]) => { + if (options === undefined) return; + setCodeList(options); + }; + + if (component.optionsId === undefined) return ; + switch (status) { + case 'pending': + return ; // Extract title to nb.json + case 'error': + return ( + + {error instanceof Error ? error.message : t('ux_editor.modal_properties_error_message')} + + ); + case 'success': { + return ( + + ); + } + } +} + +type CodeListEditorModalProps = { + codeList: CodeList; + handleOptionsChange: (options?: Option[]) => void; +} & Pick, 'component'>; + +function CodeListEditorModal({ + codeList, + component, + handleOptionsChange, +}: CodeListEditorModalProps): React.ReactNode { + const { t } = useTranslation(); + const { org, app } = useStudioEnvironmentParams(); + const { doReloadPreview } = usePreviewContext(); + const { mutate: uploadOptionList } = useUpdateOptionListMutation(org, app, { + hideDefaultError: (apiError: AxiosError) => !apiError.response.data.errorCode, + }); + const editorTexts = useCodeListEditorTexts(); + const modalRef = createRef(); + + const handleClose = () => { + uploadOptionList({ optionListId: component.optionsId, optionsList: codeList }); + doReloadPreview(); + modalRef.current?.close(); + }; + + return ( + + } + > + {t('ux_editor.modal_properties_code_list_open_editor')} + + + + + + ); +} diff --git a/frontend/packages/ux-editor/src/components/config/editModal/EditOptions/EditCodeList/CodeListTableEditor.tsx b/frontend/packages/ux-editor/src/components/config/editModal/EditOptions/EditCodeList/CodeListTableEditor.tsx deleted file mode 100644 index 7a287975c32..00000000000 --- a/frontend/packages/ux-editor/src/components/config/editModal/EditOptions/EditCodeList/CodeListTableEditor.tsx +++ /dev/null @@ -1,74 +0,0 @@ -import React, { useEffect, useState } from 'react'; -import type { IGenericEditComponent } from '@altinn/ux-editor/components/config/componentConfig'; -import type { SelectionComponentType } from '@altinn/ux-editor/types/FormComponent'; -import type { CodeListItem } from '@studio/components'; -import type { Option } from 'app-shared/types/Option'; -import { useTranslation } from 'react-i18next'; -import { StudioCodeListEditor, StudioModal } from '@studio/components'; -import { TableIcon } from '@studio/icons'; -import { useStudioEnvironmentParams } from 'app-shared/hooks/useStudioEnvironmentParams'; -import { useUpdateOptionListMutation } from '../../../../../hooks/mutations/useUpdateOptionListMutation'; -import { useOptionListsQuery } from '../../../../../hooks/queries/useOptionListsQuery'; -import { - convertCodeListItemListToOptionsList, - convertOptionsListToCodeListItemList, -} from './utils/conversionUtils'; -import { useCodeListEditorTexts } from './hooks/useCodeListEditorTexts'; -import { usePreviewContext } from 'app-development/contexts/PreviewContext'; -import classes from './CodeListTableEditor.module.css'; - -type CodeListTableEditorProps = Pick, 'component'>; - -export function CodeListTableEditor({ component }: CodeListTableEditorProps): React.ReactNode { - const { t } = useTranslation(); - const { org, app } = useStudioEnvironmentParams(); - const { doReloadPreview } = usePreviewContext(); - const { data: optionsListMap, isFetching } = useOptionListsQuery(org, app); - const { mutate: uploadOptionList } = useUpdateOptionListMutation(org, app, { - hideDefaultError: true, - }); - const [codeListItemList, setCodeListItemList] = useState([]); - const editorTexts = useCodeListEditorTexts(); - - useEffect(() => { - if (isFetching) return; - handleOptionsChange(optionsListMap[component.optionsId]); - }, [optionsListMap, component.optionsId, isFetching]); - - const handleOptionsChange = (options: Option[]) => { - const convertedList = convertOptionsListToCodeListItemList(options); - setCodeListItemList(convertedList); - }; - - const handleClose = () => { - const optionsListLocal = convertCodeListItemListToOptionsList(codeListItemList); - uploadOptionList({ optionListId: component.optionsId, optionsList: optionsListLocal }); - doReloadPreview(); - }; - - if (component.optionsId === undefined || component.optionsId === '' || isFetching) return; - return ( - - } - > - {t('ux_editor.modal_properties_code_list_open_editor')} - - - - - - ); -} diff --git a/frontend/packages/ux-editor/src/components/config/editModal/EditOptions/EditCodeList/EditCodeList.test.tsx b/frontend/packages/ux-editor/src/components/config/editModal/EditOptions/EditCodeList/EditCodeList.test.tsx index 4cefdd00a04..bbfee20279b 100644 --- a/frontend/packages/ux-editor/src/components/config/editModal/EditOptions/EditCodeList/EditCodeList.test.tsx +++ b/frontend/packages/ux-editor/src/components/config/editModal/EditOptions/EditCodeList/EditCodeList.test.tsx @@ -1,36 +1,22 @@ import React from 'react'; import { EditCodeList } from './EditCodeList'; -import { render, screen, waitFor } from '@testing-library/react'; +import { screen, waitFor } from '@testing-library/react'; import { ComponentType } from 'app-shared/types/ComponentType'; -import { optionListIdsMock } from '../../../../../testing/mocks'; +import { optionListIdsMock, renderWithProviders } from '../../../../../testing/mocks'; import userEvent, { type UserEvent } from '@testing-library/user-event'; import { textMock } from '@studio/testing/mocks/i18nMock'; import { createQueryClientMock } from 'app-shared/mocks/queryClientMock'; import type { FormComponent } from '../../../../../types/FormComponent'; -import { - type ServicesContextProps, - ServicesContextProvider, -} from 'app-shared/contexts/ServicesContext'; -import { queriesMock } from 'app-shared/mocks/queriesMock'; -import { PreviewContext, type PreviewContextProps } from 'app-development/contexts/PreviewContext'; +import { componentMocks } from '@altinn/ux-editor/testing/componentMocks'; // Test data: -const mockComponent: FormComponent = { - id: 'c24d0812-0c34-4582-8f31-ff4ce9795e96', - type: ComponentType.Dropdown, - textResourceBindings: { - title: 'ServiceName', - }, - itemType: 'COMPONENT', - dataModelBindings: { simpleBinding: 'some-path' }, +const mockComponent: FormComponent = componentMocks[ComponentType.Dropdown]; +const handleComponentChangeMock = jest.fn(); +const queriesMock = { + getOptionListIds: jest + .fn() + .mockImplementation(() => Promise.resolve(optionListIdsMock)), }; - -const defaultPreviewContextProps: PreviewContextProps = { - shouldReloadPreview: false, - doReloadPreview: jest.fn(), - previewHasLoaded: jest.fn(), -}; - const queryClientMock = createQueryClientMock(); describe('EditCodeList', () => { @@ -46,11 +32,8 @@ describe('EditCodeList', () => { }); it('should call onChange when option list changes', async () => { - const handleComponentChangeMock = jest.fn(); const user = userEvent.setup(); - renderEditCodeList({ - handleComponentChange: handleComponentChangeMock, - }); + renderEditCodeList(); await waitFor(() => screen.findByRole('combobox')); @@ -59,10 +42,8 @@ describe('EditCodeList', () => { }); it('should remove options property (if it exists) when optionsId property changes', async () => { - const handleComponentChangeMock = jest.fn(); const user = userEvent.setup(); renderEditCodeList({ - handleComponentChange: handleComponentChangeMock, componentProps: { options: [{ label: 'option1', value: 'option1' }], }, @@ -170,31 +151,18 @@ const userFindFileAndUpload = async (user: UserEvent, file: File) => { await user.upload(fileInput, file); }; -const renderEditCodeList = ({ - handleComponentChange = jest.fn(), - queries = { - getOptionListIds: jest - .fn() - .mockImplementation(() => Promise.resolve(optionListIdsMock)), - }, - componentProps = {}, -} = {}) => { - const allQueries: ServicesContextProps = { - ...queriesMock, - ...queries, - }; - - return render( - - - - - , +const renderEditCodeList = ({ queries = queriesMock, componentProps = {} } = {}) => { + return renderWithProviders( + , + { + queries: queries, + queryClient: queryClientMock, + }, ); }; diff --git a/frontend/packages/ux-editor/src/components/config/editModal/EditOptions/EditCodeList/EditCodeList.tsx b/frontend/packages/ux-editor/src/components/config/editModal/EditOptions/EditCodeList/EditCodeList.tsx index 7575017d4b0..86e3762dc32 100644 --- a/frontend/packages/ux-editor/src/components/config/editModal/EditOptions/EditCodeList/EditCodeList.tsx +++ b/frontend/packages/ux-editor/src/components/config/editModal/EditOptions/EditCodeList/EditCodeList.tsx @@ -16,7 +16,7 @@ import type { AxiosError } from 'axios'; import type { ApiError } from 'app-shared/types/api/ApiError'; import { toast } from 'react-toastify'; import classes from './EditCodeList.module.css'; -import { CodeListTableEditor } from './CodeListTableEditor'; +import { CodeListEditor } from './CodeListEditor'; import { shouldDisplayFeature } from 'app-shared/utils/featureToggleUtils'; export function EditCodeList({ @@ -27,7 +27,7 @@ export function EditCodeList({ const { org, app } = useStudioEnvironmentParams(); const { data: optionListIds } = useOptionListIdsQuery(org, app); const { mutate: uploadOptionList } = useAddOptionListMutation(org, app, { - hideDefaultError: true, + hideDefaultError: (error: AxiosError) => !error.response.data.errorCode, }); const handleOptionsIdChange = (optionsId: string) => { @@ -76,7 +76,7 @@ export function EditCodeList({ return ( <> - {shouldDisplayFeature('codeListEditor') && } + {shouldDisplayFeature('codeListEditor') && } { helpText: t('ux_editor.options_text_help_text'), itemDescription: (number) => t('ux_editor.modal_properties_code_list_item_description', { number }), - itemHelpText: (number) => t('ux_editor.modal_properties_code_list_item_helpText', { number }), + itemHelpText: (number) => t('ux_editor.modal_properties_code_list_item_help_text', { number }), itemLabel: (number) => t('ux_editor.modal_properties_code_list_item_label', { number }), itemValue: (number) => t('ux_editor.modal_properties_code_list_item_value', { number }), label: t('ux_editor.options_text_label'), diff --git a/frontend/packages/ux-editor/src/components/config/editModal/EditOptions/EditCodeList/utils/conversionUtils.test.ts b/frontend/packages/ux-editor/src/components/config/editModal/EditOptions/EditCodeList/utils/conversionUtils.test.ts deleted file mode 100644 index d09ee78f384..00000000000 --- a/frontend/packages/ux-editor/src/components/config/editModal/EditOptions/EditCodeList/utils/conversionUtils.test.ts +++ /dev/null @@ -1,44 +0,0 @@ -import type { Option } from 'app-shared/types/Option'; -import type { CodeListItem } from '@studio/components'; -import { - convertOptionsListToCodeListItemList, - convertCodeListItemListToOptionsList, -} from './conversionUtils'; - -// Test data: -const optionsList: Option[] = [ - { value: 'test', label: 'test label', description: 'description', helpText: 'help text' }, -]; -const codeListItemList: CodeListItem[] = [ - { value: 'test', label: 'test label', description: 'description', helpText: 'help text' }, -]; - -describe('conversionUtils', () => { - describe('convertOptionsListToCodeListItem', () => { - it('should return empty list if input is undefined', () => { - expect(convertOptionsListToCodeListItemList(undefined)).toEqual([]); - }); - - it('should return empty list if input is an empty list', () => { - expect(convertOptionsListToCodeListItemList([])).toEqual([]); - }); - - it('should return converted list', () => { - expect(convertOptionsListToCodeListItemList(optionsList)).toStrictEqual(codeListItemList); - }); - }); - - describe('convertCodeListItemListToOptionsList', () => { - it('should return empty list if input is undefined', () => { - expect(convertCodeListItemListToOptionsList(undefined)).toEqual([]); - }); - - it('should return empty list if input is an empty list', () => { - expect(convertCodeListItemListToOptionsList([])).toEqual([]); - }); - - it('should return converted list', () => { - expect(convertCodeListItemListToOptionsList(codeListItemList)).toStrictEqual(optionsList); - }); - }); -}); diff --git a/frontend/packages/ux-editor/src/components/config/editModal/EditOptions/EditCodeList/utils/conversionUtils.ts b/frontend/packages/ux-editor/src/components/config/editModal/EditOptions/EditCodeList/utils/conversionUtils.ts deleted file mode 100644 index bceebcd8a21..00000000000 --- a/frontend/packages/ux-editor/src/components/config/editModal/EditOptions/EditCodeList/utils/conversionUtils.ts +++ /dev/null @@ -1,38 +0,0 @@ -import type { Option } from 'app-shared/types/Option'; -import type { CodeListItem } from '@studio/components'; - -export const convertOptionsListToCodeListItemList = (optionList: Option[]): CodeListItem[] => { - if (optionList === undefined) return []; - - const tempList: CodeListItem[] = []; - if (optionList.length === 0) return tempList; - - optionList.forEach((option: Option) => { - tempList.push({ - label: option.label, - value: option.value, - description: option.description ?? '', - helpText: option.helpText ?? '', - }); - }); - return tempList; -}; - -export const convertCodeListItemListToOptionsList = ( - codeListItemList: CodeListItem[], -): Option[] => { - if (codeListItemList === undefined) return []; - - const tempList: Option[] = []; - if (codeListItemList.length === 0) return tempList; - - codeListItemList.forEach((codeListItem: CodeListItem) => { - tempList.push({ - label: codeListItem.label, - value: codeListItem.value, - description: codeListItem.description ?? '', - helpText: codeListItem.helpText ?? '', - }); - }); - return tempList; -}; diff --git a/frontend/packages/ux-editor/src/components/config/editModal/EditOptions/EditOptions.test.tsx b/frontend/packages/ux-editor/src/components/config/editModal/EditOptions/EditOptions.test.tsx index 65c00264a2b..0b4c9606068 100644 --- a/frontend/packages/ux-editor/src/components/config/editModal/EditOptions/EditOptions.test.tsx +++ b/frontend/packages/ux-editor/src/components/config/editModal/EditOptions/EditOptions.test.tsx @@ -1,18 +1,14 @@ import React from 'react'; -import { render, screen, waitFor } from '@testing-library/react'; +import { screen, waitFor } from '@testing-library/react'; import { EditOptions } from './EditOptions'; import { textMock } from '@studio/testing/mocks/i18nMock'; import { ComponentType } from 'app-shared/types/ComponentType'; import type { FormComponent } from '../../../../types/FormComponent'; import type { FormItem } from '../../../../types/FormItem'; -import { - type ServicesContextProps, - ServicesContextProvider, -} from 'app-shared/contexts/ServicesContext'; +import type { ServicesContextProps } from 'app-shared/contexts/ServicesContext'; import { createQueryClientMock } from 'app-shared/mocks/queryClientMock'; import userEvent from '@testing-library/user-event'; -import { queriesMock } from 'app-shared/mocks/queriesMock'; -import { PreviewContext, type PreviewContextProps } from 'app-development/contexts/PreviewContext'; +import { renderWithProviders } from '@altinn/ux-editor/testing/mocks'; const mockComponent: FormComponent = { id: 'c24d0812-0c34-4582-8f31-ff4ce9795e96', @@ -25,12 +21,6 @@ const mockComponent: FormComponent = { dataModelBindings: { simpleBinding: '' }, }; -const defaultPreviewContextProps: PreviewContextProps = { - shouldReloadPreview: false, - doReloadPreview: jest.fn(), - previewHasLoaded: jest.fn(), -}; - const queryClientMock = createQueryClientMock(); const renderEditOptions = async ({ @@ -46,26 +36,19 @@ const renderEditOptions = async { - const component = { - ...mockComponent, - ...componentProps, - }; - const allQueries = { - ...queriesMock, - ...queries, - }; - - render( - - - - , - - , + return renderWithProviders( + , + { + queries: queries, + queryClient: queryClientMock, + }, ); }; diff --git a/frontend/packages/ux-editor/src/hooks/mutations/useUpdateOptionListMutation.ts b/frontend/packages/ux-editor/src/hooks/mutations/useUpdateOptionListMutation.ts index 031a7ef9b9b..4bd37894dda 100644 --- a/frontend/packages/ux-editor/src/hooks/mutations/useUpdateOptionListMutation.ts +++ b/frontend/packages/ux-editor/src/hooks/mutations/useUpdateOptionListMutation.ts @@ -17,11 +17,9 @@ export const useUpdateOptionListMutation = (org: string, app: string, meta?: Mut mutationFn: ({ optionListId, optionsList }: UpdateOptionListMutationArgs) => { return updateOptionList(org, app, optionListId, optionsList); }, - onSuccess: async () => { - await Promise.all([ - queryClient.invalidateQueries({ queryKey: [QueryKey.OptionListIds, org, app] }), - queryClient.invalidateQueries({ queryKey: [QueryKey.OptionLists, org, app] }), - ]); + onSuccess: () => { + queryClient.invalidateQueries({ queryKey: [QueryKey.OptionListIds, org, app] }); + queryClient.invalidateQueries({ queryKey: [QueryKey.OptionLists, org, app] }); }, meta, }); diff --git a/frontend/packages/ux-editor/src/hooks/queries/useOptionListsQuery.ts b/frontend/packages/ux-editor/src/hooks/queries/useOptionListsQuery.ts index 473c41213b4..e0992110b80 100644 --- a/frontend/packages/ux-editor/src/hooks/queries/useOptionListsQuery.ts +++ b/frontend/packages/ux-editor/src/hooks/queries/useOptionListsQuery.ts @@ -9,16 +9,8 @@ export const useOptionListsQuery = ( app: string, ): UseQueryResult> => { const { getOptionLists } = useServicesContext(); - return useQuery({ queryKey: [QueryKey.OptionLists, org, app], - queryFn: () => - getOptionLists(org, app).then((result) => { - const optionLists = {}; - Object.keys(result).forEach((optionListId) => { - optionLists[optionListId] = result[optionListId]; - }); - return optionLists; - }), + queryFn: () => getOptionLists(org, app).then((result) => result || new Map()), }); }; diff --git a/frontend/packages/ux-editor/src/testing/mocks.tsx b/frontend/packages/ux-editor/src/testing/mocks.tsx index fa28801059f..412ab2caf20 100644 --- a/frontend/packages/ux-editor/src/testing/mocks.tsx +++ b/frontend/packages/ux-editor/src/testing/mocks.tsx @@ -14,6 +14,7 @@ import type { AppContextProps } from '../AppContext'; import { AppContext } from '../AppContext'; import { appContextMock } from './appContextMock'; import { queryClientMock } from 'app-shared/mocks/queryClientMock'; +import { PreviewContext, type PreviewContextProps } from 'app-development/contexts/PreviewContext'; export const formLayoutSettingsMock: ILayoutSettings = { pages: { @@ -25,23 +26,35 @@ export const textLanguagesMock = ['nb', 'nn', 'en']; export const optionListIdsMock: string[] = ['test-1', 'test-2']; +const defaultPreviewContextProps: PreviewContextProps = { + shouldReloadPreview: false, + doReloadPreview: jest.fn(), + previewHasLoaded: jest.fn(), +}; + type WrapperArgs = { queries: Partial; queryClient: QueryClient; appContextProps: Partial; + previewContextProps?: Partial; }; const wrapper = ({ queries = {}, queryClient = queryClientMock, appContextProps = {}, + previewContextProps = {}, }: WrapperArgs) => { const renderComponent = (component: ReactNode) => ( - {component} + + {component} + @@ -54,11 +67,17 @@ export interface ExtendedRenderOptions extends Omit { queries?: Partial; queryClient?: QueryClient; appContextProps?: Partial; + previewContextProps?: Partial; } export const renderHookWithProviders = ( hook: () => any, - { queries = {}, queryClient = queryClientMock, appContextProps = {} }: ExtendedRenderOptions = {}, + { + queries = {}, + queryClient = queryClientMock, + appContextProps = {}, + previewContextProps = {}, + }: ExtendedRenderOptions = {}, ) => { return renderHook(hook, { wrapper: ({ children }) => @@ -66,6 +85,7 @@ export const renderHookWithProviders = ( queries, queryClient, appContextProps, + previewContextProps, })(children), }); }; @@ -76,6 +96,7 @@ export const renderWithProviders = ( queries = {}, queryClient = queryClientMock, appContextProps = {}, + previewContextProps = {}, ...renderOptions }: Partial = {}, ) => { @@ -86,6 +107,7 @@ export const renderWithProviders = ( queries, queryClient, appContextProps, + previewContextProps, })(children), ...renderOptions, }),