Skip to content

Conversation

cammiida
Copy link
Contributor

@cammiida cammiida commented Aug 27, 2025

Description

Related Issue(s)

  • closes #{issue number}

Verification/QA

  • Manual functionality testing
    • I have tested these changes manually
    • Creator of the original issue (or service owner) has been contacted for manual testing (or will be contacted when released in alpha)
    • No testing done/necessary
  • Automated tests
    • Unit test(s) have been added/updated
    • Cypress E2E test(s) have been added/updated
    • No automatic tests are needed here (no functional changes/additions)
    • I want someone to help me make some tests
  • UU/WCAG (follow these guidelines until we have our own)
    • I have tested with a screen reader/keyboard navigation/automated wcag validator
    • No testing done/necessary (no DOM/visual changes)
    • I want someone to help me perform accessibility testing
  • User documentation @ altinn-studio-docs
    • Has been added/updated
    • No functionality has been changed/added, so no documentation is needed
    • I will do that later/have created an issue
  • Support in Altinn Studio
    • Issue(s) created for support in Studio
    • This change/feature does not require any changes to Altinn Studio
  • Sprint board
    • The original issue (or this PR itself) has been added to the Team Apps project and to the current sprint board
    • I don't have permissions to do that, please help me out
  • Labels
    • I have added a kind/* and backport* label to this PR for proper release notes grouping
    • I don't have permissions to add labels, please help me out

Summary by CodeRabbit

  • New Features

    • Added single-call "set tags" support with optimistic UI updates and automatic fallback to legacy add/remove when unsupported.
  • Bug Fixes

    • Improved backend validation mapping so tag- and form-related validation issues surface more reliably.
  • Refactor

    • Standardized HTTP response shapes (.data) and migrated identifiers from dataGuid to dataElementId across APIs.
  • Tests

    • Updated tests/mocks to reflect wrapped Axios-style responses.
  • Chores

    • Added feature-flag/version check for the new tags endpoint and updated public validation type names.

Copy link

coderabbitai bot commented Aug 27, 2025

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

📝 Walkthrough

Walkthrough

Adds a version-gated attachment Set Tags API with legacy fallback, backend-backed attachment removal, widened AxiosResponse (.data) consumption across network and consumers, validation-type renames and new mapping utilities, widespread identifier renames from dataModelGuid → dataElementId, URL/versioning helpers, and corresponding test/mock updates.

Changes

Cohort / File(s) Summary
Attachments plugin & exports
src/features/attachments/AttachmentsStorePlugin.tsx, src/features/attachments/index.ts
Adds internal mutations useAttachmentUpdateTagsMutation and useAttachmentsRemoveMutation; useAttachmentsUpdate branches between new Set Tags endpoint and legacy add/remove based on appSupportsSetTagsEndpoint; makes useAttachmentsUploadMutation non-exported; maps backend validation issues through validator-groups to data-model validations; updates DataPostResponse.validationIssues to BackendValidationIssuesWithSource[].
Queries & types (attachments + tags)
src/queries/queries.ts, src/queries/types.ts, src/utils/urls/appUrlHelper.ts
Adds doUpdateAttachmentTags and exported SetTagsRequest type; introduces internal UpdateTagsResponse using BackendValidationIssuesWithSource; adapts many endpoints to use dataElementId (replacing dataGuid) and adds getUpdateFileTagsUrl; adds doUpdateAttachmentTags to ignored queries list; removes fetchProcessNextSteps export.
Versioning feature flag
src/utils/versioning/versions.ts
Adds SET_TAGS_ENDPOINT to feature map and exports appSupportsSetTagsEndpoint(currentNugetVersion) wrapper.
Validation types & mapping utilities
src/features/validation/index.ts, src/features/validation/backendValidation/backendValidationUtils.ts, src/features/validation/backendValidation/BackendValidation.tsx, src/features/validation/validationContext.tsx, src/features/validation/backendValidation/backendValidationQuery.ts
Renames public type BackendValidationIssueGroupListItemBackendValidationIssuesWithSource; mapBackendIssuesToTaskValidations accepts undefined; adds mapBackendValidationsToValidatorGroups; refactors mapValidatorGroupsToDataModelValidations signature; updates BackendValidation component to use new mapping helpers and remove dataTypes prop.
Network helpers (Axios response shape)
src/utils/network/networking.ts, src/utils/network/sharedNetworking.ts
httpPost/httpPatch/httpPut now return AxiosResponse<T> (callers must read .data); redundant awaits removed; signatures updated.
FormData & consumers: response shape & types
src/features/formData/FormDataWrite.tsx, src/features/formData/types.ts, src/features/formData/FormData.test.tsx, src/features/formData/useDataModelBindings.test.tsx, src/layout/RepeatingGroup/Providers/OpenByDefaultProvider.test.tsx, src/test/renderWithProviders.tsx
Consumers of patch endpoints now unwrap payload via .data; IDataModelMultiPatchResponse.validationIssues changed to BackendValidationIssuesWithSource[]; multiple tests and test mocks updated to resolve with { data: ... }.
Process-next and tests alignment
src/features/instance/useProcessNext.tsx, src/features/processEnd/confirm/containers/ConfirmPage.test.tsx, src/setupTests.ts
useProcessNext now unwraps AxiosResponse .data; tests and global setup adjusted to mock doProcessNext returning AxiosResponse<IProcess> shapes (including a non-resolving AxiosResponse in one test).
Identifier rename: dataModelGuid → dataElementId (wide)
src/core/contexts/taskStoreContext.tsx, src/features/datamodel/*, src/layout/*, src/features/pdf/usePdfFormatQuery.ts, src/features/receipt/*, src/layout/Subform/*, src/layout/Summary2/*, src/queries/formPrefetcher.ts, src/features/validation/*
Widespread renames: overriddenDataModelUuidoverriddenDataElementId, hook renames (e.g., useCurrentDataModelGuiduseCurrentDataElementId), function/signature updates to accept dataElementId instead of dataGuid, and test fixture updates to use exampleDataElementId.
Tests, e2e helpers & mocks: types and shapes
test/e2e/support/global.ts, src/test/renderWithProviders.tsx, src/setupTests.ts, src/features/processEnd/confirm/containers/ConfirmPage.test.tsx, various other tests
Replace imports/usages of BackendValidationIssueGroupListItem with BackendValidationIssuesWithSource; fix BackendValdiationPredicateBackendValidationPredicate; adjust mocks to return Axios-style { data: ... } where network helpers now return AxiosResponse.
Misc small updates
src/layout/CustomButton/CustomButtonComponent.tsx, src/features/receipt/ReceiptContainer.tsx, src/features/pdf/usePdfFormatQuery.ts, src/utils/urls/appUrlHelper.test.ts
Type index signatures updated to [dataElementId: string]; consumer hooks and local vars renamed to dataElementId; tests updated to new identifier names or URLs.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Pre-merge checks (1 passed, 2 warnings)

❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Description Check ⚠️ Warning The current description remains as the unedited template with placeholder comments and lacks any summary of the actual changes, a valid issue reference, or completed QA and testing details, so it does not meet the repository’s required structure or content. Please replace the placeholder comments with a concise summary of what the pull request accomplishes, provide the actual issue number in the “Related Issue(s)” section, and mark or update the relevant Verification/QA checklist items to reflect the work that has been performed.
Docstring Coverage ⚠️ Warning Docstring coverage is 17.95% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (1 passed)
Check name Status Explanation
Title Check ✅ Passed The title succinctly highlights the primary functional change—switching to the new “update tags” endpoint and updating validation state based on its response—which matches the core changes in the pull request without extraneous detail. It clearly conveys the main developer intent and is specific enough for a reviewer to understand the focus at a glance. The phrasing is concise, technical yet clear, and avoids unnecessary lists or filler.
✨ Finishing Touches
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/validate-tags

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@cammiida cammiida added kind/product-feature Pull requests containing new features backport-ignore This PR is a new feature and should not be cherry-picked onto release branches labels Aug 27, 2025
@cammiida cammiida self-assigned this Aug 27, 2025
Base automatically changed from chore/versioning-cleanup to main September 1, 2025 11:18
@cammiida cammiida force-pushed the feature/validate-tags branch from aa3632b to 0ecc7b5 Compare September 1, 2025 12:20
@cammiida cammiida marked this pull request as ready for review September 1, 2025 13:21
@@ -8,6 +8,7 @@ export const FEATURE_VERSION_MAP = {
NEW_ATTACHMENTS_API: '8.5.0.153',
PDF_PREVIEW_BUTTON: '8.5.0.157',
APP_LANGUAGES_IN_ANONYMOUS: '8.5.6.180',
SET_TAGS_ENDPOINT: '8.8.0.0',
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Needs to wait until this is verified (that is, the new endpoint is released and the release version corresponds with the version set here)

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
src/utils/network/networking.ts (1)

31-37: Unify return typing and config generic for httpPost to preserve T and align with other wrappers

Return type is widened to AxiosResponse due to missing generic on AxiosResponse, and config isn’t generic over D. Keep the existing param order to avoid churn, but tighten the types.

Apply:

-export async function httpPost<T, D = unknown>(
-  url: string,
-  options?: AxiosRequestConfig,
-  data?: D,
-): Promise<AxiosResponse> {
-  return axios.post<T, AxiosResponse<T>, D>(url, data, options);
-}
+export async function httpPost<T, D = unknown>(
+  url: string,
+  options?: AxiosRequestConfig<D>,
+  data?: D,
+): Promise<AxiosResponse<T>> {
+  return axios.post<T, AxiosResponse<T>, D>(url, data, options);
+}
src/features/validation/backendValidation/backendValidationUtils.ts (1)

164-168: Remove unreachable legacy fallback

This condition is always false (legacyText === issue.code). Drop it to avoid confusion.

-  // Fallback to old behavior if source not set.
-  const legacyText = issue.code;
-  if (legacyText !== issue.code) {
-    return { key: legacyText };
-  }
🧹 Nitpick comments (16)
src/utils/versioning/versions.ts (1)

11-12: Add unit test for SET_TAGS_ENDPOINT
Extend existing isFeatureSupported tests to assert the new SET_TAGS_ENDPOINT threshold (8.8.0.0) via appSupportsSetTagsEndpoint.

src/features/validation/index.ts (1)

106-115: Type rename is fine; offer a compatibility alias to reduce churn

If downstreams still import the old name, provide a temporary alias.

 export type BackendValidationIssuesWithSource = {
   source: string;
   issues: BackendValidationIssue[];
 };
+
+// Backwards-compat alias (deprecated; remove after callers migrate)
+export type BackendValidationIssueGroupListItem = BackendValidationIssuesWithSource;
src/features/validation/backendValidation/backendValidationUtils.ts (1)

107-109: Type the shared empties to avoid implicit any

Give these precise types to satisfy our TS guideline and reduce accidental misuse.

-const emptyObject = {};
-const emptyArray = [];
+const emptyObject: BackendFieldValidatorGroups = {};
+const emptyArray: BaseValidation[] = [];
src/features/validation/backendValidation/BackendValidation.tsx (2)

25-28: Consider memoizing initial validator groups

Recomputing this object on each render may retrigger the effect due to identity changes. Memoize to stabilize deps.

-import type { BackendFieldValidatorGroups } from 'src/features/validation';
+import type { BackendFieldValidatorGroups } from 'src/features/validation';
+import { useMemo } from 'react';
@@
-const initialValidatorGroups: BackendFieldValidatorGroups = mapBackendValidationsToValidatorGroups(
-  initialValidations,
-  defaultDataElementId,
-);
+const initialValidatorGroups: BackendFieldValidatorGroups = useMemo(
+  () => mapBackendValidationsToValidatorGroups(initialValidations, defaultDataElementId),
+  [initialValidations, defaultDataElementId],
+);

31-31: Likewise, memoize task validations

Small stability win for the effect deps.

-const initialTaskValidations = mapBackendIssuesToTaskValidations(initialValidations);
+const initialTaskValidations = useMemo(
+  () => mapBackendIssuesToTaskValidations(initialValidations),
+  [initialValidations],
+);
src/features/instance/useProcessNext.tsx (1)

45-47: Deduplicate hook usage

useOnFormSubmitValidation() is called twice; keep one instance to avoid redundancy.

-  const onFormSubmitValidation = useOnFormSubmitValidation();
+  const onFormSubmitValidation = useOnFormSubmitValidation();
@@
-  const onSubmitFormValidation = useOnFormSubmitValidation();
src/features/formData/FormData.test.tsx (1)

683-683: Fix typo in test description.

"Invaid data" → "Invalid data".

-describe('Invaid data', () => {
+describe('Invalid data', () => {
src/utils/urls/appUrlHelper.ts (2)

52-56: Confirm server expects comma-separated ignoredValidators; consider safer encoding.

Using join(',') may not match API expectations if the backend expects repeated params. Prefer appending multiple ignoredValidators entries for robustness.

-export const getUpdateFileTagsUrl = (instanceId: string, dataGuid: string) => {
-  const searchParams = new URLSearchParams({ ignoredValidators: IgnoredValidators.join(',') });
-  return `${appPath}/instances/${instanceId}/data/${dataGuid}/tags?${searchParams}`;
-};
+export const getUpdateFileTagsUrl = (instanceId: string, dataGuid: string) => {
+  const params = new URLSearchParams();
+  for (const v of IgnoredValidators) {
+    params.append('ignoredValidators', String(v));
+  }
+  return `${appPath}/instances/${instanceId}/data/${dataGuid}/tags?${params.toString()}`;
+};

1-1: Optional: add language support and reuse url helper for consistency.

If this endpoint returns validations/messages, consider supporting language like other URLs.

-import { IgnoredValidators } from 'src/features/validation';
+import { IgnoredValidators } from 'src/features/validation';
+import { getQueryStringFromObject } from 'src/utils/urls/urlHelper';
@@
-export const getUpdateFileTagsUrl = (instanceId: string, dataGuid: string) => {
-  const searchParams = new URLSearchParams({ ignoredValidators: IgnoredValidators.join(',') });
-  return `${appPath}/instances/${instanceId}/data/${dataGuid}/tags?${searchParams}`;
-};
+export const getUpdateFileTagsUrl = (instanceId: string, dataGuid: string, language?: string) => {
+  const queryString = getQueryStringFromObject({
+    language,
+    // If backend supports repeated params, switch to multiple keys instead of join
+    ignoredValidators: IgnoredValidators.join(','),
+  });
+  return `${appPath}/instances/${instanceId}/data/${dataGuid}/tags${queryString}`;
+};

Also applies to: 52-56

src/features/formData/FormDataWrite.tsx (2)

285-287: Harden against undefined validationIssues from backend.

Defensively handle missing validationIssues to avoid runtime errors.

-          const validationIssueGroups: BackendValidationIssueGroups = Object.fromEntries(
-            validationIssues.map(({ source, issues }) => [source, issues]),
-          );
+          const validationIssueGroups: BackendValidationIssueGroups = Object.fromEntries(
+            (validationIssues ?? []).map(({ source, issues }) => [source, issues]),
+          );

310-317: Align single-patch call with multi-patch by passing language.

Multi-patch includes language via getUrlWithLanguage, but single-patch does not. This can cause inconsistent localization of validation messages.

-          const { newDataModel, validationIssues, instance } = (
-            await doPatchFormData(url, {
+          const { newDataModel, validationIssues, instance } = (
+            await doPatchFormData(getUrlWithLanguage(url, currentLanguage.current), {
               patch,
               // Ignore validations that require layout parsing in the backend which will slow down requests significantly
               ignoredValidators: IgnoredValidators,
             })
           ).data;
src/features/processEnd/confirm/containers/ConfirmPage.test.tsx (1)

6-6: Use type-only import for AxiosResponse.

Slight perf/readability win in TS contexts.

-import { AxiosResponse } from 'axios';
+import type { AxiosResponse } from 'axios';
src/setupTests.ts (1)

14-14: Mock AxiosResponse without casting and include minimal required fields.

Avoid as AxiosResponse casts; return a response object that satisfies the type.

-  doProcessNext: jest.fn<typeof doProcessNext>(async () => ({ data: getProcessDataMock() }) as AxiosResponse<IProcess>),
+  doProcessNext: jest.fn<typeof doProcessNext>(async () =>
+    ({
+      data: getProcessDataMock(),
+      status: 200,
+      statusText: 'OK',
+      headers: {},
+      config: {},
+    } satisfies AxiosResponse<IProcess>),
+  ),

Also applies to: 29-29, 122-122

src/test/renderWithProviders.tsx (1)

423-437: Return AxiosResponse-shaped object for doPatchFormData mock.

Keeps tests aligned with production shape and removes reliance on structural subtyping.

-    .mockImplementation(
-      async (url: string, req: IDataModelPatchRequest): Promise<{ data: IDataModelPatchResponse }> => {
+    .mockImplementation(
+      async (url: string, req: IDataModelPatchRequest): Promise<AxiosResponse<IDataModelPatchResponse>> => {
         const model = structuredClone(models[url] ?? {});
         applyPatch(model, req.patch);
         const afterProcessing = typeof mockBackend === 'function' ? mockBackend(model, url) : model;
         models[url] = afterProcessing;
 
-        return {
-          data: {
-            newDataModel: afterProcessing as object,
-            validationIssues: {},
-          },
-        };
+        return {
+          data: {
+            newDataModel: afterProcessing as object,
+            validationIssues: {},
+          },
+          status: 200,
+          statusText: 'OK',
+          headers: {},
+          config: {},
+        };
       },
     );
src/queries/queries.ts (1)

163-185: Add explicit return type and keep Axios semantics clear.

Annotate return type for the new API to make the public surface unambiguous.

-export const doUpdateAttachmentTags = async ({
+export const doUpdateAttachmentTags = async ({
   instanceId,
   dataGuid,
   setTagsRequest,
 }: {
   instanceId: string;
   dataGuid: string;
   setTagsRequest: SetTagsRequest;
-}) => {
+}): Promise<UpdateTagsResponse> => {
   const url = getUpdateFileTagsUrl(instanceId, dataGuid);
   const response = await httpPut<UpdateTagsResponse, SetTagsRequest>(url, setTagsRequest, {
     headers: {
       'Content-Type': 'application/json',
     },
   });
src/features/attachments/AttachmentsStorePlugin.tsx (1)

29-36: Consider DI via AppMutations for doUpdateAttachmentTags.

Directly importing the query makes test injection harder; exposing it via AppMutations keeps consistency with other mutations.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between a0bb9b4 and bd0dd01.

📒 Files selected for processing (20)
  • src/features/attachments/AttachmentsStorePlugin.tsx (9 hunks)
  • src/features/attachments/index.ts (2 hunks)
  • src/features/formData/FormData.test.tsx (2 hunks)
  • src/features/formData/FormDataWrite.tsx (2 hunks)
  • src/features/formData/types.ts (2 hunks)
  • src/features/formData/useDataModelBindings.test.tsx (2 hunks)
  • src/features/instance/useProcessNext.tsx (1 hunks)
  • src/features/processEnd/confirm/containers/ConfirmPage.test.tsx (2 hunks)
  • src/features/validation/backendValidation/BackendValidation.tsx (1 hunks)
  • src/features/validation/backendValidation/backendValidationUtils.ts (2 hunks)
  • src/features/validation/index.ts (1 hunks)
  • src/layout/RepeatingGroup/Providers/OpenByDefaultProvider.test.tsx (1 hunks)
  • src/queries/queries.ts (3 hunks)
  • src/queries/types.ts (1 hunks)
  • src/setupTests.ts (3 hunks)
  • src/test/renderWithProviders.tsx (1 hunks)
  • src/utils/network/networking.ts (1 hunks)
  • src/utils/network/sharedNetworking.ts (1 hunks)
  • src/utils/urls/appUrlHelper.ts (2 hunks)
  • src/utils/versioning/versions.ts (2 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx}: Avoid using any and unnecessary type casts (as Type) in TypeScript; prefer precise typings and refactor existing casts/anys
For TanStack Query, use objects to manage query keys and functions, and centralize shared options via queryOptions

Files:

  • src/features/instance/useProcessNext.tsx
  • src/features/formData/FormDataWrite.tsx
  • src/layout/RepeatingGroup/Providers/OpenByDefaultProvider.test.tsx
  • src/features/formData/useDataModelBindings.test.tsx
  • src/features/validation/index.ts
  • src/utils/urls/appUrlHelper.ts
  • src/features/formData/types.ts
  • src/utils/network/networking.ts
  • src/features/attachments/index.ts
  • src/features/validation/backendValidation/BackendValidation.tsx
  • src/queries/types.ts
  • src/features/processEnd/confirm/containers/ConfirmPage.test.tsx
  • src/features/formData/FormData.test.tsx
  • src/utils/versioning/versions.ts
  • src/utils/network/sharedNetworking.ts
  • src/features/validation/backendValidation/backendValidationUtils.ts
  • src/test/renderWithProviders.tsx
  • src/features/attachments/AttachmentsStorePlugin.tsx
  • src/queries/queries.ts
  • src/setupTests.ts
**/*.test.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

In tests, use renderWithProviders from src/test/renderWithProviders.tsx to supply required form layout context

Files:

  • src/layout/RepeatingGroup/Providers/OpenByDefaultProvider.test.tsx
  • src/features/formData/useDataModelBindings.test.tsx
  • src/features/processEnd/confirm/containers/ConfirmPage.test.tsx
  • src/features/formData/FormData.test.tsx
🧠 Learnings (1)
📚 Learning: 2025-08-22T13:53:28.252Z
Learnt from: CR
PR: Altinn/app-frontend-react#0
File: CLAUDE.md:0-0
Timestamp: 2025-08-22T13:53:28.252Z
Learning: Applies to **/*.test.{ts,tsx} : In tests, use `renderWithProviders` from `src/test/renderWithProviders.tsx` to supply required form layout context

Applied to files:

  • src/test/renderWithProviders.tsx
🧬 Code graph analysis (11)
src/features/formData/FormDataWrite.tsx (3)
src/queries/queries.ts (2)
  • doPatchMultipleFormData (240-241)
  • doPatchFormData (236-237)
src/utils/urls/urlHelper.ts (1)
  • getUrlWithLanguage (137-151)
src/features/validation/index.ts (1)
  • IgnoredValidators (23-27)
src/utils/urls/appUrlHelper.ts (1)
src/features/validation/index.ts (1)
  • IgnoredValidators (23-27)
src/features/formData/types.ts (1)
src/features/validation/index.ts (1)
  • BackendValidationIssuesWithSource (106-109)
src/features/attachments/index.ts (1)
src/features/validation/index.ts (1)
  • BackendValidationIssuesWithSource (106-109)
src/features/validation/backendValidation/BackendValidation.tsx (5)
src/features/validation/validationContext.tsx (1)
  • Validation (319-374)
src/features/datamodel/DataModelsProvider.tsx (1)
  • DataModels (394-435)
src/features/validation/index.ts (1)
  • BackendFieldValidatorGroups (117-119)
src/features/validation/backendValidation/backendValidationUtils.ts (3)
  • useShouldValidateInitial (30-36)
  • mapBackendValidationsToValidatorGroups (129-147)
  • mapBackendIssuesToTaskValidations (110-127)
src/features/validation/backendValidation/backendValidationQuery.ts (1)
  • useBackendValidationQuery (129-172)
src/features/processEnd/confirm/containers/ConfirmPage.test.tsx (2)
src/types/shared.ts (1)
  • IProcess (194-201)
src/queries/queries.ts (1)
  • doProcessNext (98-99)
src/features/validation/backendValidation/backendValidationUtils.ts (1)
src/features/validation/index.ts (3)
  • BackendValidationIssue (205-217)
  • BaseValidation (121-127)
  • BackendFieldValidatorGroups (117-119)
src/test/renderWithProviders.tsx (1)
src/features/formData/types.ts (2)
  • IDataModelPatchRequest (41-44)
  • IDataModelPatchResponse (46-50)
src/features/attachments/AttachmentsStorePlugin.tsx (7)
src/features/instance/InstanceContext.tsx (3)
  • useOptimisticallyUpdateDataElement (212-220)
  • useLaxInstanceId (69-73)
  • useOptimisticallyRemoveDataElement (221-229)
src/features/applicationMetadata/ApplicationMetadataProvider.tsx (1)
  • useApplicationMetadata (67-67)
src/utils/versioning/versions.ts (1)
  • appSupportsSetTagsEndpoint (67-69)
src/queries/queries.ts (2)
  • SetTagsRequest (154-156)
  • doUpdateAttachmentTags (163-184)
src/features/datamodel/DataModelsProvider.tsx (1)
  • DataModels (394-435)
src/features/validation/validationContext.tsx (1)
  • Validation (319-374)
src/features/validation/backendValidation/backendValidationUtils.ts (3)
  • mapBackendIssuesToTaskValidations (110-127)
  • mapBackendValidationsToValidatorGroups (129-147)
  • mapValidatorGroupsToDataModelValidations (177-205)
src/queries/queries.ts (3)
src/features/validation/index.ts (1)
  • BackendValidationIssuesWithSource (106-109)
src/utils/urls/appUrlHelper.ts (1)
  • getUpdateFileTagsUrl (52-56)
src/utils/network/sharedNetworking.ts (1)
  • httpPut (15-17)
src/setupTests.ts (3)
src/queries/queries.ts (1)
  • doProcessNext (98-99)
src/__mocks__/getProcessDataMock.ts (1)
  • getProcessDataMock (3-34)
src/types/shared.ts (1)
  • IProcess (194-201)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Install
  • GitHub Check: Install
🔇 Additional comments (19)
src/utils/network/networking.ts (1)

43-45: Make httpDelete generic (expose T) and type its return
Expose T on AxiosResponse to propagate payload types downstream—call-site scan found only uses of .data and .status, so the generic default is safe.

-export async function httpDelete(url: string, options?: AxiosRequestConfig): Promise<AxiosResponse> {
-  return axios.delete(url, options);
-}
+export async function httpDelete<T = unknown>(
+  url: string,
+  options?: AxiosRequestConfig,
+): Promise<AxiosResponse<T>> {
+  return axios.delete<T, AxiosResponse<T>>(url, options);
+}
src/queries/types.ts (1)

3-12: doUpdateAttachmentTags is internal-only – exclusion from AppMutations/AppQueries is correct
Verified that doUpdateAttachmentTags is only called in AttachmentsStorePlugin and never exposed via AppQueriesContext or referenced in tests; keeping it in IgnoredQueriesAndMutations is intentional.

src/utils/network/sharedNetworking.ts (1)

15-17: Make httpPut return type explicit and config generic over D

Avoid silent breaking changes and align with the other wrappers.

-export async function httpPut<T, D = unknown>(url: string, data: D, config?: AxiosRequestConfig) {
-  return axios.put<T, AxiosResponse<T>, D>(url, data, config);
-}
+export async function httpPut<T, D = unknown>(
+  url: string,
+  data: D,
+  config?: AxiosRequestConfig<D>,
+): Promise<AxiosResponse<T>> {
+  return axios.put<T, AxiosResponse<T>, D>(url, data, config);
+}

No httpPut call sites were found during search—please manually verify there are no existing usages relying on the implicit return type before merging.

src/utils/versioning/versions.ts (1)

67-69: The script above will list all mock files and verify whether FEATURE_VERSION_MAP and applicationMetadata appear in them. Once you’ve reviewed its output, you can update any mocks to include the new SET_TAGS_ENDPOINT entry under your version map fixture.

src/features/validation/index.ts (1)

112-115: Function signature updated; LGTM

The updated parameter type matches the renamed alias; logic unchanged.

src/features/validation/backendValidation/backendValidationUtils.ts (2)

110-114: LGTM: undefined-safe task validations

Accepting undefined and returning a typed empty array is correct and simplifies call sites.


129-147: LGTM: grouping field validations by source

The grouping logic is straightforward and correctly ignores task-level validations for initial load.

src/features/formData/useDataModelBindings.test.tsx (1)

162-163: LGTM: mocks now match Axios-like shape

Wrapping patch responses in { data: ... } aligns tests with the new response contracts.

Also applies to: 206-206

src/features/instance/useProcessNext.tsx (2)

75-75: LGTM: consume Axios payload via .data

Extracting process from { data } matches the updated query/mocking strategy.


109-112: No change required
useOnFormSubmitValidation returns true when validation errors exist (as seen in its call sites using hasErrors) so the negation if (!hasValidationErrors) correctly fires setShowAllBackendErrors() only when there are no client-side errors.

src/layout/RepeatingGroup/Providers/OpenByDefaultProvider.test.tsx (1)

145-149: LGTM: response wrapped in data

This aligns with the global shift to AxiosResponse-shaped mocks.

src/features/formData/types.ts (1)

4-6: Approve changes – old type alias fully removed
No occurrences of BackendValidationIssueGroupListItem found in src/** after verification.

src/features/formData/FormData.test.tsx (1)

516-517: Axios-like mock shape is aligned with production code.

Wrapping resolve payloads in { data } matches the new httpPatch return type usage. LGTM.

Also applies to: 578-579

src/features/formData/FormDataWrite.tsx (1)

267-274: Switch to AxiosResponse.data is correct.

Destructuring from .data matches the updated httpPatch wrappers. LGTM.

Also applies to: 310-317

src/features/attachments/index.ts (1)

4-4: Type alignment with validation layer looks good.

Import and DataPostResponse.validationIssues updated to BackendValidationIssuesWithSource[]. LGTM.

Also applies to: 36-37

src/features/processEnd/confirm/containers/ConfirmPage.test.tsx (1)

87-93: Non-resolving promise pattern is fine; watch for open handle warnings.

Good adaptation to AxiosResponse. If Jest warns about open handles, reset the mock at the end of the test.

   jest.mocked(doProcessNext).mockImplementation(async () => processNextPromise);
+  // After assertions (or in afterEach)
+  jest.mocked(doProcessNext).mockReset();
src/queries/queries.ts (1)

154-162: Types for request/response look good.

Exporting SetTagsRequest is appropriate; keep UpdateTagsResponse internal.

src/features/attachments/AttachmentsStorePlugin.tsx (2)

736-757: LGTM: remove mutation uses optimistic instance update.

Good UX; errors are logged and the store action handles node data.


713-734: LGTM: upload mutation aligned with new API.

Clear separation from legacy flow and solid error handling.

@cammiida cammiida force-pushed the feature/validate-tags branch from 3f0f01d to 653abf4 Compare September 1, 2025 13:59
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (8)
src/queries/queries.ts (4)

152-159: Types for request/response are clear; consider exporting the response type

If callers/tests need to type the mutation result explicitly, exporting UpdateTagsResponse could help. If not needed externally, keeping it internal is fine.

-type UpdateTagsResponse = {
+export type UpdateTagsResponse = {
   tags: string[];
   validationIssues: BackendValidationIssuesWithSource[];
 };

161-179: New update-tags mutation: add explicit return type and tighten status handling

Small refinements for a stronger API contract and clearer failures.

-export const doUpdateAttachmentTags = async ({
+export const doUpdateAttachmentTags = async ({
   instanceId,
   dataGuid,
   setTagsRequest,
 }: {
   instanceId: string;
   dataGuid: string;
   setTagsRequest: SetTagsRequest;
-}) => {
+}): Promise<UpdateTagsResponse> => {
   const url = getUpdateFileTagsUrl(instanceId, dataGuid);
-  const response = await httpPut<UpdateTagsResponse, SetTagsRequest>(url, setTagsRequest, {
-    headers: {
-      'Content-Type': 'application/json',
-    },
-  });
-
-  if (response.status !== 200) {
-    throw new Error('Failed to update tags on attachment');
-  }
+  const response = await httpPut<UpdateTagsResponse, SetTagsRequest>(url, setTagsRequest, {
+    headers: { 'Content-Type': 'application/json' },
+    // Fail fast unless exactly 200, since we rely on response payload
+    validateStatus: (s) => s === 200,
+  });
   return response.data;
 };

199-207: Include action and status in error message for easier debugging (optional)

Improves observability without changing behavior.

-  if (response.status !== 200) {
-    throw new Error('Failed to perform action');
-  }
+  if (response.status !== 200) {
+    throw new Error(`Failed to perform action "${actionRequest.action ?? 'unknown'}" (HTTP ${response.status})`);
+  }

246-251: Make stateless form-data POST generic to avoid object

This tightens typing for callers without behavior changes.

-export const doPostStatelessFormData = async (
-  url: string,
-  data: object,
-  options?: AxiosRequestConfig,
-): Promise<object> => (await httpPost<object>(url, options, data)).data;
+export const doPostStatelessFormData = async <T extends object>(
+  url: string,
+  data: T,
+  options?: AxiosRequestConfig,
+): Promise<T> => (await httpPost<T>(url, options, data)).data;
src/features/validation/backendValidation/backendValidationUtils.ts (4)

124-124: Avoid magic number for category; use a named mask/constant

category: 0 is unclear. Prefer a named enum/member (e.g., ValidationMask.None/Task) or a local constant to document intent.

If no suitable mask exists, add:

// near severityMap
const TASK_VALIDATION_CATEGORY = 0;

Then:

-    taskValidations.push({ severity, message, category: 0, source, noIncrementalUpdates });
+    taskValidations.push({ severity, message, category: TASK_VALIDATION_CATEGORY, source, noIncrementalUpdates });

Please confirm downstream consumers expect 0 here (always-visible task validation).


139-145: Harden dictionary creation against prototype keys from backend-controlled strings

validatorGroups uses a plain object and keys come from validation.source (backend-controlled). Defensive: create a null-prototype map to avoid surprises with keys like __proto__/constructor.

-  const validatorGroups: BackendFieldValidatorGroups = {};
+  const validatorGroups: BackendFieldValidatorGroups = Object.create(null);

183-185: Docs nit: data “elements”, not “types”

The param was renamed; update the comment to match.

-  // We need to clear all data types regardless if there are any validations or not
-  // Otherwise it would not update if there are no validations for a data type any more
+  // We need to clear all data elements regardless of whether there are any validations
+  // Otherwise it would not update if there are no validations for a data element anymore

164-169: Unreachable branch in legacy text fallback

legacyText is assigned from issue.code, so legacyText !== issue.code can never be true. Remove the dead branch.

-  const legacyText = issue.code;
-  if (legacyText !== issue.code) {
-    return { key: legacyText };
-  }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 3f0f01d and 653abf4.

📒 Files selected for processing (4)
  • src/features/attachments/AttachmentsStorePlugin.tsx (9 hunks)
  • src/features/validation/backendValidation/backendValidationUtils.ts (3 hunks)
  • src/queries/queries.ts (9 hunks)
  • src/utils/network/networking.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/features/attachments/AttachmentsStorePlugin.tsx
  • src/utils/network/networking.ts
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx}: Avoid using any and unnecessary type casts (as Type) in TypeScript; prefer precise typings and refactor existing casts/anys
For TanStack Query, use objects to manage query keys and functions, and centralize shared options via queryOptions

Files:

  • src/queries/queries.ts
  • src/features/validation/backendValidation/backendValidationUtils.ts
🧬 Code graph analysis (2)
src/queries/queries.ts (7)
src/features/instance/instanceUtils.ts (1)
  • removeProcessFromInstance (6-9)
src/utils/network/networking.ts (1)
  • httpPost (31-37)
src/types/shared.ts (2)
  • IInstance (70-89)
  • IData (34-54)
src/utils/urls/appUrlHelper.ts (3)
  • getUpdateFileTagsUrl (52-56)
  • getActionsUrl (82-85)
  • getDataModelTypeUrl (75-76)
src/features/attachments/index.ts (1)
  • DataPostResponse (33-38)
src/features/validation/index.ts (1)
  • BackendValidationIssuesWithSource (106-109)
src/utils/network/sharedNetworking.ts (1)
  • httpPut (15-17)
src/features/validation/backendValidation/backendValidationUtils.ts (1)
src/features/validation/index.ts (4)
  • BackendValidationIssue (205-217)
  • BaseValidation (121-127)
  • BackendFieldValidatorGroups (117-119)
  • DataModelValidations (88-90)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (7)
  • GitHub Check: Cypress Run Internal (1)
  • GitHub Check: Cypress Run Internal (3)
  • GitHub Check: Cypress Run Internal (6)
  • GitHub Check: Cypress Run Internal (5)
  • GitHub Check: Cypress Run Internal (4)
  • GitHub Check: Cypress Run Internal (2)
  • GitHub Check: Type-checks, eslint, unit tests and SonarCloud
🔇 Additional comments (6)
src/queries/queries.ts (5)

43-43: Import of update-tags URL helper looks correct

The new helper is used below and the import path matches existing URL helpers.


68-72: Validation types import aligns with new response shape

Brings in the exact types needed for the update-tags response and custom validation config.


92-97: Consistent switch to returning .data from httpPost

Good cleanup and consistent with the typed HTTP helpers.


112-112: Attachment upload functions: return .data directly

Looks good and consistent with axios defaults (non-2xx will reject).

Also applies to: 131-131


223-228: Typed post for subform entry: LGTM

Generic usage is correct and retains existing status check semantics.

src/features/validation/backendValidation/backendValidationUtils.ts (1)

136-147: mapBackendValidationsToValidatorGroups intentionally omits task-level validations; those are handled via mapBackendIssuesToTaskValidations and passed separately to updateBackendValidations. No change required.

Likely an incorrect or invalid review comment.

@cammiida
Copy link
Contributor Author

cammiida commented Sep 5, 2025

/publish

Copy link
Contributor

github-actions bot commented Sep 5, 2025

PR release:

  • <link rel="stylesheet" type="text/css" href="https://altinncdn.no/toolkits/altinn-app-frontend/4.21.0-pr.2142.validate-tags.1f7aee5a/altinn-app-frontend.css">
  • <script src="https://altinncdn.no/toolkits/altinn-app-frontend/4.21.0-pr.2142.validate-tags.1f7aee5a/altinn-app-frontend.js"></script>

⚙️ Building...
✅ Done!

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (1)
src/utils/versioning/versions.ts (1)

11-12: Confirm the exact backend release version for the Update Tags endpoint

Please verify that 8.7.0.0 is the first app-lib version that exposes the new update-tags endpoint. Also confirm that the runtime provides a four-part version (e.g., 8.7.0.0) to avoid compare mismatches if some environments still report 8.7.0.

Run to cross-check usage and version boundaries:

#!/bin/bash
# Find all call sites toggled by this feature
rg -nP --type=ts -C3 'appSupports(Set|Update)TagsEndpoint\('

# Sanity-check isAtLeastVersion boundary tests exist referencing "8.7.0.0"
rg -nP --type=ts -C2 "8\.7\.0\.0" test || echo "No tests found around 8.7.0.0 boundary"
🧹 Nitpick comments (2)
src/utils/versioning/versions.ts (2)

11-12: Rename for terminology consistency: use UPDATE_TAGS_ENDPOINT

The rest of the PR and URL builder use “update tags”. Rename the feature key to avoid mixed terminology.

-  SET_TAGS_ENDPOINT: '8.7.0.0',
+  UPDATE_TAGS_ENDPOINT: '8.7.0.0',

Note: Update the corresponding guard function name and all call sites.


66-69: Align guard name with endpoint naming

Rename the guard to reflect “update tags” and the renamed feature key.

-export function appSupportsSetTagsEndpoint(currentNugetVersion: string | undefined) {
-  return isFeatureSupported({ feature: 'SET_TAGS_ENDPOINT', currentNugetVersion });
-}
+export function appSupportsUpdateTagsEndpoint(currentNugetVersion: string | undefined) {
+  return isFeatureSupported({ feature: 'UPDATE_TAGS_ENDPOINT', currentNugetVersion });
+}

Follow up: rename imports/usages (e.g., AttachmentsStorePlugin.tsx) accordingly.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 653abf4 and 1f7aee5.

📒 Files selected for processing (1)
  • src/utils/versioning/versions.ts (2 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx}: Avoid using any and unnecessary type casts (as Type) in TypeScript; prefer precise typings and refactor existing casts/anys
For TanStack Query, use objects to manage query keys and functions, and centralize shared options via queryOptions

Files:

  • src/utils/versioning/versions.ts
🔇 Additional comments (1)
src/utils/versioning/versions.ts (1)

66-69: Add boundary tests for version compare

Add tests to lock behavior around 8.7.0.0 (just below, equal, and above).

Apply a new Jest test (example):

+// tests/utils/versioning/versions.update-tags.test.ts
+import { appSupportsUpdateTagsEndpoint } from 'src/utils/versioning/versions';
+
+describe('appSupportsUpdateTagsEndpoint', () => {
+  it('is false before 8.7.0.0', () => {
+    expect(appSupportsUpdateTagsEndpoint('8.6.999.999')).toBe(false);
+  });
+  it('is true at 8.7.0.0', () => {
+    expect(appSupportsUpdateTagsEndpoint('8.7.0.0')).toBe(true);
+  });
+  it('is true after 8.7.0.0', () => {
+    expect(appSupportsUpdateTagsEndpoint('8.7.0.1')).toBe(true);
+  });
+  it('handles three-part inputs if emitted by runtime', () => {
+    expect(appSupportsUpdateTagsEndpoint('8.7.0')).toBe(true);
+  });
+});

If three-part inputs aren’t supported by isAtLeastVersion, either normalize inputs or adjust the expectation and document it.

@cammiida cammiida force-pushed the feature/validate-tags branch from 1f7aee5 to 6fa68f9 Compare September 10, 2025 12:21
@cammiida cammiida changed the base branch from main to chore/update-data-model-validations September 10, 2025 12:33
@cammiida cammiida force-pushed the feature/validate-tags branch from 6fa68f9 to 9e700ac Compare September 10, 2025 12:36
Copy link

Quality Gate Failed Quality Gate failed

Failed conditions
1 Security Hotspot
D Reliability Rating on New Code (required ≥ A)

See analysis details on SonarQube Cloud

Catch issues before they fail your Quality Gate with our IDE extension SonarQube for IDE

Copy link
Contributor

@olemartinorg olemartinorg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me! 🙌

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backport-ignore This PR is a new feature and should not be cherry-picked onto release branches kind/product-feature Pull requests containing new features
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants