fix: scope repeating group validation errors to the invalid instance (#1985)#1999
Open
clinnygee wants to merge 1 commit into
Open
fix: scope repeating group validation errors to the invalid instance (#1985)#1999clinnygee wants to merge 1 commit into
clinnygee wants to merge 1 commit into
Conversation
…1985) Validation errors were stored/looked up in a flat map keyed only by `linkId`, so all instances of a repeating group child shared one key. A single invalid instance therefore displayed its error on every instance. Errors are now keyed by `linkId` plus the path of enclosing repeat-group instance indices (e.g. `child-field///1`). Non-repeating items keep a bare `linkId` key, so their behaviour is unchanged. Validation and the display hook build the identical key from a shared helper (getValidationErrorKey), and the instance-index path is supplied to descendants via a React context (RepeatGroupInstanceContext) provided per RepeatGroup instance and gtable row. This works even when a required field has no qrItem yet, and requires no mutation of the QuestionnaireResponse. - add utils/validateErrorKey.ts (getValidationErrorKey / getBaseLinkIdFromErrorKey) - add contexts/RepeatGroupInstanceContext.ts - thread repeatInstancePath through validate.ts and key all error write sites - provide the context in RepeatGroupItem and GroupTableRow - consume the context in useValidationFeedback - export the helpers; map error keys back to base linkIds in SaveAsFinalAction so "jump to first error tab" still resolves - add unit + integration tests Out of scope (follow-ups): targetConstraint per-instance validation and repeating single (non-group) items remain keyed by linkId. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #1985
Problem
Validation errors on repeating group items showed on all instances when only one was invalid. Errors were stored/looked up in a flat
Record<linkId, OperationOutcome>, and every field looked itself up asinvalidItems[qItem.linkId]. Because all instances of a repeat-group child share onelinkId, they collided on a single key — one invalid instance lit up all of them. The save gate was unaffected; this was purely a display issue.Fix
Errors are now keyed by
linkIdplus the path of enclosing repeat-group instance indices (e.g.child-field///1). Non-repeating items have an empty path, so their key stays a barelinkId— no behaviour change.Validation (a pure function over the QR) and the display hook build the identical key from one shared helper, so they always agree without mutating or persisting anything into the
QuestionnaireResponse. The instance-index path reaches descendants through a small React context provided per repeat instance / gtable row.utils/validateErrorKey.ts—getValidationErrorKey()/getBaseLinkIdFromErrorKey()contexts/RepeatGroupInstanceContext.ts— carries the instance-index pathutils/validate.ts— threadsrepeatInstancePaththrough the recursion and keys all three error write sites via the helperRepeatGroupItem.tsxandGroupTableRow.tsx— provide their index path via the contextuseValidationFeedback.ts— reads the context and looks up the instance-scoped key (no signature change, so the ~25 leaf components are untouched)SaveAsFinalAction.tsx— maps error keys back to base linkIds so "jump to first error tab" still resolvesWhy not the literal
qrItem.id ?? linkIdfrom the issue?The primary reported case is an empty required field, which has no
qrItemat the leaf (it arrives asundefined) — so there'd be nothing to carry an id. A position-path key handles that case, needs no QR mutation/stripping, and composes for nested repeat groups.Out of scope (follow-ups)
targetConstraintper-instance validation (explicitly deferred in the issue)linkIdNested repeat groups and
gtablerows are covered by this change.Testing
test/validateErrorKey.test.ts(pure helper) andtest/validateRepeatInstance.test.ts(end-to-endvalidateForm: only the empty instance is flagged, not the answered one nor the barelinkId)npm run build: clean ·npm run lint: 0 errors · apptsc --noEmit: clean🤖 Generated with Claude Code