Skip to content

Conversation

@JamalAlabdullah
Copy link
Contributor

@JamalAlabdullah JamalAlabdullah commented Dec 14, 2025

Description

closes: #16422

Changes:

  • When a row in a repeating group is non-editable (i.e. the edit button is turned off) and the target component is not editable, the edit button in Summary2 should be hidden as well.
  • Many rules govern if a component is editable and not, so this is complex - and we also need to pass this info along to the edit button possibly rendered from another component Summary2 rendering, thus I opted for using a context.
  • Adding Cypress test to ensure different modes hide/unhide the edit button

Test:

Add this to RepeatingGroup in json file after adding a few rows:

"edit": {
  "editButton": false
}

Related Issue(s)

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

    • Per-row edit button visibility in repeating-group summaries now respects per-row editability, improving control over which rows show an edit action.
  • Tests

    • Added unit and end-to-end tests ensuring edit buttons are shown or hidden per-row based on layout configuration and read-only states.

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

@JamalAlabdullah JamalAlabdullah added kind/bug Something isn't working backport-ignore This PR is a new feature and should not be cherry-picked onto release branches squad/utforming Issues that belongs to the named squad. labels Dec 14, 2025
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 14, 2025

📝 Walkthrough

Walkthrough

Per-row editability was introduced for Summary2 repeating groups: rendering of Edit buttons is gated by per-row expressions and an editable-child context; layout hooks compute editable child IDs; tests and an e2e case were added/updated to exercise editButton visibility.

Changes

Cohort / File(s) Summary
Edit button behavior & components
src/layout/Summary2/CommonSummaryComponents/EditButton.tsx
Edit button now checks repeating-group editable context (useIsEditableInRepGroup) and exports EditButtonFirstVisibleAndEditable (renamed, fallback may be undefined). Adds data-target-id and changes target resolution/skipLastIdMutator logic.
Repeating group summary rendering
src/layout/RepeatingGroup/Summary2/RepeatingGroupSummary.tsx, src/layout/RepeatingGroup/Summary2/RepeatingGroupTableSummary/RepeatingGroupTableSummary.tsx
Rows refactored to RepGroupListRow; per-row hooks compute rowWithExpressions and editableChildIds. Table summary uses editable IDs for edit-button rendering and keys, and adjusts fallback logic when edit.editButton is false.
Editable-context implementation
src/layout/RepeatingGroup/Summary2/RepGroupSummaryEditableContext.tsx
New context provider RepGroupSummaryEditableProvider and hook useIsEditableInRepGroup(baseId) expose per-row editable-child membership as a Set.
Repeating-group hooks / utils
src/layout/RepeatingGroup/utils.ts
Adds helper isChildEditableCheck and public hook RepGroupHooks.useEditableChildren(baseComponentId, rowWithExpressions) to compute editable child base IDs for a row.
Unit tests
src/layout/RepeatingGroup/Summary2/RepeatingGroupTableSummary/RepeatingGroupTableSummary.test.tsx
Test helper layoutWithHidden extended to accept editButton flag; added tests asserting Edit button absent when edit.editButton is false and present when true.
End-to-end test
test/e2e/integration/component-library/repeating-group.ts
New e2e scenario validating hiding/showing of edit buttons in Summary2 with nested repeating groups, toggling edit.editButton, tableColumns, and readOnly states.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 37.50% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Hide edit button in Summary when target not editable' clearly and specifically describes the main change: conditionally hiding edit buttons based on editability state in the Summary view.
Description check ✅ Passed The description includes the related issue, clear explanation of changes, verification/QA checklist with appropriate sections checked, and proper labels for release notes grouping.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ 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 16422-endre-knapp-vises-i-summary2-på-en-ikke-redigerbar-repeterende-gruppe

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

@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! 🙌

@olemartinorg
Copy link
Contributor

@JamalAlabdullah Maybe you should backport this? Since this is a bugfix, we can backport it and release it in a patch-release. Just switch to the backport label and it will be done mostly automatically.

@JamalAlabdullah JamalAlabdullah moved this from 🔎 In review to 🧪 Test in Team Altinn Studio Jan 5, 2026
@JamalAlabdullah JamalAlabdullah added backport This PR should be cherry-picked onto older release branches and removed backport-ignore This PR is a new feature and should not be cherry-picked onto release branches labels Jan 5, 2026
@lassopicasso lassopicasso self-assigned this Jan 6, 2026
@lassopicasso
Copy link
Contributor

@JamalAlabdullah noen tester feiler, kan du se på de?

@olemartinorg
Copy link
Contributor

Tror disse testene løser seg selv hvis du merger fra main en gang, @JamalAlabdullah - det er en del som har blitt fikset der nå.

Copy link
Contributor

@lassopicasso lassopicasso left a comment

Choose a reason for hiding this comment

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

Jeg har testet den, ser bra ut. Edit knappen vises ikke i tabellen hvis man setter editButton: false. Men skal denne knappen også skjules hvis repeterende gruppe vises som gruppe i oppsummeringen? Den gjør den ikke nå.

image

La forresten merke til at skillelinjene ikke tar full bredde når edit-knapp ikke er tilstede. Er dette ønskelig?

@JamalAlabdullah
Copy link
Contributor Author

JamalAlabdullah commented Jan 6, 2026

Jeg har testet den, ser bra ut. Edit knappen vises ikke i tabellen hvis man setter editButton: false. Men skal denne knappen også skjules hvis repeterende gruppe vises som gruppe i oppsummeringen? Den gjør den ikke nå.

image La forresten merke til at skillelinjene ikke tar full bredde når edit-knapp ikke er tilstede. Er dette ønskelig?

I am not sure if we need this also? i just followed the description in the issue , I fixed the dividing lines width.

Screenshot 2026-01-06 at 17 34 46

Copy link
Contributor

@lassopicasso lassopicasso left a comment

Choose a reason for hiding this comment

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

I am not sure if we need this also? i just followed the description in the issue , I fixed the dividing lines width.

Perhaps it is not necessary, do you have any thoughts about it @olemartinorg ? I approve this.

@olemartinorg
Copy link
Contributor

Hmm, I tested this now, and there are a lot of edit buttons showing up in ttd/component-library when I have added a few rows and turned off the edit button afterwards.. However, the edit buttons showing up in other modes are rendered for the individual components (i.e. 'name', 'points', 'date'), not the repeating group row itself. So if you just set edit.editButton: false on the row without somehow making the components inside editable (such as setting editInTable) you've also removed any possibility for the user to see that component, let alone edit it... So, a fully 'proper' fix for this should probably check all child-components to make sure they are somehow editable (either inside the edit mode or in the table), but that could become very complex.

On the flip side, even if you turn edit.editButton: false, components can still be editable in the table, so removing the edit button in this case would possibly also break some apps where that is the case.

In the older Summary component we have the EditButtonFirstVisible component - maybe we could do something like that here as well? Looking to find the first editable component in a row, show the edit button in that case, otherwise hide the edit button for that row.

TL;DR: When thinking about it more, this is probably more complex than it seemed at first glance. The current fix might even break some configurations.

@JamalAlabdullah I can take a look at this one for you, if you want!

@olemartinorg olemartinorg removed the squad/utforming Issues that belongs to the named squad. label Jan 8, 2026
@olemartinorg olemartinorg removed their assignment Jan 8, 2026
@olemartinorg olemartinorg changed the title hide edit button in summery 2 Hide edit button in Summary when target not editable Jan 9, 2026
@olemartinorg olemartinorg changed the base branch from main to chore/button-refactor January 9, 2026 14:28
@olemartinorg olemartinorg force-pushed the 16422-endre-knapp-vises-i-summary2-på-en-ikke-redigerbar-repeterende-gruppe branch from fd81601 to 859c6ac Compare January 9, 2026 14:29
Base automatically changed from chore/button-refactor to main January 12, 2026 12:17
JamalAlabdullah and others added 3 commits January 12, 2026 13:19
… be considered editable inside a repeating group. This works much better in the summary view now, and the test should cover most things
@olemartinorg olemartinorg force-pushed the 16422-endre-knapp-vises-i-summary2-på-en-ikke-redigerbar-repeterende-gruppe branch from 859c6ac to db26f3e Compare January 12, 2026 12:19
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: 1

🤖 Fix all issues with AI agents
In
@src/layout/RepeatingGroup/Summary2/RepeatingGroupTableSummary/RepeatingGroupTableSummary.tsx:
- Line 144: The hook is being called with an empty-string UUID fallback which
can produce an invalid lookup; instead call useRowWithExpressions with a
meaningful sentinel when row is missing, e.g. pass row ? { uuid: row.uuid } :
'first' so you don't supply '' — update the call to
RepGroupHooks.useRowWithExpressions(baseComponentId, row ? { uuid: row.uuid } :
'first') to avoid the empty-string UUID case while keeping hooks order stable.
🧹 Nitpick comments (3)
src/layout/RepeatingGroup/utils.ts (1)

266-274: Consider memoizing the returned array.

The filter call creates a new array reference on every render, which could cause unnecessary re-renders in consuming components. Other hooks in this file (e.g., useAllRowsWithHidden, useAllRowsWithButtons) use useMemo to stabilize their return values.

♻️ Suggested memoization
   useEditableChildren(baseComponentId: string, rowWithExpressions: RepGroupRowWithExpressions | undefined): string[] {
     const childrenBaseIds = RepGroupHooks.useChildIds(baseComponentId);
     const layoutLookups = useLayoutLookups();
     const component = layoutLookups.getComponent(baseComponentId, 'RepeatingGroup');
 
-    return childrenBaseIds.filter((childId) =>
-      isChildEditableCheck(childId, layoutLookups, component, rowWithExpressions),
-    );
+    return useMemo(
+      () =>
+        childrenBaseIds.filter((childId) =>
+          isChildEditableCheck(childId, layoutLookups, component, rowWithExpressions),
+        ),
+      [childrenBaseIds, layoutLookups, component, rowWithExpressions],
+    );
   },
src/layout/RepeatingGroup/Summary2/RepGroupSummaryEditableContext.tsx (1)

19-21: Memoization depends on array reference stability.

The useMemo dependency is [editableChildIds], which is an array. If the parent component passes a new array reference on each render (even with the same contents), this will create a new Set unnecessarily.

However, looking at the usage in RepeatingGroupSummary.tsx, the editableChildIds comes from RepGroupHooks.useEditableChildren, which currently doesn't memoize its result (as noted in my earlier comment). If that hook is updated to use useMemo, this concern is mitigated.

Consider using a deep comparison hook like useMemoDeepEqual (already imported in utils.ts) if array contents stability is important, or ensure the upstream hook memoizes its output.

src/layout/RepeatingGroup/Summary2/RepeatingGroupTableSummary/RepeatingGroupTableSummary.tsx (1)

146-146: Potential duplicate IDs and O(n) lookup.

The combination [...ids, ...children] may contain duplicates since table IDs are typically a subset of children. Also, editableChildren.includes(id) is O(n) for each element.

Consider using a Set for both deduplication and faster lookup:

♻️ Suggested optimization
-  const editableIds = [...ids, ...children].filter((id) => editableChildren.includes(id));
+  const editableSet = new Set(editableChildren);
+  const editableIds = [...new Set([...ids, ...children])].filter((id) => editableSet.has(id));
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between fd81601 and db26f3e.

📒 Files selected for processing (7)
  • src/layout/RepeatingGroup/Summary2/RepGroupSummaryEditableContext.tsx
  • src/layout/RepeatingGroup/Summary2/RepeatingGroupSummary.tsx
  • src/layout/RepeatingGroup/Summary2/RepeatingGroupTableSummary/RepeatingGroupTableSummary.test.tsx
  • src/layout/RepeatingGroup/Summary2/RepeatingGroupTableSummary/RepeatingGroupTableSummary.tsx
  • src/layout/RepeatingGroup/utils.ts
  • src/layout/Summary2/CommonSummaryComponents/EditButton.tsx
  • test/e2e/integration/component-library/repeating-group.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/layout/RepeatingGroup/Summary2/RepeatingGroupTableSummary/RepeatingGroupTableSummary.test.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/layout/RepeatingGroup/utils.ts
  • test/e2e/integration/component-library/repeating-group.ts
  • src/layout/RepeatingGroup/Summary2/RepeatingGroupSummary.tsx
  • src/layout/RepeatingGroup/Summary2/RepGroupSummaryEditableContext.tsx
  • src/layout/Summary2/CommonSummaryComponents/EditButton.tsx
  • src/layout/RepeatingGroup/Summary2/RepeatingGroupTableSummary/RepeatingGroupTableSummary.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/RepeatingGroup/utils.ts
  • test/e2e/integration/component-library/repeating-group.ts
  • src/layout/RepeatingGroup/Summary2/RepeatingGroupSummary.tsx
  • src/layout/RepeatingGroup/Summary2/RepGroupSummaryEditableContext.tsx
  • src/layout/Summary2/CommonSummaryComponents/EditButton.tsx
  • src/layout/RepeatingGroup/Summary2/RepeatingGroupTableSummary/RepeatingGroupTableSummary.tsx
🧠 Learnings (1)
📚 Learning: 2025-11-25T12:53:54.399Z
Learnt from: CR
Repo: Altinn/app-frontend-react PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T12:53:54.399Z
Learning: Applies to **/*.test.{ts,tsx} : Use `renderWithProviders` from `src/test/renderWithProviders.tsx` when testing components that require form layout context

Applied to files:

  • src/layout/RepeatingGroup/utils.ts
  • src/layout/RepeatingGroup/Summary2/RepGroupSummaryEditableContext.tsx
🧬 Code graph analysis (3)
src/layout/RepeatingGroup/Summary2/RepGroupSummaryEditableContext.tsx (1)
src/core/contexts/context.tsx (1)
  • createContext (45-89)
src/layout/Summary2/CommonSummaryComponents/EditButton.tsx (3)
src/utils/layout/hidden.ts (2)
  • useIsHiddenMulti (82-136)
  • useIsHidden (44-77)
src/layout/Summary/EditButton.tsx (1)
  • EditButton (14-30)
src/layout/RepeatingGroup/Summary2/RepGroupSummaryEditableContext.tsx (1)
  • useIsEditableInRepGroup (27-33)
src/layout/RepeatingGroup/Summary2/RepeatingGroupTableSummary/RepeatingGroupTableSummary.tsx (3)
src/layout/RepeatingGroup/useTableComponentIds.ts (1)
  • useTableComponentIds (10-48)
src/layout/RepeatingGroup/utils.ts (1)
  • RepGroupHooks (97-275)
src/layout/Summary2/CommonSummaryComponents/EditButton.tsx (1)
  • EditButtonFirstVisibleAndEditable (28-49)
⏰ 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
🔇 Additional comments (9)
test/e2e/integration/component-library/repeating-group.ts (1)

189-265: Well-structured E2E test covering multiple scenarios.

The test effectively covers the key scenarios:

  1. Initial state with edit buttons visible
  2. Hiding edit buttons via edit.editButton = false
  3. Re-enabling edit for specific components via editInTable: true
  4. Verifying readOnly components don't get edit buttons

The use of data-target-id selectors provides precise verification of which specific edit buttons are rendered.

src/layout/RepeatingGroup/Summary2/RepeatingGroupSummary.tsx (2)

143-175: Good extraction of per-row rendering logic.

The RepGroupListRow component cleanly encapsulates:

  • Row expression computation
  • Editable children calculation
  • Context providers for data model location and editability
  • Conditional divider rendering

This separation improves readability and ensures each row has its own editability context.


139-139: Type at line 139 may not match the actual IDataModelBindings<'RepeatingGroup'> structure.

The component declares dataModelBindings: { group: IDataModelReference } as required, but throughout the codebase, group is consistently accessed with optional chaining (e.g., ?.group). This pattern appears in utils.ts, Summary.tsx, and test files, suggesting group is optional in the actual type. If group can be undefined, the type should reflect this as { group?: IDataModelReference } or the component should add a guard before using dataModelBindings.group at line 158.

src/layout/RepeatingGroup/Summary2/RepGroupSummaryEditableContext.tsx (1)

27-33: Safe default behavior for context absence.

Returning true when no context is provided ensures backward compatibility - components outside repeating group contexts will remain editable by default. The Set.has() provides efficient O(1) lookup.

src/layout/RepeatingGroup/Summary2/RepeatingGroupTableSummary/RepeatingGroupTableSummary.tsx (1)

172-176: Correct gating logic for edit button visibility.

The implementation correctly:

  • Uses key={editableIds.join(',')} to trigger re-renders when editability changes
  • Provides editableIds as the pool of potential targets
  • Sets fallback to undefined when editButton is false, ensuring no edit button appears for non-editable rows
src/layout/Summary2/CommonSummaryComponents/EditButton.tsx (3)

78-82: Hook call placement may cause unnecessary early returns.

The useIsEditableInRepGroup hook is called unconditionally (which is correct for React hooks), but the check is placed before other conditionals that might also return null (like isReadOnly, overriddenDataElementId, pdfModeActive).

This is fine for correctness, but if useIsEditableInRepGroup is expensive, consider ordering checks from cheapest to most expensive. However, since it's just a context lookup with a Set check, the current placement is acceptable.


28-49: Clean implementation of visibility and editability gating.

The component properly:

  1. Finds the first visible ID from the candidates
  2. Falls back to the provided fallback if all candidates are hidden
  3. Returns null when no valid target exists
  4. Correctly sets skipLastIdMutator when using the fallback

The rename from EditButtonFirstVisible to EditButtonFirstVisibleAndEditable accurately reflects the new behavior where editability is considered.


116-116: Useful addition for testing and debugging.

The data-target-id attribute enables precise selection of edit buttons in tests (as seen in the E2E test using cy.get('button[data-target-id="..."]')), making tests more robust and easier to debug.

src/layout/RepeatingGroup/utils.ts (1)

84-86: No changes needed — the expression handling is correct.

The columnSettings?.hidden === true check at line 85 is appropriate. Although tableColumns[column].hidden can initially be an expression, it is evaluated to a boolean value in src/layout/RepeatingGroup/index.tsx (line 56) via evalBool(tableColumns[column].hidden, false) before the component is stored. By the time isChildEditableCheck receives parentComponent, the hidden field is already a boolean, so the === true check correctly distinguishes between true and false/undefined cases.

@sonarqubecloud
Copy link

@JamalAlabdullah JamalAlabdullah added the squad/utforming Issues that belongs to the named squad. label Jan 15, 2026
@JamalAlabdullah JamalAlabdullah moved this to 🔎 In review in Team Altinn Studio Jan 15, 2026
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 squad/utforming Issues that belongs to the named squad.

Projects

Status: 🔎 In review

Development

Successfully merging this pull request may close these issues.

Endre-knapp vises i Summary2 på en ikke-redigerbar repeterende gruppe

3 participants