Skip to content

Commit

Permalink
Merge branch 'main' into add-studio-component-for-search
Browse files Browse the repository at this point in the history
  • Loading branch information
TomasEng authored Jan 7, 2025
2 parents 2679d7c + 1e059fd commit 02032b5
Show file tree
Hide file tree
Showing 23 changed files with 228 additions and 43 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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();
});
Expand Down Expand Up @@ -146,16 +146,19 @@ const goToLibraryPage = async (user: UserEvent, libraryPage: string) => {

type renderAppContentLibraryProps = {
queries?: Partial<ServicesContextProps>;
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)(<AppContentLibrary />);
};
Original file line number Diff line number Diff line change
@@ -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';
Expand All @@ -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();
Expand All @@ -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 <StudioPageSpinner spinnerTitle={t('general.loading')}></StudioPageSpinner>;

const codeListsData = convertOptionsListsDataToCodeListsData(optionListsData);

const codeListsUsages: CodeListReference[] = mapToCodeListsUsage({ optionListsUsages });

const handleUpdateCodeListId = (optionListId: string, newOptionListId: string) => {
updateOptionListId({ optionListId, newOptionListId });
};
Expand Down Expand Up @@ -63,6 +68,7 @@ export function AppContentLibrary(): React.ReactElement {
onUpdateCodeListId: handleUpdateCodeListId,
onUpdateCodeList: handleUpdate,
onUploadCodeList: handleUpload,
codeListsUsages,
},
},
images: {
Expand Down
Original file line number Diff line number Diff line change
@@ -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([]);
});
});
Original file line number Diff line number Diff line change
@@ -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;
};
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export const mockPagesConfig: PagesConfig = {
onUpdateCodeListId: () => {},
onUpdateCodeList: () => {},
onUploadCodeList: () => {},
codeListsUsages: [],
},
},
images: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ const defaultCodeListPageProps: CodeListPageProps = {
onUpdateCodeListId: onUpdateCodeListIdMock,
onUpdateCodeList: onUpdateCodeListMock,
onUploadCodeList: onUploadCodeListMock,
codeListsUsages: [],
};

const renderCodeListPage = (props: Partial<CodeListPageProps> = {}) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -24,13 +25,15 @@ export type CodeListPageProps = {
onUpdateCodeListId: (codeListId: string, newCodeListId: string) => void;
onUpdateCodeList: (updatedCodeList: CodeListWithMetadata) => void;
onUploadCodeList: (uploadedCodeList: File) => void;
codeListsUsages: CodeListReference[];
};

export function CodeListPage({
codeListsData,
onUpdateCodeListId,
onUpdateCodeList,
onUploadCodeList,
codeListsUsages,
}: CodeListPageProps): React.ReactElement {
const { t } = useTranslation();
const [codeListInEditMode, setCodeListInEditMode] = useState<string>(undefined);
Expand Down Expand Up @@ -62,6 +65,7 @@ export function CodeListPage({
onUpdateCodeList={onUpdateCodeList}
codeListInEditMode={codeListInEditMode}
codeListNames={codeListTitles}
codeListsUsages={codeListsUsages}
/>
</div>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
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';
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();
Expand Down Expand Up @@ -124,6 +125,7 @@ const defaultProps: CodeListsProps = {
onUpdateCodeList: onUpdateCodeListMock,
codeListInEditMode: undefined,
codeListNames: [],
codeListsUsages: [],
};

const renderCodeLists = (props: Partial<CodeListsProps> = {}): RenderResult => {
Expand Down Expand Up @@ -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([]);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@ 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[];
onUpdateCodeListId: (codeListId: string, newCodeListId: string) => void;
onUpdateCodeList: (updatedCodeList: CodeListWithMetadata) => void;
codeListInEditMode: string | undefined;
codeListNames: string[];
codeListsUsages: CodeListReference[];
};

export function CodeLists({
Expand All @@ -19,27 +21,46 @@ export function CodeLists({
onUpdateCodeList,
codeListInEditMode,
codeListNames,
codeListsUsages,
}: CodeListsProps) {
return codeListsData.map((codeListData) => (
<CodeList
key={codeListData.title}
codeListData={codeListData}
onUpdateCodeListId={onUpdateCodeListId}
onUpdateCodeList={onUpdateCodeList}
codeListInEditMode={codeListInEditMode}
codeListNames={codeListNames}
/>
));
return codeListsData.map((codeListData) => {
const codeListSources = getCodeListSourcesById(codeListsUsages, codeListData.title);
return (
<CodeList
key={codeListData.title}
codeListData={codeListData}
onUpdateCodeListId={onUpdateCodeListId}
onUpdateCodeList={onUpdateCodeList}
codeListInEditMode={codeListInEditMode}
codeListNames={codeListNames}
codeListSources={codeListSources}
/>
);
});
}

type CodeListProps = Omit<CodeListsProps, 'codeListsData'> & { 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<CodeListsProps, 'codeListsData' | 'codeListsUsages'> & {
codeListData: CodeListData;
codeListSources: CodeListIdSource[];
};

function CodeList({
codeListData,
onUpdateCodeListId,
onUpdateCodeList,
codeListInEditMode,
codeListNames,
codeListSources,
}: CodeListProps) {
const { t } = useTranslation();

Expand All @@ -58,6 +79,7 @@ function CodeList({
onUpdateCodeListId={onUpdateCodeListId}
onUpdateCodeList={onUpdateCodeList}
codeListNames={codeListNames}
codeListSources={codeListSources}
/>
</Accordion.Item>
</Accordion>
Expand All @@ -71,6 +93,7 @@ function CodeListAccordionContent({
onUpdateCodeListId,
onUpdateCodeList,
codeListNames,
codeListSources,
}: CodeListAccordionContentProps): React.ReactElement {
const { t } = useTranslation();

Expand Down
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export { CodeListPage } from './CodeListPage';
export type { CodeListWithMetadata, CodeListData, CodeListPageProps } from './CodeListPage';
export type { CodeListIdSource, CodeListReference } from './types/CodeListReference';
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
export type CodeListReference = {
codeListId: string;
codeListIdSources: CodeListIdSource[];
};

export type CodeListIdSource = {
layoutSetId: string;
layoutName: string;
componentIds: string[];
};
Original file line number Diff line number Diff line change
@@ -1 +1,6 @@
export type { CodeListWithMetadata, CodeListData } from './CodeListPage';
export type {
CodeListWithMetadata,
CodeListData,
CodeListIdSource,
CodeListReference,
} from './CodeListPage';
7 changes: 6 additions & 1 deletion frontend/libs/studio-content-library/src/index.ts
Original file line number Diff line number Diff line change
@@ -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';
1 change: 1 addition & 0 deletions frontend/packages/shared/src/api/paths.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 3 additions & 1 deletion frontend/packages/shared/src/api/queries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ import {
selectedMaskinportenScopesPath,
resourceAccessPackageServicesPath,
optionListPath,
optionListReferencesPath,
} from './paths';

import type { AppReleasesResponse, DataModelMetadataResponse, SearchRepoFilterParams, SearchRepositoryResponse } from 'app-shared/types/api';
Expand Down Expand Up @@ -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';

Expand Down Expand Up @@ -118,6 +119,7 @@ export const getLayoutSets = (owner: string, app: string) => get<LayoutSets>(lay
export const getLayoutSetsExtended = (owner: string, app: string) => get<LayoutSetsModel>(layoutSetsPath(owner, app) + '/extended');
export const getOptionList = (owner: string, app: string, optionsListId: string) => get<OptionsList>(optionListPath(owner, app, optionsListId));
export const getOptionLists = (owner: string, app: string) => get<OptionsListsResponse>(optionListsPath(owner, app));
export const getOptionListsReferences = (owner: string, app: string) => get<OptionListsReferences>(optionListReferencesPath(owner, app));
export const getOptionListIds = (owner: string, app: string) => get<string[]>(optionListIdsPath(owner, app));
export const getOrgList = () => get<OrgList>(orgListUrl());
export const getOrganizations = () => get<Organization[]>(orgsListPath());
Expand Down
Loading

0 comments on commit 02032b5

Please sign in to comment.