diff --git a/src/layout/SigningDocumentList/SigningDocumentListComponent.test.tsx b/src/layout/SigningDocumentList/SigningDocumentListComponent.test.tsx
index 9fde8a0a34..34981277a3 100644
--- a/src/layout/SigningDocumentList/SigningDocumentListComponent.test.tsx
+++ b/src/layout/SigningDocumentList/SigningDocumentListComponent.test.tsx
@@ -49,6 +49,7 @@ jest.mock('src/features/language/Lang', () => ({
jest.mock('src/features/applicationMetadata/ApplicationMetadataProvider', () => ({
useApplicationMetadata: jest.fn(() => ({
dataTypes: [],
+ altinnNugetVersion: '8.9.0.225',
})),
}));
diff --git a/src/layout/SigningDocumentList/SigningDocumentListComponent.tsx b/src/layout/SigningDocumentList/SigningDocumentListComponent.tsx
index ec39915538..eef039c17d 100644
--- a/src/layout/SigningDocumentList/SigningDocumentListComponent.tsx
+++ b/src/layout/SigningDocumentList/SigningDocumentListComponent.tsx
@@ -6,6 +6,7 @@ import { DownloadIcon } from '@navikt/aksel-icons';
import { AppTable } from 'src/app-components/Table/Table';
import { Caption } from 'src/components/form/caption/Caption';
+import { useApplicationMetadata } from 'src/features/applicationMetadata/ApplicationMetadataProvider';
import { Lang } from 'src/features/language/Lang';
import { useLanguage } from 'src/features/language/useLanguage';
import classes from 'src/layout/SigneeList/SigneeListComponent.module.css';
@@ -21,8 +22,9 @@ export function SigningDocumentListComponent({
}) {
const { instanceOwnerPartyId, instanceGuid } = useParams();
const { langAsString } = useLanguage();
+ const { altinnNugetVersion } = useApplicationMetadata();
- const { data, isLoading, error } = useDocumentList(instanceOwnerPartyId, instanceGuid);
+ const { data, isLoading, error } = useDocumentList(instanceOwnerPartyId, instanceGuid, altinnNugetVersion);
if (error) {
return ;
diff --git a/src/layout/SigningDocumentList/api.test.ts b/src/layout/SigningDocumentList/api.test.ts
new file mode 100644
index 0000000000..fd9934e590
--- /dev/null
+++ b/src/layout/SigningDocumentList/api.test.ts
@@ -0,0 +1,88 @@
+import { jest } from '@jest/globals';
+import { useQuery } from '@tanstack/react-query';
+import { renderHook } from '@testing-library/react';
+
+import { type SigningDocument, useDocumentList } from 'src/layout/SigningDocumentList/api';
+import { httpGet } from 'src/utils/network/sharedNetworking';
+
+jest.mock('@tanstack/react-query', () => ({
+ useQuery: jest.fn(),
+}));
+
+jest.mock('src/utils/network/sharedNetworking', () => ({
+ httpGet: jest.fn(),
+}));
+
+describe('useDocumentList', () => {
+ const mockedUseQuery = jest.mocked(useQuery);
+ const mockedHttpGet = jest.mocked(httpGet);
+
+ const response = {
+ dataElements: [
+ {
+ id: '1',
+ dataType: 'attachment',
+ contentType: 'application/pdf',
+ filename: 'zeta.pdf',
+ size: 100,
+ tags: ['tag-a'],
+ selfLinks: {
+ apps: 'https://storage.example.com/zeta.pdf',
+ },
+ },
+ {
+ id: '2',
+ dataType: 'attachment',
+ contentType: 'application/pdf',
+ filename: 'alpha.pdf',
+ size: 200,
+ tags: ['tag-b'],
+ selfLinks: {
+ apps: 'https://storage.example.com/alpha.pdf',
+ },
+ },
+ ],
+ };
+
+ beforeEach(() => {
+ jest.clearAllMocks();
+ mockedHttpGet.mockResolvedValue(response);
+ });
+
+ function hasQueryFn(value: unknown): value is { queryFn: () => Promise } {
+ if (typeof value !== 'object' || value === null) {
+ return false;
+ }
+
+ return 'queryFn' in value && typeof value.queryFn === 'function';
+ }
+
+ const runQueryFn = async (altinnNugetVersion: string | undefined): Promise => {
+ mockedUseQuery.mockReturnValue({} as ReturnType);
+
+ renderHook(() => useDocumentList('party-id', 'instance-guid', altinnNugetVersion));
+
+ const [queryOptions] = mockedUseQuery.mock.calls.at(-1) ?? [];
+
+ if (!hasQueryFn(queryOptions)) {
+ throw new Error('Expected useQuery to receive a queryFn');
+ }
+
+ return queryOptions.queryFn();
+ };
+
+ it('returns backend order when altinnNugetVersion is at least 8.9.0.225', async () => {
+ const documents = await runQueryFn('8.9.0.225');
+
+ expect(documents.map((doc) => doc.filename)).toEqual(['zeta.pdf', 'alpha.pdf']);
+ });
+
+ it.each<[string | undefined]>([['8.9.0.224'], [undefined]])(
+ 'sorts by filename when altinnNugetVersion is %s',
+ async (altinnNugetVersion) => {
+ const documents = await runQueryFn(altinnNugetVersion);
+
+ expect(documents.map((doc) => doc.filename)).toEqual(['alpha.pdf', 'zeta.pdf']);
+ },
+ );
+});
diff --git a/src/layout/SigningDocumentList/api.ts b/src/layout/SigningDocumentList/api.ts
index 38ec7dcc09..fd52e400e7 100644
--- a/src/layout/SigningDocumentList/api.ts
+++ b/src/layout/SigningDocumentList/api.ts
@@ -6,6 +6,7 @@ import { DataTypeReference } from 'src/utils/attachmentsUtils';
import { httpGet } from 'src/utils/network/sharedNetworking';
import { appPath } from 'src/utils/urls/appUrlHelper';
import { makeUrlRelativeIfSameDomain } from 'src/utils/urls/urlHelper';
+import { backendSupportsSigningDocumentOrdering } from 'src/utils/versioning/versions';
const signingDocumentSchema = z
.object({
@@ -33,18 +34,23 @@ export type SigningDocument = z.infer;
export function useDocumentList(
instanceOwnerPartyId: string | undefined,
instanceGuid: string | undefined,
+ altinnNugetVersion: string | undefined,
): UseQueryResult {
+ const backendHandlesOrdering = backendSupportsSigningDocumentOrdering(altinnNugetVersion);
+
return useQuery({
- queryKey: ['signingDocumentList', instanceOwnerPartyId, instanceGuid],
+ queryKey: ['signingDocumentList', instanceOwnerPartyId, instanceGuid, backendHandlesOrdering],
queryFn: async () => {
const url = `${appPath}/instances/${instanceOwnerPartyId}/${instanceGuid}/signing/data-elements`;
const response = await httpGet(url);
- return z
- .object({ dataElements: z.array(signingDocumentSchema) })
- .parse(response)
- .dataElements.toSorted((a, b) => (a.filename ?? '').localeCompare(b.filename ?? ''));
+ const dataElements = z.object({ dataElements: z.array(signingDocumentSchema) }).parse(response).dataElements;
+
+ if (backendHandlesOrdering) {
+ return dataElements;
+ }
+ return dataElements.toSorted((a, b) => (a.filename ?? '').localeCompare(b.filename ?? ''));
},
staleTime: 1000 * 60 * 30, // 30 minutes
refetchOnMount: 'always',
diff --git a/src/utils/versioning/versions.ts b/src/utils/versioning/versions.ts
index 097b7b891d..bc903faebd 100644
--- a/src/utils/versioning/versions.ts
+++ b/src/utils/versioning/versions.ts
@@ -9,6 +9,7 @@ export const FEATURE_VERSION_MAP = {
PDF_PREVIEW_BUTTON: '8.5.0.157',
APP_LANGUAGES_IN_ANONYMOUS: '8.5.6.180',
SET_TAGS_ENDPOINT: '8.8.0.215',
+ BACKEND_ORDERED_SIGNING_DOCUMENTS: '8.9.0.225',
} as const;
type AppFeature = keyof typeof FEATURE_VERSION_MAP;
@@ -67,3 +68,7 @@ export function appSupportsIncrementalValidationFeatures(currentNugetVersion: st
export function appSupportsSetTagsEndpoint(currentNugetVersion: string | undefined) {
return isFeatureSupported({ feature: 'SET_TAGS_ENDPOINT', currentNugetVersion });
}
+
+export function backendSupportsSigningDocumentOrdering(currentNugetVersion: string | undefined) {
+ return isFeatureSupported({ feature: 'BACKEND_ORDERED_SIGNING_DOCUMENTS', currentNugetVersion });
+}