Skip to content

Conversation

@walldenfilippa
Copy link
Contributor

@walldenfilippa walldenfilippa commented Oct 21, 2025

Description

Added metadata to the data element, along with functionality to store the metadata within it.
Additional functionality in app-lib (Altinn/app-lib-dotnet#1531) and localtest(Altinn/app-localtest#183). Storage is in process.

Design in figma, pre development:
image
Mobileview:
image

Current layout:
image
Mobilview:
image

Related Issue(s)

#792

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
    • Thumbnail image previews added to file uploads with responsive sizing and a new thumbnail column in the file list
    • Table and row layout updated to display thumbnails correctly in mobile and desktop views
    • Added localization strings for English, Norwegian Bokmål, and Norwegian Nynorsk
    • File metadata support introduced to enable thumbnail handling

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 21, 2025

📝 Walkthrough

Walkthrough

Adds thumbnail support to the file upload table: new translation keys for "Thumbnail", a CSS module and React AttachmentThumbnail component, FileTable/FileTableRow updated to render thumbnails conditionally, and a new metadata field on IData to store attachment metadata.

Changes

Cohort / File(s) Summary
Translation entries
src/language/texts/en.ts, src/language/texts/nb.ts, src/language/texts/nn.ts
Adds form_filler.file_uploader_list_header_thumbnail localization entries ("Thumbnail", "Miniatyrbilde", "Miniatyrbilete").
Attachment thumbnail styling
src/layout/FileUpload/FileUploadTable/AttachmentThumbnail.module.css
New CSS module with .thumbnailContainer, .thumbnail (100×70), and .thumbnailMobile (80×60) styles.
Attachment thumbnail component
src/layout/FileUpload/FileUploadTable/AttachmentThumbnail.tsx
New React component AttachmentThumbnail that finds thumbnail via attachment metadata, constructs a thumbnail URL (with relative conversion), guards missing data, and renders a responsive <img>.
File upload table updates
src/layout/FileUpload/FileUploadTable/FileTable.tsx
Adds detection of thumbnails (thumbnailLink), computes hasImages, adjusts column span/width logic, conditionally renders thumbnail header, and passes hasImages to rows.
File table row updates
src/layout/FileUpload/FileUploadTable/FileTableRow.tsx
Adds optional hasImages?: boolean prop, imports AttachmentThumbnail, moves readable size cell for non-mobile, and conditionally renders a thumbnail cell when hasImages is true.
Type definitions
src/types/shared.ts
Adds IMetadata interface and metadata?: IMetadata[] to IData to support attachment metadata (used for thumbnails).

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Points to review closely:

  • Column span and responsive layout changes in FileTable.tsx for table layout regressions.
  • Null/edge-case guards and URL construction / domain-relative conversion in AttachmentThumbnail.tsx.
  • Type addition (IMetadata and IData.metadata) compatibility with existing data flows and serialization.
  • Prop threading of hasImages through FileTableFileTableRow and corresponding rendering branches.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Title check ❓ Inconclusive The title 'Feat/thumbnail' is vague and uses a generic naming pattern that doesn't clearly communicate the main feature being added. Use a more descriptive title like 'Add thumbnail preview functionality to file uploader' that clearly explains what feature is being introduced.
✅ Passed checks (1 passed)
Check name Status Explanation
Description check ✅ Passed The PR description includes design assets, related issues, and QA verification details, though some required sections have incomplete checkboxes and testing/documentation tasks are deferred.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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.

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: 6

🧹 Nitpick comments (5)
src/types/shared.ts (2)

24-27: Make metadata fields required (call sites assume presence)

Downstream code checks meta.key === 'thumbnailLink'. Optional key/value weakens safety. Make both required (and optionally narrow key type).

-export interface IMetadata {
-  key?: string;
-  value?: string;
-}
+export type MetadataKey = 'thumbnailLink' | (string & {});
+export interface IMetadata {
+  key: MetadataKey;
+  value: string;
+}

59-59: Sanitize/validate thumbnail URL before use

If metadata will carry external URLs, ensure the renderer only accepts http(s) and same-origin (or approved) hosts to avoid mixed content/SSRF/image beacons. Add a small helper to validate before rendering.

Would you like me to add a safe isTrustedThumbnailUrl(url: string) and wire it in AttachmentThumbnail?

src/layout/FileUpload/FileUploadTable/AttachmentThumbnail.module.css (1)

8-13: Prevent layout shift and improve perceived performance

Add explicit width/height (or aspect-ratio) so cells reserve space before images load.

 .thumbnail {
-  max-width: 100px;
-  max-height: 70px;
+  inline-size: 100px;
+  block-size: 70px;
+  aspect-ratio: 100 / 70;
   object-fit: contain;
   border-radius: 2px;
 }
 
 .thumbnailMobile {
-  max-width: 80px;
-  max-height: 60px;
+  inline-size: 80px;
+  block-size: 60px;
+  aspect-ratio: 80 / 60;
   object-fit: contain;
   border-radius: 2px;
 }

Also applies to: 15-20

src/layout/FileUpload/FileUploadTable/FileTable.tsx (1)

90-93: Handle missing tagTitle gracefully

If tagTitle is undefined, <Lang id={undefined} /> may render poorly. Fallback or skip the column.

-            {hasTag && !mobileView && (
+            {hasTag && !mobileView && tagTitle && (
               <th>
                 <Lang id={tagTitle} />
               </th>
             )}
src/layout/FileUpload/FileUploadTable/AttachmentThumbnail.tsx (1)

49-51: Remove redundant null check.

The thumbnailUrl will always be a string since both getDataElementUrl and makeUrlRelativeIfSameDomain always return strings. This check is redundant and can be safely removed.

Apply this diff to remove the unnecessary check:

   const thumbnailUrl = makeUrlRelativeIfSameDomain(getDataElementUrl(instanceId, thumbnailDataElement.id, language));
 
-  if (!thumbnailUrl) {
-    return null;
-  }
-
   return (
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 00d8151 and 7672e60.

📒 Files selected for processing (8)
  • src/language/texts/en.ts (1 hunks)
  • src/language/texts/nb.ts (1 hunks)
  • src/language/texts/nn.ts (1 hunks)
  • src/layout/FileUpload/FileUploadTable/AttachmentThumbnail.module.css (1 hunks)
  • src/layout/FileUpload/FileUploadTable/AttachmentThumbnail.tsx (1 hunks)
  • src/layout/FileUpload/FileUploadTable/FileTable.tsx (1 hunks)
  • src/layout/FileUpload/FileUploadTable/FileTableRow.tsx (1 hunks)
  • src/types/shared.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.module.css

📄 CodeRabbit inference engine (CLAUDE.md)

Use CSS Modules for component styling and follow existing patterns in *.module.css files

Files:

  • src/layout/FileUpload/FileUploadTable/AttachmentThumbnail.module.css
**/*.{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/language/texts/nb.ts
  • src/types/shared.ts
  • src/language/texts/nn.ts
  • src/layout/FileUpload/FileUploadTable/AttachmentThumbnail.tsx
  • src/layout/FileUpload/FileUploadTable/FileTableRow.tsx
  • src/language/texts/en.ts
  • src/layout/FileUpload/FileUploadTable/FileTable.tsx
🧬 Code graph analysis (4)
src/types/shared.ts (2)
src/types/index.ts (1)
  • LooseAutocomplete (51-51)
src/features/attachments/types.ts (1)
  • FileScanResult (1-1)
src/layout/FileUpload/FileUploadTable/AttachmentThumbnail.tsx (5)
src/features/attachments/index.ts (3)
  • IAttachment (22-22)
  • isAttachmentUploaded (29-31)
  • UploadedAttachment (20-20)
src/features/instance/InstanceContext.tsx (2)
  • useInstanceDataElements (139-143)
  • useLaxInstanceId (58-62)
src/features/language/LanguageProvider.tsx (1)
  • useCurrentLanguage (79-79)
src/utils/urls/urlHelper.ts (1)
  • makeUrlRelativeIfSameDomain (107-117)
src/utils/urls/appUrlHelper.ts (1)
  • getDataElementUrl (78-79)
src/layout/FileUpload/FileUploadTable/FileTableRow.tsx (13)
src/features/attachments/index.ts (2)
  • IAttachment (22-22)
  • isAttachmentUploaded (29-31)
src/utils/layout/hooks.ts (1)
  • useExternalItem (16-22)
src/features/pdf/PDFWrapper.tsx (1)
  • usePdfModeActive (11-15)
src/utils/attachmentsUtils.ts (1)
  • getSizeWithUnit (72-82)
src/core/contexts/TaskOverrides.tsx (1)
  • useTaskOverrides (32-32)
src/features/attachments/types.ts (1)
  • FileScanResults (3-8)
src/layout/FileUpload/FileUploadTable/AttachmentThumbnail.tsx (1)
  • AttachmentThumbnail (15-65)
src/layout/Summary2/CommonSummaryComponents/EditButton.tsx (1)
  • EditButton (48-116)
src/layout/FileUpload/FileUploadTable/AttachmentFileName.tsx (1)
  • AttachmentFileName (16-56)
src/theme/altinnAppTheme.tsx (1)
  • AltinnPalette (2-25)
src/components/AltinnLoader.tsx (1)
  • AltinnLoader (17-29)
src/layout/FileUpload/FileUploadTable/FileTableRowContext.tsx (1)
  • useFileTableRow (12-12)
src/layout/FileUpload/FileUploadTable/FileTableButtons.tsx (1)
  • FileTableButtons (26-109)
src/layout/FileUpload/FileUploadTable/FileTable.tsx (3)
src/features/attachments/index.ts (2)
  • IAttachment (22-22)
  • isAttachmentUploaded (29-31)
src/utils/formComponentUtils.ts (1)
  • atLeastOneTagExists (20-29)
src/layout/FileUpload/FileUploadTable/FileTableRow.tsx (1)
  • FileTableRow (32-126)
⏰ 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 (6)
src/language/texts/en.ts (1)

77-77: LGTM

Key name and placement align with existing patterns.

src/layout/FileUpload/FileUploadTable/FileTable.tsx (1)

99-103: A11y: column header aligns to data cell semantics

Thumb column is purely decorative; ensure cells use role="presentation" or images have empty alt when decorative. Verify AttachmentThumbnail sets appropriate alt.

Would you like a quick sweep to enforce alt="" and aria-hidden where appropriate?

src/layout/FileUpload/FileUploadTable/AttachmentThumbnail.tsx (2)

1-13: LGTM!

The imports and interface definition are well-structured and appropriate for the component's functionality.


53-64: LGTM!

The rendering logic is well-implemented with proper accessibility (alt text), conditional styling for mobile/desktop views, and test ID for testing purposes.

src/layout/FileUpload/FileUploadTable/FileTableRow.tsx (2)

13-13: LGTM!

The new import and optional hasImages prop are correctly integrated into the component interface.

Also applies to: 29-29


32-39: LGTM!

The hasImages prop is properly destructured and used for conditional rendering of the thumbnail cell.

Comment on lines +62 to +67
const calculateColSpan = () => {
if (mobileView) {
return hasImages ? 4 : 3;
}
return hasImages ? 7 : 6;
};
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

colSpan is off; causes misalignment, especially on mobile

Compute colSpan from the same conditions as headers to avoid drift.

-  const calculateColSpan = () => {
-    if (mobileView) {
-      return hasImages ? 4 : 3;
-    }
-    return hasImages ? 7 : 6;
-  };
+  const calculateColSpan = () => {
+    let count = 1; // Name
+    if (!mobileView) count += 1; // File size
+    if (hasTag && !mobileView) count += 1; // Tag
+    if (!pdfModeActive && !mobileView) count += 1; // Status
+    if (hasImages) count += 1; // Thumbnail
+    if (!pdfModeActive) count += 1; // Delete/Action
+    return count;
+  };
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const calculateColSpan = () => {
if (mobileView) {
return hasImages ? 4 : 3;
}
return hasImages ? 7 : 6;
};
const calculateColSpan = () => {
let count = 1; // Name
if (!mobileView) count += 1; // File size
if (hasTag && !mobileView) count += 1; // Tag
if (!pdfModeActive && !mobileView) count += 1; // Status
if (hasImages) count += 1; // Thumbnail
if (!pdfModeActive) count += 1; // Delete/Action
return count;
};
🤖 Prompt for AI Agents
In src/layout/FileUpload/FileUploadTable/FileTable.tsx around lines 62 to 67,
the calculateColSpan function returns hardcoded numbers that drift from the
actual headers and cause misalignment on mobile; change it to compute colspan
from the same visible headers used to render the table (e.g., derive the headers
array based on mobileView and hasImages and return headers.length or
visibleHeaders.length) instead of returning fixed constants so colspan always
matches header count.

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

♻️ Duplicate comments (1)
src/layout/FileUpload/FileUploadTable/FileTable.tsx (1)

62-67: calculateColSpan is inconsistent with actual column count (misaligned edit rows).

The current hard-coded values (mobileView ? 4/3 : 7/6) don’t match the real number of <td> cells rendered in FileTableRow across combinations of mobileView, hasTag, pdfModeActive, hasImages, and isSummary. This causes the edit row (<EditWindowComponent>) to span too many columns, particularly on mobile and when tags/thumbnails are toggled.

Recommend deriving colSpan from the same conditions used to render row cells so it always matches:

-  const calculateColSpan = () => {
-    if (mobileView) {
-      return hasImages ? 4 : 3;
-    }
-    return hasImages ? 7 : 6;
-  };
+  const calculateColSpan = () => {
+    let count = 1; // Name
+
+    if (!mobileView) {
+      count += 1; // File size
+      if (hasTag) {
+        count += 1; // Tag
+      }
+      if (!pdfModeActive) {
+        count += 1; // Status
+      }
+    }
+
+    if (hasImages) {
+      count += 1; // Thumbnail
+    }
+
+    const hasActionColumn = !isSummary || (!pdfModeActive && isSummary);
+    if (hasActionColumn) {
+      count += 1; // Delete/Edit actions
+    }
+
+    return count;
+  };

This keeps colSpan in lockstep with both header and body cells for all view modes.

🧹 Nitpick comments (3)
src/layout/FileUpload/FileUploadTable/FileTable.tsx (1)

43-52: Optional: precompute options lookup map to avoid repeated find.

label does an options?.find for each attachment; with many attachments this is O(n²) over options×attachments. Not a bug, just slightly wasteful.

If options can grow, consider precomputing a value→label map once per render:

-  const label = (attachment: IAttachment) => {
+  const optionLabelByValue = React.useMemo(
+    () => new Map(options?.map((o) => [o.value, o.label])),
+    [options],
+  );
+
+  const label = (attachment: IAttachment) => {
     if (!isAttachmentUploaded(attachment)) {
       return undefined;
     }
 
     const firstTag = attachment.data.tags && attachment.data.tags[0];
-    return options?.find((option) => option.value === firstTag)?.label;
+    return (firstTag && optionLabelByValue.get(firstTag)) || undefined;
   };

Not required for correctness, but keeps render cost flat as counts grow.

src/layout/FileUpload/FileUploadTable/FileTableRow.tsx (2)

23-39: hasImages prop usage looks good; consider defaulting to false on destructuring.

Using an optional hasImages?: boolean and checking {hasImages && ...} is safe (undefined is falsy) and keeps older call sites compatible. If you want to make intent explicit and help future readers, you could default it during destructuring:

-export function FileTableRow({
+export function FileTableRow({
   baseComponentId,
   attachment,
   mobileView,
   tagLabel,
   isSummary,
-  hasImages,
+  hasImages = false,
 }: IFileUploadTableRowProps) {

Not required, but clarifies that hasImages is effectively boolean.


129-185: Clean up unreachable / redundant conditions in NameCell mobile branch.

Inside the mobileView && (...) block:

  • tagLabel && mobileView repeats the mobileView check, which is already guaranteed true.
  • hasTag && !mobileView can never be true here (we’re in the mobileView branch), so that block is dead code.

You can simplify and drop the unreachable part without behavior change:

-        {mobileView && (
+        {mobileView && (
           <div
             style={{
               color: AltinnPalette.grey,
             }}
           >
             {attachment.uploaded ? (
               <div>
-                {tagLabel && mobileView && (
+                {tagLabel && (
                   <div>
                     <Lang id={tagLabel} />
                   </div>
                 )}
-                {`${readableSize} ${mobileView ? uploadStatus : ''}`}
-                {hasTag && !mobileView && (
-                  <div data-testid='status-success'>
-                    <Lang id='form_filler.file_uploader_list_status_done' />
-                  </div>
-                )}
+                {`${readableSize} ${uploadStatus}`}
               </div>
             ) : (

This keeps the mobile behavior identical while reducing noise.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7672e60 and 742b983.

📒 Files selected for processing (5)
  • src/language/texts/nb.ts (1 hunks)
  • src/language/texts/nn.ts (1 hunks)
  • src/layout/FileUpload/FileUploadTable/AttachmentThumbnail.tsx (1 hunks)
  • src/layout/FileUpload/FileUploadTable/FileTable.tsx (1 hunks)
  • src/layout/FileUpload/FileUploadTable/FileTableRow.tsx (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/language/texts/nb.ts
  • src/layout/FileUpload/FileUploadTable/AttachmentThumbnail.tsx
  • src/language/texts/nn.ts
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx}: Avoid using any type or type casting (as type) in TypeScript code; improve typing by avoiding casts and anys when refactoring
Use objects for managing query keys and functions, and queryOptions for sharing TanStack Query patterns across the system for central management

Files:

  • src/layout/FileUpload/FileUploadTable/FileTable.tsx
  • src/layout/FileUpload/FileUploadTable/FileTableRow.tsx
{**/*.module.css,**/*.{ts,tsx}}

📄 CodeRabbit inference engine (CLAUDE.md)

Use CSS Modules for component styling and leverage Digdir Design System components when possible

Files:

  • src/layout/FileUpload/FileUploadTable/FileTable.tsx
  • src/layout/FileUpload/FileUploadTable/FileTableRow.tsx
🧠 Learnings (1)
📚 Learning: 2025-10-14T09:01:40.985Z
Learnt from: lassopicasso
Repo: Altinn/app-frontend-react PR: 3654
File: src/layout/ImageUpload/ImageUploadSummary2/ImageUploadSummary2.tsx:49-53
Timestamp: 2025-10-14T09:01:40.985Z
Learning: In the Altinn app-frontend-react codebase, when data integrity is guaranteed through business logic and parent components guard rendering (e.g., `storedImage ? <Component /> : undefined`), non-null assertions on guaranteed fields like `storedImage!.data?.filename` are acceptable and preferred over optional chaining with fallbacks.

Applied to files:

  • src/layout/FileUpload/FileUploadTable/FileTable.tsx
🧬 Code graph analysis (1)
src/layout/FileUpload/FileUploadTable/FileTable.tsx (5)
src/features/attachments/index.ts (2)
  • IAttachment (22-22)
  • isAttachmentUploaded (29-31)
src/features/pdf/PDFWrapper.tsx (1)
  • usePdfModeActive (11-15)
src/utils/formComponentUtils.ts (1)
  • atLeastOneTagExists (20-29)
src/layout/FileUpload/FileUploadTable/FileTableRowContext.tsx (2)
  • FileTableRowContext (3-7)
  • FileTableRowProvider (11-11)
src/layout/FileUpload/FileUploadTable/FileTableRow.tsx (1)
  • FileTableRow (32-127)

@walldenfilippa
Copy link
Contributor Author

/publish

@github-actions
Copy link
Contributor

github-actions bot commented Dec 11, 2025

PR release:

  • <link rel="stylesheet" type="text/css" href="https://altinncdn.no/toolkits/altinn-app-frontend/4.23.0-pr.3276.Thumbnail.742b9837/altinn-app-frontend.css">
  • <script src="https://altinncdn.no/toolkits/altinn-app-frontend/4.23.0-pr.3276.Thumbnail.742b9837/altinn-app-frontend.js"></script>

⚙️ Building...
❌ Failed: https://github.com/Altinn/app-frontend-react/actions/runs/20134896062

@walldenfilippa walldenfilippa added the backport-ignore This PR is a new feature and should not be cherry-picked onto release branches label Dec 11, 2025
<Lang id={tagLabel} />
</div>
)}
{`${readableSize} ${mobileView ? uploadStatus : ''}`}

Check warning

Code scanning / CodeQL

Useless conditional Warning

This use of variable 'mobileView' always evaluates to true.
@walldenfilippa walldenfilippa added the ignore-for-release Pull requests to be ignored in release notes label Dec 11, 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: 0

🧹 Nitpick comments (2)
src/types/shared.ts (1)

24-27: Consider making the key field required in IMetadata.

The IMetadata interface has both key and value as optional, allowing metadata entries like {} or {value: 'bar'} without a key. Typically, metadata requires at least a key identifier for lookup purposes.

Consider this refinement:

 export interface IMetadata {
-  key?: string;
+  key: string;
   value?: string;
 }

This ensures every metadata entry has a key while keeping the value optional, which aligns better with the usage pattern metadata?.find((meta) => meta.key === 'thumbnailLink') seen in the codebase. However, if the backend API contract requires both fields to be optional, the current definition is acceptable.

src/layout/FileUpload/FileUploadTable/FileTableRow.tsx (1)

101-108: Consider adding visual feedback for empty thumbnail cells.

The thumbnail cell is always rendered when hasImages is true, but the AttachmentThumbnail component may return null for attachments without thumbnail metadata. This creates empty <td> elements that maintain table alignment but lack visual indicators.

Consider wrapping the thumbnail in a container that provides consistent visual presentation:

{hasImages && (
  <td>
    <AttachmentThumbnail
      attachment={attachment}
      mobileView={mobileView}
    />
    {/* Or conditionally render a placeholder */}
  </td>
)}

Alternatively, enhance the AttachmentThumbnail component to render a placeholder (e.g., an empty state icon or space preserver) instead of returning null when no thumbnail is available. This would ensure consistent table cell appearance across all rows when the thumbnail column is visible.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 742b983 and 86022a7.

📒 Files selected for processing (7)
  • src/language/texts/en.ts (1 hunks)
  • src/language/texts/nb.ts (1 hunks)
  • src/language/texts/nn.ts (1 hunks)
  • src/layout/FileUpload/FileUploadTable/AttachmentThumbnail.tsx (1 hunks)
  • src/layout/FileUpload/FileUploadTable/FileTable.tsx (1 hunks)
  • src/layout/FileUpload/FileUploadTable/FileTableRow.tsx (1 hunks)
  • src/types/shared.ts (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • src/language/texts/nn.ts
  • src/layout/FileUpload/FileUploadTable/FileTable.tsx
  • src/language/texts/en.ts
  • src/layout/FileUpload/FileUploadTable/AttachmentThumbnail.tsx
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx}: Avoid using any type or type casting (as type) in TypeScript code; improve typing by avoiding casts and anys when refactoring
Use objects for managing query keys and functions, and queryOptions for sharing TanStack Query patterns across the system for central management

Files:

  • src/language/texts/nb.ts
  • src/types/shared.ts
  • src/layout/FileUpload/FileUploadTable/FileTableRow.tsx
{**/*.module.css,**/*.{ts,tsx}}

📄 CodeRabbit inference engine (CLAUDE.md)

Use CSS Modules for component styling and leverage Digdir Design System components when possible

Files:

  • src/language/texts/nb.ts
  • src/types/shared.ts
  • src/layout/FileUpload/FileUploadTable/FileTableRow.tsx
🧬 Code graph analysis (1)
src/layout/FileUpload/FileUploadTable/FileTableRow.tsx (6)
src/features/attachments/index.ts (2)
  • IAttachment (22-22)
  • isAttachmentUploaded (29-31)
src/utils/attachmentsUtils.ts (1)
  • getSizeWithUnit (72-82)
src/features/attachments/types.ts (1)
  • FileScanResults (3-8)
src/layout/FileUpload/FileUploadTable/AttachmentThumbnail.tsx (1)
  • AttachmentThumbnail (15-58)
src/layout/FileUpload/FileUploadTable/AttachmentFileName.tsx (1)
  • AttachmentFileName (16-56)
src/layout/FileUpload/FileUploadTable/FileTableRowContext.tsx (1)
  • useFileTableRow (12-12)
⏰ 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: Type-checks, eslint, unit tests and SonarCloud
  • GitHub Check: Analyze (javascript)
🔇 Additional comments (4)
src/language/texts/nb.ts (1)

78-78: LGTM! Translation properly uses native Bokmål term.

The Norwegian Bokmål translation correctly uses "Miniatyrbilde" instead of the English "Thumbnail", ensuring consistency with other localized strings in the application.

src/types/shared.ts (1)

59-59: Field addition looks good.

The metadata field is appropriately optional and supports the thumbnail feature integration described in the PR. The inline comment clearly documents its purpose.

src/layout/FileUpload/FileUploadTable/FileTableRow.tsx (2)

1-30: Imports and interface changes look good.

The new AttachmentThumbnail import and the hasImages prop addition properly support the thumbnail feature. The interface follows TypeScript best practices with the optional hasImages field.


84-92: File size cell properly added, resolving past misalignment issue.

The file size cell at line 92 correctly addresses the column misalignment issue flagged in the previous review. The cell is conditionally rendered when !mobileView, matching the header structure in FileTable.

@walldenfilippa walldenfilippa added kind/product-feature Pull requests containing new features and removed ignore-for-release Pull requests to be ignored in release notes labels Dec 11, 2025
@walldenfilippa walldenfilippa marked this pull request as draft December 11, 2025 14:17
@walldenfilippa
Copy link
Contributor Author

/publish

@github-actions
Copy link
Contributor

github-actions bot commented Dec 11, 2025

PR release:

  • <link rel="stylesheet" type="text/css" href="https://altinncdn.no/toolkits/altinn-app-frontend/4.24.0-pr.3279.Thumbnail.86022a75/altinn-app-frontend.css">
  • <script src="https://altinncdn.no/toolkits/altinn-app-frontend/4.24.0-pr.3279.Thumbnail.86022a75/altinn-app-frontend.js"></script>

⚙️ Building...
❌ Failed: https://github.com/Altinn/app-frontend-react/actions/runs/20136399825

@walldenfilippa walldenfilippa deleted the Feat/Thumbnail branch December 12, 2025 08:13
@walldenfilippa
Copy link
Contributor Author

new PR: #3898

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