From f04d99e84e42a1242fc9c4b59df0360521c35180 Mon Sep 17 00:00:00 2001 From: Jonas Dyrlie Date: Tue, 16 Dec 2025 08:03:10 +0100 Subject: [PATCH 1/2] feat: instance contextual layout settings --- .../layoutSettings/LayoutSettingsContext.tsx | 19 +++++++++++++++++-- src/queries/queries.ts | 4 ++++ src/test/renderWithProviders.tsx | 1 + src/utils/urls/appUrlHelper.ts | 2 ++ 4 files changed, 24 insertions(+), 2 deletions(-) diff --git a/src/features/form/layoutSettings/LayoutSettingsContext.tsx b/src/features/form/layoutSettings/LayoutSettingsContext.tsx index 3241600abe..0b57d3178c 100644 --- a/src/features/form/layoutSettings/LayoutSettingsContext.tsx +++ b/src/features/form/layoutSettings/LayoutSettingsContext.tsx @@ -1,24 +1,39 @@ import { useEffect } from 'react'; -import { useQuery } from '@tanstack/react-query'; +import { skipToken, useQuery } from '@tanstack/react-query'; import { v4 as uuidv4 } from 'uuid'; import { useAppQueries } from 'src/core/contexts/AppQueriesProvider'; import { ContextNotProvided } from 'src/core/contexts/context'; import { delayedContext } from 'src/core/contexts/delayedContext'; import { createQueryContext } from 'src/core/contexts/queryContext'; +import { useApplicationMetadata } from 'src/features/applicationMetadata/ApplicationMetadataProvider'; import { useLaxGlobalUISettings } from 'src/features/form/layoutSets/LayoutSetsProvider'; import { useLayoutSetIdFromUrl } from 'src/features/form/layoutSets/useCurrentLayoutSet'; +import { useLaxInstanceId } from 'src/features/instance/InstanceContext'; import { useShallowMemo } from 'src/hooks/useShallowMemo'; +import { fetchLayoutSettingsForInstance } from 'src/queries/queries'; import type { QueryDefinition } from 'src/core/queries/usePrefetchQuery'; import type { GlobalPageSettings, ILayoutSettings, NavigationPageGroup } from 'src/layout/common.generated'; // Also used for prefetching @see formPrefetcher.ts export function useLayoutSettingsQueryDef(layoutSetId?: string): QueryDefinition { const { fetchLayoutSettings } = useAppQueries(); + const instanceId = useLaxInstanceId(); + const features = useApplicationMetadata().features ?? {}; + return { queryKey: ['layoutSettings', layoutSetId], - queryFn: async () => processData(layoutSetId ? await fetchLayoutSettings(layoutSetId) : null), + queryFn: layoutSetId + ? async () => { + const shouldUseInstanceEndpoint = features.addInstanceIdentifierToLayoutRequests && instanceId; + const layoutSettings = shouldUseInstanceEndpoint + ? await fetchLayoutSettingsForInstance(layoutSetId, instanceId) + : await fetchLayoutSettings(layoutSetId); + + return processData(layoutSettings); + } + : skipToken, }; } diff --git a/src/queries/queries.ts b/src/queries/queries.ts index 8198a10785..12e8d3badd 100644 --- a/src/queries/queries.ts +++ b/src/queries/queries.ts @@ -27,6 +27,7 @@ import { getFileUploadUrl, getFileUploadUrlOld, getFooterLayoutUrl, + getInstanceLayoutSettingsUrl, getInstanceLayoutsUrl, getInstantiateUrl, getJsonSchemaUrl, @@ -299,6 +300,9 @@ export const fetchLayoutsForInstance = (layoutSetId: string, instanceId: string) export const fetchLayoutSettings = (layoutSetId: string): Promise => httpGet(getLayoutSettingsUrl(layoutSetId)); +export const fetchLayoutSettingsForInstance = (layoutSetId: string, instanceId: string): Promise => + httpGet(getInstanceLayoutSettingsUrl(layoutSetId, instanceId)); + export const fetchOptions = (url: string): Promise | null> => httpGetRaw(url); export const fetchDataList = (url: string): Promise => httpGet(url); diff --git a/src/test/renderWithProviders.tsx b/src/test/renderWithProviders.tsx index 39664bb8a1..45e7e5d2cd 100644 --- a/src/test/renderWithProviders.tsx +++ b/src/test/renderWithProviders.tsx @@ -151,6 +151,7 @@ const defaultQueryMocks: AppQueries = { fetchAppLanguages: async () => [{ language: 'nb' }, { language: 'nn' }, { language: 'en' }], fetchPostPlace: async () => ({ valid: true, result: 'OSLO' }), fetchLayoutSettings: async () => ({ pages: { order: [] } }), + fetchLayoutSettingsForInstance: async () => ({ pages: { order: [] } }), fetchLayouts: () => Promise.reject(new Error('fetchLayouts not mocked')), fetchLayoutsForInstance: () => Promise.reject(new Error('fetchLayoutsForInstance not mocked')), fetchBackendValidations: async () => [], diff --git a/src/utils/urls/appUrlHelper.ts b/src/utils/urls/appUrlHelper.ts index 66d642d028..69935ea4c0 100644 --- a/src/utils/urls/appUrlHelper.ts +++ b/src/utils/urls/appUrlHelper.ts @@ -182,6 +182,8 @@ export const redirectToUpgrade = (reqAuthLevel: string) => { export const getJsonSchemaUrl = () => `${appPath}/api/jsonschema/`; export const getCustomValidationConfigUrl = (dataTypeId: string) => `${appPath}/api/validationconfig/${dataTypeId}`; export const getLayoutSettingsUrl = (layoutSetId: string) => `${appPath}/api/layoutsettings/${layoutSetId}`; +export const getInstanceLayoutSettingsUrl = (layoutSetId: string, instanceId: string) => + `${appPath}/instances/${instanceId}/layoutsettings/${layoutSetId}`; export const getLayoutSetsUrl = () => `${appPath}/api/layoutsets`; export const getFooterLayoutUrl = () => `${appPath}/api/v1/footer`; export const getFetchFormDynamicsUrl = (layoutSetId: string) => `${appPath}/api/ruleconfiguration/${layoutSetId}`; From 1d7aebf98dad825b7a67de86f3fb25dd878afba7 Mon Sep 17 00:00:00 2001 From: Jonas Dyrlie Date: Tue, 16 Dec 2025 09:18:50 +0100 Subject: [PATCH 2/2] fix: correct query importing --- src/features/form/layout/LayoutsContext.tsx | 3 +-- src/features/form/layoutSettings/LayoutSettingsContext.tsx | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/features/form/layout/LayoutsContext.tsx b/src/features/form/layout/LayoutsContext.tsx index 45646e6945..e4cdee8a96 100644 --- a/src/features/form/layout/LayoutsContext.tsx +++ b/src/features/form/layout/LayoutsContext.tsx @@ -16,7 +16,6 @@ import { useLayoutSetIdFromUrl } from 'src/features/form/layoutSets/useCurrentLa import { useInstanceDataQuery, useLaxInstanceId } from 'src/features/instance/InstanceContext'; import { useProcessQuery } from 'src/features/instance/useProcessQuery'; import { makeLikertChildId } from 'src/layout/Likert/Generator/makeLikertChildId'; -import { fetchLayoutsForInstance } from 'src/queries/queries'; import type { QueryDefinition } from 'src/core/queries/usePrefetchQuery'; import type { CompExternal, ILayoutCollection, ILayouts } from 'src/layout/layout'; import type { IExpandedWidthLayouts, IHiddenLayoutsExternal } from 'src/types'; @@ -33,7 +32,7 @@ export function useLayoutQueryDef( defaultDataModelType: string, layoutSetId?: string, ): QueryDefinition { - const { fetchLayouts } = useAppQueries(); + const { fetchLayouts, fetchLayoutsForInstance } = useAppQueries(); const instanceId = useLaxInstanceId(); const features = useApplicationMetadata().features ?? {}; diff --git a/src/features/form/layoutSettings/LayoutSettingsContext.tsx b/src/features/form/layoutSettings/LayoutSettingsContext.tsx index 0b57d3178c..2a1620b354 100644 --- a/src/features/form/layoutSettings/LayoutSettingsContext.tsx +++ b/src/features/form/layoutSettings/LayoutSettingsContext.tsx @@ -12,13 +12,12 @@ import { useLaxGlobalUISettings } from 'src/features/form/layoutSets/LayoutSetsP import { useLayoutSetIdFromUrl } from 'src/features/form/layoutSets/useCurrentLayoutSet'; import { useLaxInstanceId } from 'src/features/instance/InstanceContext'; import { useShallowMemo } from 'src/hooks/useShallowMemo'; -import { fetchLayoutSettingsForInstance } from 'src/queries/queries'; import type { QueryDefinition } from 'src/core/queries/usePrefetchQuery'; import type { GlobalPageSettings, ILayoutSettings, NavigationPageGroup } from 'src/layout/common.generated'; // Also used for prefetching @see formPrefetcher.ts export function useLayoutSettingsQueryDef(layoutSetId?: string): QueryDefinition { - const { fetchLayoutSettings } = useAppQueries(); + const { fetchLayoutSettings, fetchLayoutSettingsForInstance } = useAppQueries(); const instanceId = useLaxInstanceId(); const features = useApplicationMetadata().features ?? {};