diff --git a/frontend/app-development/features/appContentLibrary/AppContentLibrary.test.tsx b/frontend/app-development/features/appContentLibrary/AppContentLibrary.test.tsx index 2ab2d32e1af..c3537873930 100644 --- a/frontend/app-development/features/appContentLibrary/AppContentLibrary.test.tsx +++ b/frontend/app-development/features/appContentLibrary/AppContentLibrary.test.tsx @@ -63,7 +63,7 @@ describe('AppContentLibrary', () => { }); it('renders a spinner when waiting for option lists', () => { - renderAppContentLibrary({ optionListsData: [] }); + renderAppContentLibrary({ shouldPutDataOnCache: false }); const spinner = screen.getByText(textMock('general.loading')); expect(spinner).toBeInTheDocument(); }); @@ -146,16 +146,19 @@ const goToLibraryPage = async (user: UserEvent, libraryPage: string) => { type renderAppContentLibraryProps = { queries?: Partial; + shouldPutDataOnCache?: boolean; optionListsData?: OptionsListsResponse; }; const renderAppContentLibrary = ({ queries = {}, + shouldPutDataOnCache = true, optionListsData = optionListsDataMock, }: renderAppContentLibraryProps = {}) => { const queryClientMock = createQueryClientMock(); - if (optionListsData.length) { + if (shouldPutDataOnCache) { queryClientMock.setQueryData([QueryKey.OptionLists, org, app], optionListsData); + queryClientMock.setQueryData([QueryKey.OptionListsUsage, org, app], []); } renderWithProviders(queries, queryClientMock)(); }; diff --git a/frontend/app-development/features/appContentLibrary/AppContentLibrary.tsx b/frontend/app-development/features/appContentLibrary/AppContentLibrary.tsx index c7ce3b9d4d1..92f65b621d1 100644 --- a/frontend/app-development/features/appContentLibrary/AppContentLibrary.tsx +++ b/frontend/app-development/features/appContentLibrary/AppContentLibrary.tsx @@ -1,7 +1,7 @@ -import type { CodeListWithMetadata } from '@studio/content-library'; +import type { CodeListReference, CodeListWithMetadata } from '@studio/content-library'; import { ResourceContentLibraryImpl } from '@studio/content-library'; import React from 'react'; -import { useOptionListsQuery } from 'app-shared/hooks/queries'; +import { useOptionListsQuery, useOptionListsReferencesQuery } from 'app-shared/hooks/queries'; import { useStudioEnvironmentParams } from 'app-shared/hooks/useStudioEnvironmentParams'; import { convertOptionsListsDataToCodeListsData } from './utils/convertOptionsListsDataToCodeListsData'; import { StudioPageSpinner } from '@studio/components'; @@ -15,6 +15,7 @@ import { useUpdateOptionListMutation, useUpdateOptionListIdMutation, } from 'app-shared/hooks/mutations'; +import { mapToCodeListsUsage } from './utils/mapToCodeListsUsage'; export function AppContentLibrary(): React.ReactElement { const { org, app } = useStudioEnvironmentParams(); @@ -28,12 +29,16 @@ export function AppContentLibrary(): React.ReactElement { }); const { mutate: updateOptionList } = useUpdateOptionListMutation(org, app); const { mutate: updateOptionListId } = useUpdateOptionListIdMutation(org, app); + const { data: optionListsUsages, isPending: optionListsUsageIsPending } = + useOptionListsReferencesQuery(org, app); - if (optionListsDataPending) + if (optionListsDataPending || optionListsUsageIsPending) return ; const codeListsData = convertOptionsListsDataToCodeListsData(optionListsData); + const codeListsUsages: CodeListReference[] = mapToCodeListsUsage({ optionListsUsages }); + const handleUpdateCodeListId = (optionListId: string, newOptionListId: string) => { updateOptionListId({ optionListId, newOptionListId }); }; @@ -63,6 +68,7 @@ export function AppContentLibrary(): React.ReactElement { onUpdateCodeListId: handleUpdateCodeListId, onUpdateCodeList: handleUpdate, onUploadCodeList: handleUpload, + codeListsUsages, }, }, images: { diff --git a/frontend/app-development/features/appContentLibrary/utils/mapToCodeListsUsage.test.ts b/frontend/app-development/features/appContentLibrary/utils/mapToCodeListsUsage.test.ts new file mode 100644 index 00000000000..1be4ee745d7 --- /dev/null +++ b/frontend/app-development/features/appContentLibrary/utils/mapToCodeListsUsage.test.ts @@ -0,0 +1,35 @@ +import type { CodeListIdSource } from '@studio/content-library'; +import { mapToCodeListsUsage } from './mapToCodeListsUsage'; +import type { OptionListsReferences } from 'app-shared/types/api/OptionsLists'; + +const optionListId: string = 'optionListId'; +const optionListIdSources: CodeListIdSource[] = [ + { + layoutSetId: 'layoutSetId', + layoutName: 'layoutName', + componentIds: ['componentId1', 'componentId2'], + }, +]; +const optionListsUsages: OptionListsReferences = [ + { + optionListId, + optionListIdSources, + }, +]; + +describe('mapToCodeListsUsage', () => { + it('maps optionListsUsage to codeListUsage', () => { + const codeListUsage = mapToCodeListsUsage({ optionListsUsages }); + expect(codeListUsage).toEqual([ + { + codeListId: optionListId, + codeListIdSources: optionListIdSources, + }, + ]); + }); + + it('maps undefined optionListsUsage to empty array', () => { + const codeListUsage = mapToCodeListsUsage({ optionListsUsages: undefined }); + expect(codeListUsage).toEqual([]); + }); +}); diff --git a/frontend/app-development/features/appContentLibrary/utils/mapToCodeListsUsage.ts b/frontend/app-development/features/appContentLibrary/utils/mapToCodeListsUsage.ts new file mode 100644 index 00000000000..51b13cb1e95 --- /dev/null +++ b/frontend/app-development/features/appContentLibrary/utils/mapToCodeListsUsage.ts @@ -0,0 +1,20 @@ +import type { OptionListsReferences } from 'app-shared/types/api/OptionsLists'; +import type { CodeListReference } from '@studio/content-library'; + +type MapToCodeListsUsageProps = { + optionListsUsages: OptionListsReferences; +}; + +export const mapToCodeListsUsage = ({ + optionListsUsages, +}: MapToCodeListsUsageProps): CodeListReference[] => { + const codeListsUsages: CodeListReference[] = []; + if (!optionListsUsages) return codeListsUsages; + optionListsUsages.map((optionListsUsage) => + codeListsUsages.push({ + codeListId: optionListsUsage.optionListId, + codeListIdSources: optionListsUsage.optionListIdSources, + }), + ); + return codeListsUsages; +}; diff --git a/frontend/libs/studio-content-library/mocks/mockPagesConfig.ts b/frontend/libs/studio-content-library/mocks/mockPagesConfig.ts index f600db463bd..678f509b8ee 100644 --- a/frontend/libs/studio-content-library/mocks/mockPagesConfig.ts +++ b/frontend/libs/studio-content-library/mocks/mockPagesConfig.ts @@ -15,6 +15,7 @@ export const mockPagesConfig: PagesConfig = { onUpdateCodeListId: () => {}, onUpdateCodeList: () => {}, onUploadCodeList: () => {}, + codeListsUsages: [], }, }, images: { diff --git a/frontend/libs/studio-content-library/src/ContentLibrary/LibraryBody/pages/CodeListPage/CodeListPage.test.tsx b/frontend/libs/studio-content-library/src/ContentLibrary/LibraryBody/pages/CodeListPage/CodeListPage.test.tsx index 0566b6bf598..e02e6d3ced9 100644 --- a/frontend/libs/studio-content-library/src/ContentLibrary/LibraryBody/pages/CodeListPage/CodeListPage.test.tsx +++ b/frontend/libs/studio-content-library/src/ContentLibrary/LibraryBody/pages/CodeListPage/CodeListPage.test.tsx @@ -154,6 +154,7 @@ const defaultCodeListPageProps: CodeListPageProps = { onUpdateCodeListId: onUpdateCodeListIdMock, onUpdateCodeList: onUpdateCodeListMock, onUploadCodeList: onUploadCodeListMock, + codeListsUsages: [], }; const renderCodeListPage = (props: Partial = {}) => { diff --git a/frontend/libs/studio-content-library/src/ContentLibrary/LibraryBody/pages/CodeListPage/CodeListPage.tsx b/frontend/libs/studio-content-library/src/ContentLibrary/LibraryBody/pages/CodeListPage/CodeListPage.tsx index d8350981b89..9c93970f191 100644 --- a/frontend/libs/studio-content-library/src/ContentLibrary/LibraryBody/pages/CodeListPage/CodeListPage.tsx +++ b/frontend/libs/studio-content-library/src/ContentLibrary/LibraryBody/pages/CodeListPage/CodeListPage.tsx @@ -7,6 +7,7 @@ import { CodeLists } from './CodeLists'; import { CodeListsCounterMessage } from './CodeListsCounterMessage'; import classes from './CodeListPage.module.css'; import { ArrayUtils, FileNameUtils } from '@studio/pure-functions'; +import type { CodeListReference } from './types/CodeListReference'; export type CodeListWithMetadata = { codeList: CodeList; @@ -24,6 +25,7 @@ export type CodeListPageProps = { onUpdateCodeListId: (codeListId: string, newCodeListId: string) => void; onUpdateCodeList: (updatedCodeList: CodeListWithMetadata) => void; onUploadCodeList: (uploadedCodeList: File) => void; + codeListsUsages: CodeListReference[]; }; export function CodeListPage({ @@ -31,6 +33,7 @@ export function CodeListPage({ onUpdateCodeListId, onUpdateCodeList, onUploadCodeList, + codeListsUsages, }: CodeListPageProps): React.ReactElement { const { t } = useTranslation(); const [codeListInEditMode, setCodeListInEditMode] = useState(undefined); @@ -62,6 +65,7 @@ export function CodeListPage({ onUpdateCodeList={onUpdateCodeList} codeListInEditMode={codeListInEditMode} codeListNames={codeListTitles} + codeListsUsages={codeListsUsages} /> ); diff --git a/frontend/libs/studio-content-library/src/ContentLibrary/LibraryBody/pages/CodeListPage/CodeLists/CodeLists.test.tsx b/frontend/libs/studio-content-library/src/ContentLibrary/LibraryBody/pages/CodeListPage/CodeLists/CodeLists.test.tsx index ee1c20ecf03..00136dc7cde 100644 --- a/frontend/libs/studio-content-library/src/ContentLibrary/LibraryBody/pages/CodeListPage/CodeLists/CodeLists.test.tsx +++ b/frontend/libs/studio-content-library/src/ContentLibrary/LibraryBody/pages/CodeListPage/CodeLists/CodeLists.test.tsx @@ -1,7 +1,7 @@ import React from 'react'; import { render, screen } from '@testing-library/react'; import type { CodeListsProps } from './CodeLists'; -import { updateCodeListWithMetadata, CodeLists } from './CodeLists'; +import { getCodeListSourcesById, updateCodeListWithMetadata, CodeLists } from './CodeLists'; import { textMock } from '@studio/testing/mocks/i18nMock'; import type { CodeListWithMetadata } from '../CodeListPage'; import type { RenderResult } from '@testing-library/react'; @@ -9,6 +9,7 @@ import type { UserEvent } from '@testing-library/user-event'; import userEvent from '@testing-library/user-event'; import type { CodeList as StudioComponentsCodeList } from '@studio/components'; import { codeListsDataMock } from '../../../../../../mocks/mockPagesConfig'; +import type { CodeListIdSource, CodeListReference } from '../types/CodeListReference'; const codeListName = codeListsDataMock[0].title; const onUpdateCodeListIdMock = jest.fn(); @@ -124,6 +125,7 @@ const defaultProps: CodeListsProps = { onUpdateCodeList: onUpdateCodeListMock, codeListInEditMode: undefined, codeListNames: [], + codeListsUsages: [], }; const renderCodeLists = (props: Partial = {}): RenderResult => { @@ -156,3 +158,37 @@ describe('updateCodeListWithMetadata', () => { }); }); }); + +const codeListId1: string = 'codeListId1'; +const codeListId2: string = 'codeListId2'; +const componentIds: string[] = ['componentId1', 'componentId2']; +const codeListIdSources1: CodeListIdSource[] = [ + { layoutSetId: 'layoutSetId', layoutName: 'layoutName', componentIds }, +]; +const codeListIdSources2: CodeListIdSource[] = [...codeListIdSources1]; + +describe('getCodeListSourcesById', () => { + it('returns an array of CodeListSources if given Id is present in codeListsUsages array', () => { + const codeListUsages: CodeListReference[] = [ + { codeListId: codeListId1, codeListIdSources: codeListIdSources1 }, + { codeListId: codeListId2, codeListIdSources: codeListIdSources2 }, + ]; + const codeListSources = getCodeListSourcesById(codeListUsages, codeListId1); + + expect(codeListSources).toBe(codeListIdSources1); + expect(codeListSources).not.toBe(codeListIdSources2); + }); + + it('returns an empty array if given Id is not present in codeListsUsages array', () => { + const codeListUsages: CodeListReference[] = [ + { codeListId: codeListId2, codeListIdSources: codeListIdSources2 }, + ]; + const codeListSources = getCodeListSourcesById(codeListUsages, codeListId1); + expect(codeListSources).toEqual([]); + }); + + it('returns an empty array if codeListsUsages array is empty', () => { + const codeListSources = getCodeListSourcesById([], codeListId1); + expect(codeListSources).toEqual([]); + }); +}); diff --git a/frontend/libs/studio-content-library/src/ContentLibrary/LibraryBody/pages/CodeListPage/CodeLists/CodeLists.tsx b/frontend/libs/studio-content-library/src/ContentLibrary/LibraryBody/pages/CodeListPage/CodeLists/CodeLists.tsx index 11afcfdd26e..57738b08890 100644 --- a/frontend/libs/studio-content-library/src/ContentLibrary/LibraryBody/pages/CodeListPage/CodeLists/CodeLists.tsx +++ b/frontend/libs/studio-content-library/src/ContentLibrary/LibraryBody/pages/CodeListPage/CodeLists/CodeLists.tsx @@ -4,6 +4,7 @@ import { Accordion } from '@digdir/designsystemet-react'; import { StudioAlert, type CodeList as StudioComponentsCodeList } from '@studio/components'; import { EditCodeList } from './EditCodeList/EditCodeList'; import { useTranslation } from 'react-i18next'; +import type { CodeListIdSource, CodeListReference } from '../types/CodeListReference'; export type CodeListsProps = { codeListsData: CodeListData[]; @@ -11,6 +12,7 @@ export type CodeListsProps = { onUpdateCodeList: (updatedCodeList: CodeListWithMetadata) => void; codeListInEditMode: string | undefined; codeListNames: string[]; + codeListsUsages: CodeListReference[]; }; export function CodeLists({ @@ -19,20 +21,38 @@ export function CodeLists({ onUpdateCodeList, codeListInEditMode, codeListNames, + codeListsUsages, }: CodeListsProps) { - return codeListsData.map((codeListData) => ( - - )); + return codeListsData.map((codeListData) => { + const codeListSources = getCodeListSourcesById(codeListsUsages, codeListData.title); + return ( + + ); + }); } -type CodeListProps = Omit & { codeListData: CodeListData }; +export const getCodeListSourcesById = ( + codeListsUsages: CodeListReference[], + codeListTitle: string, +): CodeListIdSource[] => { + const codeListUsages: CodeListReference | undefined = codeListsUsages.find( + (codeListUsage) => codeListUsage.codeListId === codeListTitle, + ); + return codeListUsages?.codeListIdSources ?? []; +}; + +type CodeListProps = Omit & { + codeListData: CodeListData; + codeListSources: CodeListIdSource[]; +}; function CodeList({ codeListData, @@ -40,6 +60,7 @@ function CodeList({ onUpdateCodeList, codeListInEditMode, codeListNames, + codeListSources, }: CodeListProps) { const { t } = useTranslation(); @@ -58,6 +79,7 @@ function CodeList({ onUpdateCodeListId={onUpdateCodeListId} onUpdateCodeList={onUpdateCodeList} codeListNames={codeListNames} + codeListSources={codeListSources} /> @@ -71,6 +93,7 @@ function CodeListAccordionContent({ onUpdateCodeListId, onUpdateCodeList, codeListNames, + codeListSources, }: CodeListAccordionContentProps): React.ReactElement { const { t } = useTranslation(); diff --git a/frontend/libs/studio-content-library/src/ContentLibrary/LibraryBody/pages/CodeListPage/index.ts b/frontend/libs/studio-content-library/src/ContentLibrary/LibraryBody/pages/CodeListPage/index.ts index ffcb4126071..2bf6c858f95 100644 --- a/frontend/libs/studio-content-library/src/ContentLibrary/LibraryBody/pages/CodeListPage/index.ts +++ b/frontend/libs/studio-content-library/src/ContentLibrary/LibraryBody/pages/CodeListPage/index.ts @@ -1,2 +1,3 @@ export { CodeListPage } from './CodeListPage'; export type { CodeListWithMetadata, CodeListData, CodeListPageProps } from './CodeListPage'; +export type { CodeListIdSource, CodeListReference } from './types/CodeListReference'; diff --git a/frontend/libs/studio-content-library/src/ContentLibrary/LibraryBody/pages/CodeListPage/types/CodeListReference.ts b/frontend/libs/studio-content-library/src/ContentLibrary/LibraryBody/pages/CodeListPage/types/CodeListReference.ts new file mode 100644 index 00000000000..bb9ae55d0be --- /dev/null +++ b/frontend/libs/studio-content-library/src/ContentLibrary/LibraryBody/pages/CodeListPage/types/CodeListReference.ts @@ -0,0 +1,10 @@ +export type CodeListReference = { + codeListId: string; + codeListIdSources: CodeListIdSource[]; +}; + +export type CodeListIdSource = { + layoutSetId: string; + layoutName: string; + componentIds: string[]; +}; diff --git a/frontend/libs/studio-content-library/src/ContentLibrary/LibraryBody/pages/index.ts b/frontend/libs/studio-content-library/src/ContentLibrary/LibraryBody/pages/index.ts index cedde4105d1..7d9aed54b86 100644 --- a/frontend/libs/studio-content-library/src/ContentLibrary/LibraryBody/pages/index.ts +++ b/frontend/libs/studio-content-library/src/ContentLibrary/LibraryBody/pages/index.ts @@ -1 +1,6 @@ -export type { CodeListWithMetadata, CodeListData } from './CodeListPage'; +export type { + CodeListWithMetadata, + CodeListData, + CodeListIdSource, + CodeListReference, +} from './CodeListPage'; diff --git a/frontend/libs/studio-content-library/src/index.ts b/frontend/libs/studio-content-library/src/index.ts index aa13dfd73a0..d06bfbe240b 100644 --- a/frontend/libs/studio-content-library/src/index.ts +++ b/frontend/libs/studio-content-library/src/index.ts @@ -1,2 +1,7 @@ export { ResourceContentLibraryImpl } from './config/ContentResourceLibraryImpl'; -export type { CodeListWithMetadata, CodeListData } from './ContentLibrary/LibraryBody/pages'; +export type { + CodeListWithMetadata, + CodeListData, + CodeListIdSource, + CodeListReference, +} from './ContentLibrary/LibraryBody/pages'; diff --git a/frontend/packages/shared/src/api/paths.js b/frontend/packages/shared/src/api/paths.js index 3f389f518db..410030811b2 100644 --- a/frontend/packages/shared/src/api/paths.js +++ b/frontend/packages/shared/src/api/paths.js @@ -43,6 +43,7 @@ export const ruleHandlerPath = (org, app, layoutSetName) => `${basePath}/${org}/ export const widgetSettingsPath = (org, app) => `${basePath}/${org}/${app}/app-development/widget-settings`; // Get export const optionListPath = (org, app, optionsListId) => `${basePath}/${org}/${app}/options/${optionsListId}`; // Get export const optionListsPath = (org, app) => `${basePath}/${org}/${app}/options/option-lists`; // Get +export const optionListReferencesPath = (org, app) => `${basePath}/${org}/${app}/options/usage`; // Get export const optionListIdsPath = (org, app) => `${basePath}/${org}/${app}/app-development/option-list-ids`; // Get export const optionListUpdatePath = (org, app, optionsListId) => `${basePath}/${org}/${app}/options/${optionsListId}`; // Put export const optionListIdUpdatePath = (org, app, optionsListId) => `${basePath}/${org}/${app}/options/change-name/${optionsListId}`; // Put diff --git a/frontend/packages/shared/src/api/queries.ts b/frontend/packages/shared/src/api/queries.ts index af0fef14bd7..fa66f176057 100644 --- a/frontend/packages/shared/src/api/queries.ts +++ b/frontend/packages/shared/src/api/queries.ts @@ -58,6 +58,7 @@ import { selectedMaskinportenScopesPath, resourceAccessPackageServicesPath, optionListPath, + optionListReferencesPath, } from './paths'; import type { AppReleasesResponse, DataModelMetadataResponse, SearchRepoFilterParams, SearchRepositoryResponse } from 'app-shared/types/api'; @@ -89,7 +90,7 @@ import type { Policy } from 'app-shared/types/Policy'; import type { RepoDiffResponse } from 'app-shared/types/api/RepoDiffResponse'; import type { ExternalImageUrlValidationResponse } from 'app-shared/types/api/ExternalImageUrlValidationResponse'; import type { MaskinportenScopes } from 'app-shared/types/MaskinportenScope'; -import type { OptionsList, OptionsListsResponse } from 'app-shared/types/api/OptionsLists'; +import type { OptionListsReferences, OptionsList, OptionsListsResponse } from 'app-shared/types/api/OptionsLists'; import type { LayoutSetsModel } from '../types/api/dto/LayoutSetsModel'; import type { AccessPackageResource, PolicyAccessPackageAreaGroup } from 'app-shared/types/PolicyAccessPackages'; @@ -118,6 +119,7 @@ export const getLayoutSets = (owner: string, app: string) => get(lay export const getLayoutSetsExtended = (owner: string, app: string) => get(layoutSetsPath(owner, app) + '/extended'); export const getOptionList = (owner: string, app: string, optionsListId: string) => get(optionListPath(owner, app, optionsListId)); export const getOptionLists = (owner: string, app: string) => get(optionListsPath(owner, app)); +export const getOptionListsReferences = (owner: string, app: string) => get(optionListReferencesPath(owner, app)); export const getOptionListIds = (owner: string, app: string) => get(optionListIdsPath(owner, app)); export const getOrgList = () => get(orgListUrl()); export const getOrganizations = () => get(orgsListPath()); diff --git a/frontend/packages/shared/src/hooks/queries/index.ts b/frontend/packages/shared/src/hooks/queries/index.ts index f97cf89f7a0..e028665ba07 100644 --- a/frontend/packages/shared/src/hooks/queries/index.ts +++ b/frontend/packages/shared/src/hooks/queries/index.ts @@ -4,6 +4,7 @@ export { useDataModelsJsonQuery } from './useDataModelsJsonQuery'; export { useDataModelsXsdQuery } from './useDataModelsXsdQuery'; export { useOptionListQuery } from './useOptionListQuery'; export { useOptionListsQuery } from './useOptionListsQuery'; +export { useOptionListsReferencesQuery } from './useOptionListsReferencesQuery'; export { useRepoMetadataQuery } from './useRepoMetadataQuery'; export { useRepoPullQuery } from './useRepoPullQuery'; export { useRepoStatusQuery } from './useRepoStatusQuery'; diff --git a/frontend/packages/shared/src/hooks/queries/useOptionListsReferencesQuery.test.ts b/frontend/packages/shared/src/hooks/queries/useOptionListsReferencesQuery.test.ts new file mode 100644 index 00000000000..878ba62d616 --- /dev/null +++ b/frontend/packages/shared/src/hooks/queries/useOptionListsReferencesQuery.test.ts @@ -0,0 +1,18 @@ +import { queriesMock } from 'app-shared/mocks/queriesMock'; +import { app, org } from '@studio/testing/testids'; +import { renderHookWithProviders } from 'app-shared/mocks/renderHookWithProviders'; +import { waitFor } from '@testing-library/react'; +import { useOptionListsReferencesQuery } from './useOptionListsReferencesQuery'; + +describe('useOptionListsReferencesQuery', () => { + it('calls getOptionListsReferences with the correct parameters', () => { + render(); + expect(queriesMock.getOptionListsReferences).toHaveBeenCalledWith(org, app); + }); +}); + +const render = async () => { + const { result } = renderHookWithProviders(() => useOptionListsReferencesQuery(org, app)); + await waitFor(() => expect(result.current.isSuccess).toBe(true)); + return result; +}; diff --git a/frontend/packages/shared/src/hooks/queries/useOptionListsReferencesQuery.ts b/frontend/packages/shared/src/hooks/queries/useOptionListsReferencesQuery.ts new file mode 100644 index 00000000000..c8c7415580f --- /dev/null +++ b/frontend/packages/shared/src/hooks/queries/useOptionListsReferencesQuery.ts @@ -0,0 +1,16 @@ +import { useServicesContext } from 'app-shared/contexts/ServicesContext'; +import { QueryKey } from 'app-shared/types/QueryKey'; +import type { UseQueryResult } from '@tanstack/react-query'; +import { useQuery } from '@tanstack/react-query'; +import type { OptionListsReferences } from 'app-shared/types/api/OptionsLists'; + +export const useOptionListsReferencesQuery = ( + org: string, + app: string, +): UseQueryResult => { + const { getOptionListsReferences } = useServicesContext(); + return useQuery({ + queryKey: [QueryKey.OptionListsUsage, org, app], + queryFn: () => getOptionListsReferences(org, app), + }); +}; diff --git a/frontend/packages/shared/src/mocks/queriesMock.ts b/frontend/packages/shared/src/mocks/queriesMock.ts index ce0e2f1faa7..616564b7aa6 100644 --- a/frontend/packages/shared/src/mocks/queriesMock.ts +++ b/frontend/packages/shared/src/mocks/queriesMock.ts @@ -69,7 +69,11 @@ import type { DeploymentsResponse } from 'app-shared/types/api/DeploymentsRespon import type { RepoDiffResponse } from 'app-shared/types/api/RepoDiffResponse'; import type { ExternalImageUrlValidationResponse } from 'app-shared/types/api/ExternalImageUrlValidationResponse'; import type { MaskinportenScope } from 'app-shared/types/MaskinportenScope'; -import type { OptionsList, OptionsListsResponse } from 'app-shared/types/api/OptionsLists'; +import type { + OptionListsReferences, + OptionsList, + OptionsListsResponse, +} from 'app-shared/types/api/OptionsLists'; import type { LayoutSetsModel } from '../types/api/dto/LayoutSetsModel'; import { layoutSetsExtendedMock } from '@altinn/ux-editor/testing/layoutSetsMock'; @@ -110,6 +114,9 @@ export const queriesMock: ServicesContextProps = { getOptionListIds: jest.fn().mockImplementation(() => Promise.resolve([])), getOptionList: jest.fn().mockImplementation(() => Promise.resolve([])), getOptionLists: jest.fn().mockImplementation(() => Promise.resolve([])), + getOptionListsReferences: jest + .fn() + .mockImplementation(() => Promise.resolve([])), 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/QueryKey.ts b/frontend/packages/shared/src/types/QueryKey.ts index bea955f6158..3f2cabcac3e 100644 --- a/frontend/packages/shared/src/types/QueryKey.ts +++ b/frontend/packages/shared/src/types/QueryKey.ts @@ -28,6 +28,7 @@ export enum QueryKey { LayoutSets = 'LayoutSets', LayoutSetsExtended = 'LayoutSetsExtended', OptionList = 'OptionList', + OptionListsUsage = 'OptionListsUsage', OptionLists = 'OptionLists', OptionListIds = 'OptionListIds', OrgList = 'OrgList', diff --git a/frontend/packages/shared/src/types/api/OptionsLists.ts b/frontend/packages/shared/src/types/api/OptionsLists.ts index 4552a783d1f..27c46294c52 100644 --- a/frontend/packages/shared/src/types/api/OptionsLists.ts +++ b/frontend/packages/shared/src/types/api/OptionsLists.ts @@ -1,4 +1,5 @@ import type { Option } from 'app-shared/types/Option'; +import type { CodeListIdSource } from '@studio/content-library'; export type OptionsList = Option[]; @@ -9,3 +10,10 @@ export type OptionsListData = { }; export type OptionsListsResponse = OptionsListData[]; + +export type OptionListsReference = { + optionListId: string; + optionListIdSources: CodeListIdSource[]; +}; + +export type OptionListsReferences = OptionListsReference[];