Skip to content

Conversation

@bjosttveit
Copy link
Member

@bjosttveit bjosttveit commented Nov 7, 2025

Description

Remaining potential issues identified (there may be more I haven't considered), added TODOs:

// TODO(Error handling): Should failing to fetch app languages cause PDF generation to fail?

// TODO(Error handling): If fetching options fails, we just log and PDF generation will still succeed?

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 FatalError/FatalErrorEmpty error containers, LoadingEmpty and LoadingWrapper, a local Spinner wrapper, and a configurable content loader with default/form/receipt variants.
  • Refactor

    • Consolidated loading components and switched loading detection from CSS classes to data attributes; removed legacy print-blocking behavior. Error UIs now render with fatal-error markers and many imports updated to use local loading primitives.
  • Tests

    • Added unit tests for loader variants and an E2E test for subform PDF failure handling; one legacy unit test removed.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 7, 2025

📝 Walkthrough

Walkthrough

Adds local loading and error components (Spinner, LoadingEmpty, LoadingWrapper, AltinnContentLoader, FatalError, FatalErrorEmpty), migrates many Spinner imports to the local Spinner, replaces the old molecules AltinnContentLoader usage with the new variant-based loader, and refactors DOM detection from class-based to attribute-based for print gating.

Changes

Cohort / File(s) Summary
New loading components
src/app-components/loading/Spinner/Spinner.tsx, src/app-components/loading/LoadingEmpty/LoadingEmpty.tsx, src/app-components/loading/LoadingWrapper/LoadingWrapper.tsx
Add a local Spinner wrapper that forwards props to the design-system spinner and adds data-loading, a hidden LoadingEmpty sentinel with data-loading, and a LoadingWrapper that forwards div props and children.
New AltinnContentLoader + tests & icons
src/app-components/loading/AltinnContentLoader/AltinnContentLoader.tsx, src/app-components/loading/AltinnContentLoader/AltinnContentLoader.test.tsx, src/app-components/loading/AltinnContentLoader/AltinnContentIconFormData.tsx, src/app-components/loading/AltinnContentLoader/AltinnContentIconReceipt.tsx
Introduce AltinnContentLoader component with variant support (default/form/receipt), icon components for variants, and unit tests covering variant rendering.
New error components
src/app-components/error/FatalError/FatalError.tsx, src/app-components/error/FatalErrorEmpty/FatalErrorEmpty.tsx
Add FatalError (forwards div props and renders data-fatal-error) and FatalErrorEmpty (hidden sentinel with data-fatal-error).
Spinner import migrations
src/app-components/Button/Button.tsx, src/app-components/Table/Table.tsx, src/components/AltinnSpinner.tsx, src/components/PDFGeneratorPreview/PDFGeneratorPreview.tsx, src/components/presentation/BackNavigationButton.tsx, src/layout/ImageUpload/ImageCanvas/ImagePreview.tsx, src/layout/NavigationBar/NavigationBarComponent.tsx, src/layout/SigningActions/PanelAwaitingCurrentUserSignature.tsx, src/layout/SigningActions/SigningActionsComponent.tsx, src/layout/Subform/SubformComponent.tsx, src/layout/Subform/Summary/SubformSummaryTable.tsx, src/features/devtools/components/VersionSwitcher/VersionSwitcher.tsx, src/features/navigation/components/Page.tsx, src/features/navigation/components/PageGroup.tsx
Replace imports of Spinner from @digdir/designsystemet-react with the local src/app-components/loading/Spinner/Spinner; usages unchanged.
Remove legacy molecules AltinnContentLoader
src/components/molecules/AltinnContentLoader.tsx, src/components/molecules/AltinnContentLoader.test.tsx
Delete the old molecules AltinnContentLoader component and its test.
AltinnContentLoader consumption updates
src/core/loading/Loader.tsx, src/features/process/confirm/containers/Confirm.tsx, src/features/receipt/ReceiptContainer.tsx
Update imports to new AltinnContentLoader and switch usages to the variant prop (e.g., 'form', 'receipt') instead of passing icon children.
DOM detection & print gating refactor
src/components/ReadyForPrint.tsx, src/core/ui/RenderStart.tsx, src/core/loading/LoadingContext.tsx
Replace class-based detection with attribute-based detection (useHasElementsByAttribute, loadingAttribute), remove BlockPrint rendering, and include fatal-error checks in render gating.
Error UI wrapping
src/components/altinnError.tsx, src/layout/GenericComponent.tsx, src/layout/SigneeList/SigneeListError.tsx, src/layout/SigneeList/SigneeListSummary.tsx, src/layout/SigningDocumentList/SigningDocumentListError.tsx, src/layout/Subform/SubformComponent.tsx, src/layout/Subform/Summary/SubformSummaryComponent.tsx, src/layout/Subform/Summary/SubformSummaryTable.tsx, src/layout/SigningActions/SigningActionsComponent.tsx
Wrap existing error render branches with FatalError (or return FatalErrorEmpty in non-dev ComponentErrorList), replacing previous plain divs.
Loading UI replacements & misc
src/features/pdf/PdfFromLayout.tsx, src/layout/Option/OptionComponent.tsx, src/layout/Subform/Summary/SubformSummaryComponent2.tsx
Replace BlockPrint with LoadingEmpty for loading states, render LoadingEmpty during option fetching, and adjust subform summary loading/error handling.
Tests & e2e
test/e2e/integration/subform-test/pdf.ts
Add E2E test that simulates a failing subform fetch, verifies #readyForPrint is hidden until recovery, and asserts unknown-error UI.
Minor comments and TODOs
src/features/options/useGetOptions.ts, src/features/language/LanguageProvider.tsx
Add TODO comments regarding error handling for option/language fetch failures.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~30 minutes

Areas to focus review on:

  • src/components/ReadyForPrint.tsx — verify MutationObserver attributeFilter and that attribute-based detection preserves prior semantics.
  • src/app-components/loading/AltinnContentLoader/AltinnContentLoader.tsx and ...test.tsx — confirm variant mapping, default fallback, and test coverage.
  • Spinner import migrations — ensure all updated import paths resolve and added data-loading does not break existing DOM queries or CSS.
  • FatalError/FatalErrorEmpty usage — confirm error content accessibility and that hiding sentinel variants behaves as intended.
  • test/e2e/integration/subform-test/pdf.ts — validate request interception patterns and timing for CI reliability.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 28.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main focus of this PR, which refactors loading and error handling in ReadyForPrint and related components.
Description check ✅ Passed The PR description follows the template structure and includes manual testing verification, Cypress E2E tests, and accessibility/documentation notes, though it lacks a specific issue number.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/pdf-loading-and-error-handling

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between af8e535 and 3664b1d.

📒 Files selected for processing (3)
  • src/features/language/LanguageProvider.tsx (1 hunks)
  • src/features/options/useGetOptions.ts (1 hunks)
  • test/e2e/integration/subform-test/pdf.ts (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • test/e2e/integration/subform-test/pdf.ts
  • src/features/options/useGetOptions.ts
  • src/features/language/LanguageProvider.tsx
⏰ 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). (3)
  • GitHub Check: Install
  • GitHub Check: Analyze (javascript)
  • GitHub Check: Type-checks, eslint, unit tests and SonarCloud

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.

@bjosttveit bjosttveit added kind/bug Something isn't working backport This PR should be cherry-picked onto older release branches labels Nov 7, 2025
@bjosttveit bjosttveit marked this pull request as ready for review November 7, 2025 10:51
@bjosttveit bjosttveit changed the title improve loading and error handling in readyforprint Improve loading and error handling in ReadyForPrint Nov 7, 2025
Copy link
Contributor

@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

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7942dc0 and 34f5206.

📒 Files selected for processing (41)
  • src/app-components/Button/Button.tsx (1 hunks)
  • src/app-components/Table/Table.tsx (1 hunks)
  • src/app-components/error/FatalError/FatalError.tsx (1 hunks)
  • src/app-components/error/FatalErrorEmpty/FatalErrorEmpty.tsx (1 hunks)
  • src/app-components/loading/AltinnContentLoader/AltinnContentIconFormData.tsx (1 hunks)
  • src/app-components/loading/AltinnContentLoader/AltinnContentIconReceipt.tsx (1 hunks)
  • src/app-components/loading/AltinnContentLoader/AltinnContentLoader.test.tsx (1 hunks)
  • src/app-components/loading/AltinnContentLoader/AltinnContentLoader.tsx (1 hunks)
  • src/app-components/loading/LoadingEmpty/LoadingEmpty.tsx (1 hunks)
  • src/app-components/loading/Spinner/Spinner.tsx (1 hunks)
  • src/components/AltinnSpinner.tsx (1 hunks)
  • src/components/PDFGeneratorPreview/PDFGeneratorPreview.tsx (1 hunks)
  • src/components/ReadyForPrint.tsx (5 hunks)
  • src/components/altinnError.tsx (3 hunks)
  • src/components/molecules/AltinnContentLoader.test.tsx (0 hunks)
  • src/components/molecules/AltinnContentLoader.tsx (0 hunks)
  • src/components/presentation/BackNavigationButton.tsx (1 hunks)
  • src/core/loading/Loader.tsx (2 hunks)
  • src/core/loading/LoadingContext.tsx (1 hunks)
  • src/core/ui/RenderStart.tsx (2 hunks)
  • src/features/devtools/components/VersionSwitcher/VersionSwitcher.tsx (1 hunks)
  • src/features/navigation/components/Page.tsx (1 hunks)
  • src/features/navigation/components/PageGroup.tsx (1 hunks)
  • src/features/options/useGetOptions.ts (1 hunks)
  • src/features/pdf/PdfFromLayout.tsx (2 hunks)
  • src/features/process/confirm/containers/Confirm.tsx (2 hunks)
  • src/features/receipt/ReceiptContainer.tsx (2 hunks)
  • src/layout/GenericComponent.tsx (2 hunks)
  • src/layout/ImageUpload/ImageCanvas/ImagePreview.tsx (1 hunks)
  • src/layout/NavigationBar/NavigationBarComponent.tsx (1 hunks)
  • src/layout/Option/OptionComponent.tsx (2 hunks)
  • src/layout/SigneeList/SigneeListError.tsx (4 hunks)
  • src/layout/SigneeList/SigneeListSummary.tsx (2 hunks)
  • src/layout/SigningActions/PanelAwaitingCurrentUserSignature.tsx (1 hunks)
  • src/layout/SigningActions/SigningActionsComponent.tsx (2 hunks)
  • src/layout/SigningDocumentList/SigningDocumentListError.tsx (4 hunks)
  • src/layout/Subform/SubformComponent.tsx (2 hunks)
  • src/layout/Subform/Summary/SubformSummaryComponent.tsx (2 hunks)
  • src/layout/Subform/Summary/SubformSummaryComponent2.tsx (2 hunks)
  • src/layout/Subform/Summary/SubformSummaryTable.tsx (2 hunks)
  • test/e2e/integration/subform-test/pdf.ts (2 hunks)
💤 Files with no reviewable changes (2)
  • src/components/molecules/AltinnContentLoader.tsx
  • src/components/molecules/AltinnContentLoader.test.tsx
🧰 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/app-components/loading/LoadingEmpty/LoadingEmpty.tsx
  • src/app-components/error/FatalErrorEmpty/FatalErrorEmpty.tsx
  • src/layout/GenericComponent.tsx
  • src/app-components/loading/AltinnContentLoader/AltinnContentLoader.test.tsx
  • src/app-components/error/FatalError/FatalError.tsx
  • src/layout/SigningActions/SigningActionsComponent.tsx
  • src/features/devtools/components/VersionSwitcher/VersionSwitcher.tsx
  • src/app-components/Table/Table.tsx
  • src/app-components/loading/AltinnContentLoader/AltinnContentLoader.tsx
  • src/features/pdf/PdfFromLayout.tsx
  • src/layout/SigneeList/SigneeListError.tsx
  • src/app-components/loading/AltinnContentLoader/AltinnContentIconFormData.tsx
  • src/components/PDFGeneratorPreview/PDFGeneratorPreview.tsx
  • src/app-components/Button/Button.tsx
  • src/layout/Subform/Summary/SubformSummaryComponent2.tsx
  • src/layout/Subform/SubformComponent.tsx
  • src/layout/Option/OptionComponent.tsx
  • src/app-components/loading/AltinnContentLoader/AltinnContentIconReceipt.tsx
  • src/features/process/confirm/containers/Confirm.tsx
  • src/components/AltinnSpinner.tsx
  • src/components/presentation/BackNavigationButton.tsx
  • src/features/receipt/ReceiptContainer.tsx
  • src/layout/SigningDocumentList/SigningDocumentListError.tsx
  • src/layout/SigningActions/PanelAwaitingCurrentUserSignature.tsx
  • src/layout/NavigationBar/NavigationBarComponent.tsx
  • src/layout/Subform/Summary/SubformSummaryComponent.tsx
  • src/features/navigation/components/Page.tsx
  • src/layout/SigneeList/SigneeListSummary.tsx
  • src/components/altinnError.tsx
  • src/features/navigation/components/PageGroup.tsx
  • src/layout/Subform/Summary/SubformSummaryTable.tsx
  • src/core/loading/LoadingContext.tsx
  • src/app-components/loading/Spinner/Spinner.tsx
  • src/core/ui/RenderStart.tsx
  • src/features/options/useGetOptions.ts
  • test/e2e/integration/subform-test/pdf.ts
  • src/core/loading/Loader.tsx
  • src/layout/ImageUpload/ImageCanvas/ImagePreview.tsx
  • src/components/ReadyForPrint.tsx
**/*.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/app-components/loading/AltinnContentLoader/AltinnContentLoader.test.tsx
🧠 Learnings (8)
📚 Learning: 2025-08-22T13:53:28.252Z
Learnt from: CR
Repo: Altinn/app-frontend-react PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-08-22T13:53:28.252Z
Learning: Applies to src/layout/*/{config.ts,Component.tsx,index.tsx,config.generated.ts} : Layout components must follow the standardized structure: `config.ts`, `Component.tsx`, `index.tsx`, and include generated types in `config.generated.ts`

Applied to files:

  • src/layout/GenericComponent.tsx
📚 Learning: 2025-08-22T13:53:28.252Z
Learnt from: CR
Repo: Altinn/app-frontend-react PR: 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/app-components/loading/AltinnContentLoader/AltinnContentLoader.test.tsx
  • src/layout/Subform/Summary/SubformSummaryComponent2.tsx
  • test/e2e/integration/subform-test/pdf.ts
📚 Learning: 2025-08-28T12:25:27.289Z
Learnt from: olemartinorg
Repo: Altinn/app-frontend-react PR: 3645
File: src/components/wrappers/ProcessWrapper.tsx:107-110
Timestamp: 2025-08-28T12:25:27.289Z
Learning: In the app-frontend-react codebase, the architecture favors navigation happening closer to user interactions or specific process state changes, rather than using universal effects that automatically redirect users. This is part of a design philosophy to avoid "free-standing effects that throw you around" and make navigation more predictable and contextual.

Applied to files:

  • src/layout/SigningActions/SigningActionsComponent.tsx
  • src/layout/Subform/SubformComponent.tsx
  • src/components/presentation/BackNavigationButton.tsx
  • src/layout/SigningActions/PanelAwaitingCurrentUserSignature.tsx
  • src/layout/Subform/Summary/SubformSummaryTable.tsx
  • src/core/ui/RenderStart.tsx
📚 Learning: 2025-08-28T12:00:32.967Z
Learnt from: olemartinorg
Repo: Altinn/app-frontend-react PR: 3645
File: src/features/datamodel/DataModelsProvider.tsx:172-175
Timestamp: 2025-08-28T12:00:32.967Z
Learning: In DataModelsProvider.tsx, the effect that processes referenced data types must run for both stateless and non-stateless apps. The `isFetching` guard is appropriate because stateless apps don't fetch instance data (useInstanceDataQuery is disabled with `enabled: !isStateless`) but still need the data type processing to occur.

Applied to files:

  • src/layout/Option/OptionComponent.tsx
  • src/features/navigation/components/PageGroup.tsx
  • src/components/ReadyForPrint.tsx
📚 Learning: 2025-09-03T14:23:33.606Z
Learnt from: olemartinorg
Repo: Altinn/app-frontend-react PR: 3645
File: src/features/receipt/FixWrongReceiptType.tsx:16-34
Timestamp: 2025-09-03T14:23:33.606Z
Learning: In FixWrongReceiptType.tsx, brief ping-ponging between receipt routes during instance data loading is acceptable because the instance data is typically already fetched when this component runs. The author considers this a non-issue.

Applied to files:

  • src/layout/Option/OptionComponent.tsx
  • src/app-components/loading/AltinnContentLoader/AltinnContentIconReceipt.tsx
  • src/features/process/confirm/containers/Confirm.tsx
  • src/features/receipt/ReceiptContainer.tsx
📚 Learning: 2025-08-28T12:00:32.967Z
Learnt from: olemartinorg
Repo: Altinn/app-frontend-react PR: 3645
File: src/features/datamodel/DataModelsProvider.tsx:172-175
Timestamp: 2025-08-28T12:00:32.967Z
Learning: In the Altinn app-frontend-react codebase, "stateless" refers to "instanceless" applications. While stateless/instanceless apps don't have server-side instance data, they still require data models to be loaded and processed for local state management.

Applied to files:

  • src/features/process/confirm/containers/Confirm.tsx
📚 Learning: 2025-08-28T12:25:27.289Z
Learnt from: olemartinorg
Repo: Altinn/app-frontend-react PR: 3645
File: src/components/wrappers/ProcessWrapper.tsx:107-110
Timestamp: 2025-08-28T12:25:27.289Z
Learning: In ProcessWrapper.tsx, when taskType === ProcessTaskType.Archived and taskId !== TaskKeys.CustomReceipt, the component shows a loader with reason 'redirect-to-receipt' but does not perform explicit navigation. This is intentional - other parts of the system handle the actual navigation closer to where user interactions occur.

Applied to files:

  • src/features/receipt/ReceiptContainer.tsx
📚 Learning: 2025-08-22T13:53:28.252Z
Learnt from: CR
Repo: Altinn/app-frontend-react PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-08-22T13:53:28.252Z
Learning: Applies to src/features/*/Provider.tsx : Place feature-specific context providers as `Provider.tsx` within each feature directory under `src/features/`

Applied to files:

  • src/core/loading/LoadingContext.tsx
🧬 Code graph analysis (16)
src/layout/GenericComponent.tsx (1)
src/app-components/error/FatalErrorEmpty/FatalErrorEmpty.tsx (1)
  • FatalErrorEmpty (6-13)
src/app-components/loading/AltinnContentLoader/AltinnContentLoader.test.tsx (1)
src/app-components/loading/AltinnContentLoader/AltinnContentLoader.tsx (2)
  • IAltinnContentLoaderProps (10-17)
  • AltinnContentLoader (38-58)
src/layout/SigningActions/SigningActionsComponent.tsx (2)
src/app-components/error/FatalError/FatalError.tsx (1)
  • FatalError (7-16)
src/layout/SigningActions/PanelSigning.tsx (1)
  • SigningPanel (24-61)
src/app-components/loading/AltinnContentLoader/AltinnContentLoader.tsx (3)
src/app-components/loading/AltinnContentLoader/AltinnContentIconFormData.tsx (1)
  • AltinnContentIconFormData (3-160)
src/app-components/loading/AltinnContentLoader/AltinnContentIconReceipt.tsx (1)
  • AltinnContentIconReceipt (3-94)
src/app-components/loading/AltinnContentLoader/AltinnContentIcon.tsx (1)
  • AltinnContentIcon (3-83)
src/features/pdf/PdfFromLayout.tsx (1)
src/app-components/loading/LoadingEmpty/LoadingEmpty.tsx (1)
  • LoadingEmpty (6-13)
src/layout/SigneeList/SigneeListError.tsx (2)
src/app-components/error/FatalError/FatalError.tsx (1)
  • FatalError (7-16)
src/features/language/Lang.tsx (1)
  • Lang (15-23)
src/layout/Subform/Summary/SubformSummaryComponent2.tsx (2)
src/core/loading/Loader.tsx (1)
  • Loader (13-35)
src/core/errorHandling/DisplayError.tsx (1)
  • DisplayError (18-32)
src/layout/Subform/SubformComponent.tsx (2)
src/app-components/error/FatalError/FatalError.tsx (1)
  • FatalError (7-16)
src/features/language/Lang.tsx (1)
  • Lang (15-23)
src/layout/Option/OptionComponent.tsx (1)
src/app-components/loading/LoadingEmpty/LoadingEmpty.tsx (1)
  • LoadingEmpty (6-13)
src/layout/SigningDocumentList/SigningDocumentListError.tsx (2)
src/app-components/error/FatalError/FatalError.tsx (1)
  • FatalError (7-16)
src/features/language/Lang.tsx (1)
  • Lang (15-23)
src/layout/Subform/Summary/SubformSummaryComponent.tsx (2)
src/app-components/error/FatalError/FatalError.tsx (1)
  • FatalError (7-16)
src/features/language/Lang.tsx (1)
  • Lang (15-23)
src/layout/SigneeList/SigneeListSummary.tsx (1)
src/app-components/error/FatalError/FatalError.tsx (1)
  • FatalError (7-16)
src/components/altinnError.tsx (1)
src/app-components/error/FatalError/FatalError.tsx (1)
  • FatalError (7-16)
src/layout/Subform/Summary/SubformSummaryTable.tsx (2)
src/app-components/error/FatalError/FatalError.tsx (1)
  • FatalError (7-16)
src/features/language/Lang.tsx (1)
  • Lang (15-23)
src/core/ui/RenderStart.tsx (1)
src/components/ReadyForPrint.tsx (2)
  • useHasElementsByAttribute (79-104)
  • loadingAttribute (7-7)
test/e2e/integration/subform-test/pdf.ts (1)
src/types/shared.ts (1)
  • IInstance (70-89)
⏰ 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). (1)
  • GitHub Check: Install
🔇 Additional comments (50)
src/features/options/useGetOptions.ts (1)

258-258: Clarify the TODO comment's intent and action item.

The TODO is phrased as a question ("we just log and PDF generation will still succeed?") rather than specifying the desired behavior or action. Given the PR objective to improve error handling, clarify whether:

  • PDF generation should fail if options fail to fetch?
  • Additional error UI should be shown (as suggested by broader PR changes)?
  • Current logging behavior is intentional but needs documentation?

Regarding the AI summary claiming "two identical TODO comments"—only one TODO appears in the provided code at line 258. Verify whether a second TODO was intended or if this is an inconsistency in the summary.

src/app-components/loading/AltinnContentLoader/AltinnContentIconFormData.tsx (1)

7-7: LGTM! Test identifier added.

The data-testid attribute enables precise targeting of this icon variant in tests without affecting runtime behavior.

src/core/ui/RenderStart.tsx (1)

5-5: LGTM! Clean migration to attribute-based loading detection.

The shift from class-based to attribute-based detection is consistent with the broader refactoring in ReadyForPrint.tsx, improving the reliability of loading state detection.

Also applies to: 35-35

src/components/ReadyForPrint.tsx (3)

7-8: LGTM! Attribute-based detection improves reliability.

The shift from loadingClassName to loadingAttribute and the addition of errorAttribute provides more robust detection of loading and error states via data attributes rather than CSS classes.


28-29: Excellent addition of error state detection.

The dual detection of both hasLoaders and hasErrors ensures that the PDF indicator correctly hides when fatal errors occur, preventing premature PDF generation.

Also applies to: 44-44


79-104: Well-refactored hook with proper MutationObserver configuration.

The useHasElementsByAttribute hook correctly:

  • Initializes state with a document query
  • Configures MutationObserver to watch for attribute changes on the specified attribute
  • Updates dependencies appropriately
src/components/presentation/BackNavigationButton.tsx (1)

8-8: LGTM! Spinner migration to local component.

Part of the project-wide migration from design system Spinner to a local implementation. No behavioral changes.

src/features/devtools/components/VersionSwitcher/VersionSwitcher.tsx (1)

3-3: LGTM! Spinner import migration.

Consistent with the project-wide migration to local Spinner component. No behavioral changes.

Also applies to: 8-8

src/layout/SigneeList/SigneeListSummary.tsx (1)

9-9: Excellent integration with attribute-based error detection.

Wrapping the error state in FatalError adds the data-fatal-error attribute, enabling ReadyForPrint to detect the error condition and prevent premature PDF generation. This aligns with the broader error handling pattern introduced in this PR.

Also applies to: 49-59

src/layout/SigningActions/PanelAwaitingCurrentUserSignature.tsx (1)

4-4: LGTM! Spinner import migration.

Consistent with the project-wide Spinner migration. No behavioral changes.

Also applies to: 7-7

src/layout/NavigationBar/NavigationBarComponent.tsx (1)

7-7: LGTM!

The Spinner import has been successfully migrated to the local implementation, aligning with the PR's goal to centralize loading components.

src/features/navigation/components/Page.tsx (1)

6-6: LGTM!

The Spinner import has been successfully migrated to the local implementation.

src/components/AltinnSpinner.tsx (1)

7-7: LGTM!

The Spinner import has been successfully migrated to the local implementation.

src/app-components/loading/AltinnContentLoader/AltinnContentIconReceipt.tsx (1)

7-7: LGTM!

Adding the data-testid attribute enables targeted testing for the receipt icon variant, improving test coverage and maintainability.

src/app-components/Table/Table.tsx (1)

10-10: LGTM!

The Spinner import has been successfully migrated to the local implementation.

src/layout/Option/OptionComponent.tsx (1)

6-6: Improved loading state detection.

Replacing the null return with <LoadingEmpty /> provides a DOM-based signal (data-loading attribute) that enables external processes to detect loading states, which aligns with the PR's objective to improve loading handling for the readyforprint feature.

Also applies to: 62-64

src/layout/Subform/Summary/SubformSummaryComponent2.tsx (2)

8-9: LGTM!

Added necessary imports for improved error and loading state handling in subform summaries.


96-102: Excellent error and loading state handling.

The explicit handling of loading and error states prevents rendering incomplete or invalid data when subform data is being fetched or has encountered an error. This significantly improves the user experience and data integrity.

src/layout/GenericComponent.tsx (1)

7-7: Improved error state detection in production.

Replacing the null return with <FatalErrorEmpty /> provides a DOM-based signal (data-fatal-error attribute) that enables external processes to detect unrecoverable errors in production, preventing PDF generation when components have fatal configuration errors. This aligns with the PR's objective to improve error handling for the readyforprint feature.

Also applies to: 194-194

src/features/navigation/components/PageGroup.tsx (1)

6-6: LGTM – Clean import path update.

The Spinner import has been successfully migrated to the local component path, consistent with the broader refactoring effort to centralize loading components.

src/components/PDFGeneratorPreview/PDFGeneratorPreview.tsx (1)

3-7: LGTM – Clean import migration.

The Spinner import has been cleanly migrated from the design system package to the local component implementation, maintaining all existing functionality.

src/layout/ImageUpload/ImageCanvas/ImagePreview.tsx (1)

3-3: LGTM – Import path updated correctly.

The Spinner component import has been successfully updated to use the local implementation.

src/layout/Subform/Summary/SubformSummaryComponent.tsx (2)

4-5: LGTM – Imports updated for centralized error/loading components.

The imports have been correctly updated to use the local FatalError and Spinner implementations.


61-65: LGTM – Error handling improved with FatalError wrapper.

Wrapping the error message in FatalError adds the data-fatal-error attribute, which signals to the PDF generation system that an unrecoverable error has occurred and prevents incomplete PDF generation.

src/components/altinnError.tsx (2)

5-5: LGTM – FatalError import added.


33-79: LGTM – Root element correctly wrapped with FatalError.

The AltinnError component has been properly updated to use FatalError as the root wrapper, which adds the data-fatal-error attribute for PDF generation prevention. All props are correctly preserved through spreading.

src/app-components/error/FatalErrorEmpty/FatalErrorEmpty.tsx (1)

1-13: LGTM – Well-designed utility component for error signaling.

This component provides a clean, focused solution for signaling unrecoverable errors to the PDF generation system without rendering visible content. The inline style is appropriate for this specific use case, and the documentation clearly explains the purpose of the data-fatal-error attribute.

src/app-components/loading/LoadingEmpty/LoadingEmpty.tsx (1)

1-13: LGTM – Well-designed utility component for loading state signaling.

This component provides a clean solution for signaling pending/loading states to the PDF generation system without rendering visible UI. The design mirrors FatalErrorEmpty and the documentation clearly explains the purpose of the data-loading attribute.

src/layout/Subform/SubformComponent.tsx (2)

9-11: LGTM – Imports updated correctly.

The imports have been properly updated to use the local FatalError and Spinner implementations, consistent with the broader refactoring effort.


242-244: LGTM – Error handling improved with FatalError wrapper.

The error message is now properly wrapped in FatalError, adding the data-fatal-error attribute to signal unrecoverable errors and prevent incomplete PDF generation. This change is consistent with the error handling pattern applied throughout the codebase.

src/app-components/Button/Button.tsx (1)

7-7: LGTM: Spinner import centralized.

The import path change centralizes the Spinner component to a local implementation while preserving existing functionality.

src/features/pdf/PdfFromLayout.tsx (1)

8-8: LGTM: LoadingEmpty signals loading state.

The change from BlockPrint to LoadingEmpty aligns with the PR's goal of using attribute-based detection (data-loading) for loading states.

Also applies to: 65-65

src/core/loading/LoadingContext.tsx (1)

16-18: LGTM: Cleaner Provider implementation.

Removing the UI rendering side-effect from the context provider improves separation of concerns.

src/layout/SigningActions/SigningActionsComponent.tsx (2)

4-5: LGTM: Imports updated to centralized components.

The import changes align with the PR's refactoring to centralize loading and error components.


61-69: LGTM: FatalError wrapper appropriately signals unrecoverable error.

The FatalError wrapper correctly signals that PDF generation should not proceed when the signee list API fails.

src/app-components/error/FatalError/FatalError.tsx (1)

1-16: LGTM: Well-designed error wrapper component.

The FatalError component provides a clean abstraction for signaling unrecoverable errors. The JSDoc clearly explains its purpose in preventing PDF generation.

src/layout/SigningDocumentList/SigningDocumentListError.tsx (1)

21-32: LGTM: Consistent FatalError wrapping for all error branches.

All error states are appropriately wrapped with FatalError to signal that PDF generation should not proceed.

Also applies to: 42-46, 50-54

src/layout/SigneeList/SigneeListError.tsx (1)

26-37: LGTM: Consistent FatalError wrapping for all error branches.

All error states are appropriately wrapped with FatalError, maintaining consistency with other error components in the codebase.

Also applies to: 46-50, 54-58

src/layout/Subform/Summary/SubformSummaryTable.tsx (2)

4-9: LGTM! Import consolidation aligns with readyforprint improvements.

The migration to local wrapper components (Spinner, FatalError) is consistent with the PR's goal of adding data attributes for PDF generation detection.


69-71: LGTM! Error handling wrapper properly applied.

The FatalError component correctly wraps the error message, adding the data-fatal-error attribute for PDF generation detection.

src/app-components/loading/Spinner/Spinner.tsx (1)

1-15: LGTM! Clean wrapper with proper type inference.

The component correctly wraps the design system spinner, adds the data-loading attribute for PDF generation detection, and uses type inference to avoid duplication.

src/features/receipt/ReceiptContainer.tsx (2)

6-6: LGTM! Import path updated to centralized location.


164-169: LGTM! Migration to prop-based variant API.

The change from child component pattern to variant='receipt' prop aligns with the new AltinnContentLoader API, simplifying the usage while maintaining the same visual behavior.

src/features/process/confirm/containers/Confirm.tsx (2)

3-3: LGTM! Import path updated to centralized location.


23-28: LGTM! Consistent migration to prop-based variant API.

The change to variant='receipt' matches the pattern used throughout the PR, maintaining consistency across the codebase.

src/core/loading/Loader.tsx (2)

3-3: LGTM! Import path updated to centralized location.


38-44: LGTM! Migration to prop-based variant API.

The use of variant='form' correctly replaces the previous child component pattern, maintaining the form-specific loading icon while simplifying the API.

src/app-components/loading/AltinnContentLoader/AltinnContentLoader.tsx (3)

8-17: LGTM! Well-defined type interfaces.

The type definitions are clear and properly scoped. The LoaderVariant type and IAltinnContentLoaderProps interface provide good type safety without using any.


23-33: LGTM! Robust variant handling with proper defaults.

The switch statement correctly maps each variant to its corresponding icon component and includes a sensible default case.


38-58: LGTM! Clean component implementation with debugging support.

The component properly:

  • Adds data-loading for PDF generation detection
  • Provides debugging attributes (data-reason, data-details)
  • Sets sensible defaults for width and height
  • Forwards all props correctly

Copy link
Contributor

@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

🧹 Nitpick comments (2)
test/e2e/integration/subform-test/pdf.ts (2)

119-119: Throw an Error object instead of a string.

Best practice is to throw an Error object rather than a string literal for better stack traces and consistency.

Apply this diff:

-        throw 'Could not find data element to block';
+        throw new Error('Could not find data element to block');

128-128: Remove commented-out code.

The commented-out req.destroy() line should be removed for cleaner test code.

Apply this diff:

       if (req.url.includes(data.dataElementIdToBlock)) {
-        // req.destroy();
         req.reply({ statusCode: 404, body: 'Not Found' });
       }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 34f5206 and 633d136.

📒 Files selected for processing (2)
  • src/app-components/loading/AltinnContentLoader/AltinnContentLoader.test.tsx (1 hunks)
  • test/e2e/integration/subform-test/pdf.ts (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/app-components/loading/AltinnContentLoader/AltinnContentLoader.test.tsx
🧰 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:

  • test/e2e/integration/subform-test/pdf.ts
🧠 Learnings (3)
📚 Learning: 2025-09-03T14:23:33.606Z
Learnt from: olemartinorg
Repo: Altinn/app-frontend-react PR: 3645
File: src/features/receipt/FixWrongReceiptType.tsx:16-34
Timestamp: 2025-09-03T14:23:33.606Z
Learning: In FixWrongReceiptType.tsx, brief ping-ponging between receipt routes during instance data loading is acceptable because the instance data is typically already fetched when this component runs. The author considers this a non-issue.

Applied to files:

  • test/e2e/integration/subform-test/pdf.ts
📚 Learning: 2025-09-05T12:57:07.200Z
Learnt from: olemartinorg
Repo: Altinn/app-frontend-react PR: 3673
File: src/utils/layout/plugins/claimRepeatingChildren.ts:8-27
Timestamp: 2025-09-05T12:57:07.200Z
Learning: In the app-frontend-react codebase, the maintainer prefers throwing errors for invalid multiPage ID formats in claimRepeatingChildren rather than logging and continuing processing. This indicates a preference for strict validation that halts on malformed input.

Applied to files:

  • test/e2e/integration/subform-test/pdf.ts
📚 Learning: 2025-08-22T13:53:28.252Z
Learnt from: CR
Repo: Altinn/app-frontend-react PR: 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:

  • test/e2e/integration/subform-test/pdf.ts
🧬 Code graph analysis (1)
test/e2e/integration/subform-test/pdf.ts (2)
src/types/shared.ts (1)
  • IInstance (70-89)
src/utils/instanceIdRegExp.ts (1)
  • getInstanceIdRegExp (3-18)
⏰ 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). (3)
  • GitHub Check: Analyze (javascript)
  • GitHub Check: Type-checks, eslint, unit tests and SonarCloud
  • GitHub Check: Install
🔇 Additional comments (5)
test/e2e/integration/subform-test/pdf.ts (5)

3-6: LGTM! Imports are appropriate for the new test.

The added imports (getInstanceIdRegExp and IInstance) are properly used in the new error handling test case.


105-110: Well-structured test setup.

The test name clearly communicates intent, and the waiting strategy appropriately ensures the page and data are ready before intercepting requests.


133-141: Solid URL manipulation and navigation logic.

The code correctly extracts the instance ID using the provided utility function and constructs the PDF URL appropriately. The reload strategy effectively triggers the error scenario.


143-149: Error state assertions are correct.

The test appropriately verifies both the presence of the error heading and the absence of the #readyForPrint element when a subform fails to load.


151-156: Excellent recovery validation.

The test effectively confirms recovery by reloading (after intercepts are exhausted) and validating that the PDF view renders correctly with #readyForPrint visible and no error message present. This provides comprehensive coverage of the error handling and recovery flow.

Copy link
Contributor

@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

🧹 Nitpick comments (2)
src/features/language/LanguageProvider.tsx (1)

51-51: Clarify whether this TODO should be resolved in this PR.

Since this PR specifically addresses error handling improvements in ReadyForPrint (labeled kind/bug), it's unclear whether this TODO represents:

  1. A known limitation being flagged for future work, or
  2. An open question that should be resolved in this PR

Currently, language fetch errors are only logged (line 54) and don't prevent PDF generation. If the app languages fail to load, the PDF will render using fallback language logic, which may not match user expectations.

Please clarify:

  • Should this decision be made and implemented in this PR?
  • If deferring, should a tracking issue be created?

If you'd like to implement error handling now, I can help propose a solution that either:

  • Blocks PDF generation on language fetch errors, or
  • Shows a warning/degraded state indicator in the PDF when languages couldn't be loaded
src/app-components/loading/LoadingWrapper/LoadingWrapper.tsx (1)

1-1: Remove unused React import.

With React 19's JSX transform, the React import is no longer necessary when you're not using React APIs directly. Consider removing it for cleaner code.

-import React from 'react';
 import type { HTMLAttributes, PropsWithChildren } from 'react';
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between dc85688 and af8e535.

📒 Files selected for processing (3)
  • src/app-components/loading/LoadingWrapper/LoadingWrapper.tsx (1 hunks)
  • src/features/language/LanguageProvider.tsx (1 hunks)
  • src/layout/SigneeList/SigneeListSummary.tsx (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/layout/SigneeList/SigneeListSummary.tsx
🧰 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/app-components/loading/LoadingWrapper/LoadingWrapper.tsx
  • src/features/language/LanguageProvider.tsx
⏰ 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). (3)
  • GitHub Check: Type-checks, eslint, unit tests and SonarCloud
  • GitHub Check: Install
  • GitHub Check: Analyze (javascript)
🔇 Additional comments (1)
src/app-components/loading/LoadingWrapper/LoadingWrapper.tsx (1)

7-15: Verify that data-loading can be overridden by props.

The data-loading attribute is placed before {...props}, which allows callers to override it by passing data-loading={false} or data-loading={undefined} in props. Given that this component's purpose is to signal a loading state for PDF print gating, allowing the attribute to be overridden seems unintentional and could lead to bugs.

If data-loading should always be present when using this wrapper, consider moving the spread before the attribute to prevent overrides.

Apply this diff if the attribute should not be overridable:

 export function LoadingWrapper({ children, ...props }: PropsWithChildren<HTMLAttributes<HTMLDivElement>>) {
   return (
     <div
-      data-loading
       {...props}
+      data-loading
     >
       {children}
     </div>
   );
 }

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.

LGTM! 💪

@sonarqubecloud
Copy link

sonarqubecloud bot commented Nov 7, 2025

@bjosttveit
Copy link
Member Author

bjosttveit commented Nov 7, 2025

I tested blocking application languages, and it seems monstly fine honestly, the PDF generator should always specify the language explicitly through a query param, and the logic currently will just use that even if the allowed languages have not loaded. So not really a problem right now.

However, if I block an options fetch it looks like it retries a bunch of times but eventually just shows the option value (not label). This does not block print from occuring though, but probably blocks while the query is fetching through the useIsFetching() in ReadyForPrint?

bilde

@bjosttveit
Copy link
Member Author

Most other important queries failing results in unknown error, and now, these queries will also cause failure for readyForPrint if they occur within a subform context.

The mehcanism previously was that when unknown error is rendered, the readyForPrint element is not rendered at all, but this broke down when we added subforms as an independent subtree next to (not above) readyForPrint, which could fail independently. Hence, why checking for errors anywhere in the DOM is now necessary

@bjosttveit bjosttveit merged commit 2517d53 into main Nov 7, 2025
16 checks passed
@bjosttveit bjosttveit deleted the fix/pdf-loading-and-error-handling branch November 7, 2025 12:28
github-actions bot pushed a commit that referenced this pull request Nov 7, 2025
* improve loading and error handling in readyforprint

* fix test description

* strict equality

* use fatal error in dev as well

* use loading attribute in signeelistsummary

* add todo

* clarify comments

* remove comment
@github-actions
Copy link
Contributor

github-actions bot commented Nov 7, 2025

Automatic backport successful!

A backport PR has been automatically created for the release/v4.23 release branch.

A new release branch release/v4.23 was created from release v4.23.1.

The cherry-pick was clean with no conflicts. Please review the backport PR when it appears.

bjosttveit added a commit that referenced this pull request Nov 7, 2025
* improve loading and error handling in readyforprint

* fix test description

* strict equality

* use fatal error in dev as well

* use loading attribute in signeelistsummary

* add todo

* clarify comments

* remove comment
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backport This PR should be cherry-picked onto older release branches kind/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants