Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 2 additions & 8 deletions src/features/applicationMetadata/ApplicationMetadataProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,10 @@ import type { UseQueryOptions } from '@tanstack/react-query';
import { delayedContext } from 'src/core/contexts/delayedContext';
import { createQueryContext } from 'src/core/contexts/queryContext';
import { onEntryValuesThatHaveState } from 'src/features/applicationMetadata/appMetadataUtils';
import { MINIMUM_APPLICATION_VERSION } from 'src/features/applicationMetadata/minVersion';
import { VersionErrorOrChildren } from 'src/features/applicationMetadata/VersionErrorOrChildren';
import { useNavigationParam } from 'src/hooks/navigation';
import { fetchApplicationMetadata } from 'src/queries/queries';
import { isAtLeastVersion } from 'src/utils/versionCompare';
import { isMinimumApplicationVersion } from 'src/utils/versioning/versions';
import type { ApplicationMetadata, IncomingApplicationMetadata } from 'src/features/applicationMetadata/types';

// Also used for prefetching @see appPrefetcher.ts
Expand All @@ -24,12 +23,7 @@ export function getApplicationMetadataQueryDef(instanceGuid: string | undefined)

return {
...data,
isValidVersion:
!!data.altinnNugetVersion &&
isAtLeastVersion({
actualVersion: data.altinnNugetVersion,
minimumVersion: MINIMUM_APPLICATION_VERSION.build,
}),
isValidVersion: isMinimumApplicationVersion(data.altinnNugetVersion),
onEntry,
isStatelessApp: isStatelessApp(!!instanceGuid, onEntry.show),
logoOptions: data.logo,
Expand Down
4 changes: 2 additions & 2 deletions src/features/applicationMetadata/VersionErrorOrChildren.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ import React from 'react';
import type { PropsWithChildren } from 'react';

import { useApplicationMetadata } from 'src/features/applicationMetadata/ApplicationMetadataProvider';
import { MINIMUM_APPLICATION_VERSION } from 'src/features/applicationMetadata/minVersion';
import { InstantiationErrorPage } from 'src/features/instantiate/containers/InstantiationErrorPage';
import { Lang } from 'src/features/language/Lang';
import { MINIMUM_APPLICATION_VERSION_NAME } from 'src/utils/versioning/versions';

export function VersionErrorOrChildren({ children }: PropsWithChildren) {
const { isValidVersion } = useApplicationMetadata();
Expand All @@ -21,7 +21,7 @@ export function VersionErrorOrChildren({ children }: PropsWithChildren) {
<br />
<Lang
id='version_error.min_backend_version'
params={[MINIMUM_APPLICATION_VERSION.name]}
params={[MINIMUM_APPLICATION_VERSION_NAME]}
/>
</>
}
Expand Down
4 changes: 0 additions & 4 deletions src/features/applicationMetadata/minVersion.ts

This file was deleted.

5 changes: 3 additions & 2 deletions src/features/attachments/AttachmentsStorePlugin.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { ContextNotProvided } from 'src/core/contexts/context';
import { useApplicationMetadata } from 'src/features/applicationMetadata/ApplicationMetadataProvider';
import { isAttachmentUploaded, isDataPostError } from 'src/features/attachments/index';
import { sortAttachmentsByName } from 'src/features/attachments/sortAttachments';
import { appSupportsNewAttachmentAPI, attachmentSelector } from 'src/features/attachments/tools';
import { attachmentSelector } from 'src/features/attachments/tools';
import { FileScanResults } from 'src/features/attachments/types';
import { FD } from 'src/features/formData/FormDataWrite';
import { dataModelPairsToObject } from 'src/features/formData/types';
Expand All @@ -28,6 +28,7 @@ import { useWaitForState } from 'src/hooks/useWaitForState';
import { nodesProduce } from 'src/utils/layout/NodesContext';
import { NodeDataPlugin } from 'src/utils/layout/plugins/NodeDataPlugin';
import { splitDashedKey } from 'src/utils/splitDashedKey';
import { appSupportsNewAttachmentAPI } from 'src/utils/versioning/versions';
import type {
DataPostResponse,
IAttachment,
Expand Down Expand Up @@ -296,7 +297,7 @@ export class AttachmentsStorePlugin extends NodeDataPlugin<AttachmentsStorePlugi
const { mutateAsync: uploadAttachment } = useAttachmentsUploadMutation();

const applicationMetadata = useApplicationMetadata();
const supportsNewAttachmentAPI = appSupportsNewAttachmentAPI(applicationMetadata);
const supportsNewAttachmentAPI = appSupportsNewAttachmentAPI(applicationMetadata.altinnNugetVersion);

const setAttachmentsInDataModel = useSetAttachmentInDataModel();
const lock = FD.useLocking('__attachment__upload__');
Expand Down
6 changes: 0 additions & 6 deletions src/features/attachments/tools.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import { sortAttachmentsByName } from 'src/features/attachments/sortAttachments';
import { isAtLeastVersion } from 'src/utils/versionCompare';
import type { ApplicationMetadata } from 'src/features/applicationMetadata/types';
import type { IAttachment } from 'src/features/attachments/index';
import type { NodesContext } from 'src/utils/layout/NodesContext';

Expand All @@ -17,7 +15,3 @@ export const attachmentSelector = (nodeId: string) => (state: NodesContext) => {
}
return emptyArray;
};

export function appSupportsNewAttachmentAPI({ altinnNugetVersion }: ApplicationMetadata) {
return !altinnNugetVersion || isAtLeastVersion({ actualVersion: altinnNugetVersion, minimumVersion: '8.5.0.153' });
}
22 changes: 11 additions & 11 deletions src/features/instance/useProcessNext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,14 @@ import { useOptimisticallyUpdateProcess, useProcessQuery } from 'src/features/in
import { Lang } from 'src/features/language/Lang';
import { useCurrentLanguage } from 'src/features/language/LanguageProvider';
import { useUpdateInitialValidations } from 'src/features/validation/backendValidation/backendValidationQuery';
import { appSupportsIncrementalValidationFeatures } from 'src/features/validation/backendValidation/backendValidationUtils';
import { useOnFormSubmitValidation } from 'src/features/validation/callbacks/onFormSubmitValidation';
import { Validation } from 'src/features/validation/validationContext';
import { TaskKeys, useNavigateToTask } from 'src/hooks/useNavigatePage';
import { doProcessNext } from 'src/queries/queries';
import { isAtLeastVersion } from 'src/utils/versionCompare';
import type { ApplicationMetadata } from 'src/features/applicationMetadata/types';
import {
appSupportsIncrementalValidationFeatures,
appSupportsUnlockingOnProcessNextFailure,
} from 'src/utils/versioning/versions';
import type { BackendValidationIssue } from 'src/features/validation';
import type { IActionType, IProcess, ProblemDetails } from 'src/types/shared';
import type { HttpClientError } from 'src/utils/network/sharedNetworking';
Expand All @@ -44,12 +45,15 @@ export function useProcessNext({ action }: ProcessNextProps = {}) {
const updateInitialValidations = useUpdateInitialValidations();
const setShowAllBackendErrors = Validation.useSetShowAllBackendErrors();
const onSubmitFormValidation = useOnFormSubmitValidation();
const applicationMetadata = useApplicationMetadata();
const queryClient = useQueryClient();
const displayError = useDisplayError();
const hasPendingScans = useHasPendingScans();
const optimisticallyUpdateProcess = useOptimisticallyUpdateProcess();

const altinnNugetVersion = useApplicationMetadata().altinnNugetVersion;
const isUnlockingOnProcessNextSupported = appSupportsUnlockingOnProcessNextFailure(altinnNugetVersion);
const isIncrementalValidationSupported = appSupportsIncrementalValidationFeatures(altinnNugetVersion);

return useMutation({
scope: { id: 'process/next' },
mutationKey: getProcessNextMutationKey(action),
Expand All @@ -76,7 +80,7 @@ export function useProcessNext({ action }: ProcessNextProps = {}) {
} else if (
error.response?.status === 500 &&
error.response?.data?.['detail'] === 'Pdf generation failed' &&
appSupportsUnlockingOnProcessNextFailure(applicationMetadata)
isUnlockingOnProcessNextSupported
) {
// If process next fails due to the PDF generator failing, don't show unknown error if the app unlocks data elements
toast(<Lang id='process_error.submit_error_please_retry' />, { type: 'error', autoClose: false });
Expand All @@ -100,7 +104,7 @@ export function useProcessNext({ action }: ProcessNextProps = {}) {
navigateToTask(task);
} else if (validationIssues) {
// Set initial validation to validation issues from process/next and make all errors visible
updateInitialValidations(validationIssues, !appSupportsIncrementalValidationFeatures(applicationMetadata));
updateInitialValidations(validationIssues, !isIncrementalValidationSupported);

const hasValidationErrors = await onSubmitFormValidation(true);
if (!hasValidationErrors) {
Expand All @@ -111,7 +115,7 @@ export function useProcessNext({ action }: ProcessNextProps = {}) {
onError: async (error: HttpClientError<ProblemDetails | undefined>) => {
window.logError('Process next failed:\n', error);

if (!appSupportsUnlockingOnProcessNextFailure(applicationMetadata)) {
if (!isUnlockingOnProcessNextSupported) {
displayError(error);
return;
}
Expand All @@ -132,10 +136,6 @@ export function useProcessNext({ action }: ProcessNextProps = {}) {
});
}

function appSupportsUnlockingOnProcessNextFailure({ altinnNugetVersion }: ApplicationMetadata) {
return !altinnNugetVersion || isAtLeastVersion({ actualVersion: altinnNugetVersion, minimumVersion: '8.1.0.115' });
}

export function getTargetTaskFromProcess(processData: IProcess | undefined) {
if (!processData) {
return undefined;
Expand Down
10 changes: 2 additions & 8 deletions src/features/language/LanguageProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { useGetAppLanguageQuery } from 'src/features/language/textResources/useG
import { useProfileQuery } from 'src/features/profile/ProfileProvider';
import { useIsAllowAnonymous } from 'src/features/stateless/getAllowAnonymous';
import { useLocalStorageState } from 'src/hooks/useLocalStorageState';
import { isAtLeastVersion } from 'src/utils/versionCompare';
import { appSupportsFetchAppLanguagesInAnonymous } from 'src/utils/versioning/versions';

interface LanguageCtx {
current: string;
Expand Down Expand Up @@ -91,15 +91,9 @@ export const SetShouldFetchAppLanguages = () => {
// We make the same assumption as in ProfileProvider that the user is logged in when the app does not allow anonymous.
const userIsAuthenticated = useIsAllowAnonymous(false);
const { altinnNugetVersion } = useApplicationMetadata();
const appSupportsFetchAppLanguagesInAnonymous =
altinnNugetVersion &&
isAtLeastVersion({
actualVersion: altinnNugetVersion,
minimumVersion: '8.5.6.180',
});

const setShouldFetchAppLanguages = useCtx().setShouldFetchAppLanguages;
const shouldFetchAppLanguages = appSupportsFetchAppLanguagesInAnonymous || userIsAuthenticated;
const shouldFetchAppLanguages = appSupportsFetchAppLanguagesInAnonymous(altinnNugetVersion) || userIsAuthenticated;
useEffect(() => {
setShouldFetchAppLanguages(shouldFetchAppLanguages);
}, [shouldFetchAppLanguages, setShouldFetchAppLanguages]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ import { useCurrentDataModelGuid } from 'src/features/datamodel/useBindingSchema
import { useLaxInstanceId } from 'src/features/instance/InstanceContext';
import { useProcessQuery } from 'src/features/instance/useProcessQuery';
import { useCurrentLanguage } from 'src/features/language/LanguageProvider';
import { appSupportsIncrementalValidationFeatures } from 'src/features/validation/backendValidation/backendValidationUtils';
import { useAsRef } from 'src/hooks/useAsRef';
import { fetchBackendValidationsForDataElement } from 'src/queries/queries';
import { appSupportsIncrementalValidationFeatures } from 'src/utils/versioning/versions';
import type { fetchBackendValidations } from 'src/queries/queries';

/**
Expand Down Expand Up @@ -132,7 +132,9 @@ export function useBackendValidationQuery<TResult = BackendValidationIssue[]>(
) {
const queryKey = useBackendValidationQueryKey();
const { fetchBackendValidations, fetchBackendValidationsForDataElement } = useAppQueries();
const hasIncrementalValidationFeatures = appSupportsIncrementalValidationFeatures(useApplicationMetadata());
const hasIncrementalValidationFeatures = appSupportsIncrementalValidationFeatures(
useApplicationMetadata().altinnNugetVersion,
);
const currentDataElementID = useCurrentDataModelGuid();
const instanceId = useLaxInstanceId();
const currentLanguage = useAsRef(useCurrentLanguage()).current;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@ import { BackendValidationSeverity, BuiltInValidationIssueSources, ValidationMas
import { validationTexts } from 'src/features/validation/backendValidation/validationTexts';
import { useIsPdf } from 'src/hooks/useIsPdf';
import { TaskKeys } from 'src/hooks/useNavigatePage';
import { isAtLeastVersion } from 'src/utils/versionCompare';
import type { ApplicationMetadata } from 'src/features/applicationMetadata/types';
import type { TextReference } from 'src/features/language/useLanguage';
import type {
BackendFieldValidatorGroups,
Expand Down Expand Up @@ -179,20 +177,3 @@ export function mapValidatorGroupsToDataModelValidations(

return backendValidations;
}

/**
* TODO(Subform): Make sure we reference the correct version here, and in applicationMetadataMock
*
* Prior to app-lib version 8.5.0 there was no way of identifying validation messages that were not run incrementally (ITaskValidator),
* this led to an edge case where if an ITaskValidator returned a validation message with a field, we could not
* distinguish this from a regular custom backend validation which does runs incrementally. The problem is that we block
* submit when we have custom backend validation errors until they are fixed, but since ITaskValidator is not run
* incrementally it would never get fixed until the user refreshed the page. This issue was somewhat mitigated
* by the old dataElement validation API which did not run ITaskValidators.
*
* Therefore, if this function returns false, this means that the app does not make this distinction, but
* has the old API available, so this needs to be used for backwards compatibility.
*/
export function appSupportsIncrementalValidationFeatures({ altinnNugetVersion }: ApplicationMetadata) {
return !altinnNugetVersion || isAtLeastVersion({ actualVersion: altinnNugetVersion, minimumVersion: '8.5.0.141' });
}
14 changes: 5 additions & 9 deletions src/layout/PDFPreviewButton/PDFPreviewButtonComponent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,18 @@ import { useApplicationMetadata } from 'src/features/applicationMetadata/Applica
import { useStrictInstanceId } from 'src/features/instance/InstanceContext';
import { NodesInternal } from 'src/utils/layout/NodesContext';
import { useItemWhenType } from 'src/utils/layout/useNodeItem';
import { isAtLeastVersion } from 'src/utils/versionCompare';
import { appSupportsPdfPreviewButton, FEATURE_VERSION_MAP } from 'src/utils/versioning/versions';
import type { NodeValidationProps } from 'src/layout/layout';

export function PDFPreviewButtonRenderLayoutValidator({ intermediateItem }: NodeValidationProps<'PDFPreviewButton'>) {
const instanceId = useStrictInstanceId();
const addError = NodesInternal.useAddError();
const applicationMetadata = useApplicationMetadata();
const minimumBackendVersion = '8.5.0.157';
const backendVersionOK = isAtLeastVersion({
actualVersion: applicationMetadata.altinnNugetVersion ?? '',
minimumVersion: minimumBackendVersion,
});
const isPdfPreviewButtonSupported = appSupportsPdfPreviewButton(applicationMetadata.altinnNugetVersion);

useEffect(() => {
if (!backendVersionOK) {
const error = `Need to be on at least backend version: ${minimumBackendVersion} to user this component`;
if (!isPdfPreviewButtonSupported) {
const error = `Need to be on at least backend version: ${FEATURE_VERSION_MAP.PDF_PREVIEW_BUTTON} to use this component`;
addError(error, intermediateItem.id, 'node');
window.logErrorOnce(`Validation error for '${intermediateItem.id}': ${error}`);
}
Expand All @@ -32,7 +28,7 @@ export function PDFPreviewButtonRenderLayoutValidator({ intermediateItem }: Node
addError(error, intermediateItem.id, 'node');
window.logErrorOnce(`Validation error for '${intermediateItem.id}': ${error}`);
}
}, [addError, backendVersionOK, instanceId, intermediateItem.id]);
}, [addError, isPdfPreviewButtonSupported, instanceId, intermediateItem.id]);

return null;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { isAtLeastVersion } from 'src/utils/versionCompare';
import { isAtLeastVersion } from 'src/utils/versioning/versionCompare';

describe('versionCompare', () => {
interface TestCase {
Expand Down
File renamed without changes.
64 changes: 64 additions & 0 deletions src/utils/versioning/versions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { isAtLeastVersion } from 'src/utils/versioning/versionCompare';

export const MINIMUM_APPLICATION_VERSION_NAME = 'v8.0.0';
export const FEATURE_VERSION_MAP = {
MINIMUM_APPLICATION_VERSION: '8.0.0.108',
UNLOCKING_ON_PROCESS_NEXT_FAILURE: '8.1.0.115',
INCREMENTAL_VALIDATION: '8.5.0.141',
NEW_ATTACHMENTS_API: '8.5.0.153',
PDF_PREVIEW_BUTTON: '8.5.0.157',
APP_LANGUAGES_IN_ANONYMOUS: '8.5.6.180',
} as const;

type AppFeature = keyof typeof FEATURE_VERSION_MAP;

function isFeatureSupported({
feature,
currentNugetVersion,
}: {
feature: AppFeature;
currentNugetVersion: string | undefined;
}) {
if (!currentNugetVersion) {
return false;
}

return isAtLeastVersion({ actualVersion: currentNugetVersion, minimumVersion: FEATURE_VERSION_MAP[feature] });
}

export function isMinimumApplicationVersion(currentNugetVersion: string | undefined) {
return isFeatureSupported({ feature: 'MINIMUM_APPLICATION_VERSION', currentNugetVersion });
}

export function appSupportsPdfPreviewButton(currentNugetVersion: string | undefined) {
return isFeatureSupported({ feature: 'PDF_PREVIEW_BUTTON', currentNugetVersion });
}

export function appSupportsFetchAppLanguagesInAnonymous(currentNugetVersion: string | undefined) {
return isFeatureSupported({ feature: 'APP_LANGUAGES_IN_ANONYMOUS', currentNugetVersion });
}

export function appSupportsUnlockingOnProcessNextFailure(currentNugetVersion: string | undefined) {
return isFeatureSupported({ feature: 'UNLOCKING_ON_PROCESS_NEXT_FAILURE', currentNugetVersion });
}

export function appSupportsNewAttachmentAPI(currentNugetVersion: string | undefined) {
return isFeatureSupported({ feature: 'NEW_ATTACHMENTS_API', currentNugetVersion });
}

/**
* TODO(Subform): Make sure we reference the correct version here, and in applicationMetadataMock
*
* Prior to app-lib version 8.5.0 there was no way of identifying validation messages that were not run incrementally (ITaskValidator),
* this led to an edge case where if an ITaskValidator returned a validation message with a field, we could not
* distinguish this from a regular custom backend validation which does runs incrementally. The problem is that we block
* submit when we have custom backend validation errors until they are fixed, but since ITaskValidator is not run
* incrementally it would never get fixed until the user refreshed the page. This issue was somewhat mitigated
* by the old dataElement validation API which did not run ITaskValidators.
*
* Therefore, if this function returns false, this means that the app does not make this distinction, but
* has the old API available, so this needs to be used for backwards compatibility.
*/
export function appSupportsIncrementalValidationFeatures(currentNugetVersion: string | undefined) {
return isFeatureSupported({ feature: 'INCREMENTAL_VALIDATION', currentNugetVersion });
}
Loading