Skip to content

Fix/5109 debounce metadata field keystroke#5874

Open
shernandez-dev wants to merge 3 commits into
DSpace:mainfrom
shernandez-dev:fix/5109-debounce-metadata-field-keystroke
Open

Fix/5109 debounce metadata field keystroke#5874
shernandez-dev wants to merge 3 commits into
DSpace:mainfrom
shernandez-dev:fix/5109-debounce-metadata-field-keystroke

Conversation

@shernandez-dev

@shernandez-dev shernandez-dev commented Jun 26, 2026

Copy link
Copy Markdown

References

Description

Debounces metadata field name input and gates findDsoFieldVocabulary() behind validateMetadataField() to prevent 422 errors being triggered on every keystroke when editing item metadata.

Instructions for Reviewers

Root Cause

DsoEditMetadataValueComponent#ngOnChanges reassigned fieldType$ on every input change, immediately invoking findDsoFieldVocabulary() with no debounce. The isNotEmpty() guard in DsoEditMetadataFieldService passed for any non-empty string including partial inputs like dc.re, causing byMetadataAndCollection requests that resulted in 422 errors. Since the 422 propagates through the full Spring Security filter chain before reaching the controller layer, no @ExceptionHandler catches it — which is why the stack traces are so verbose.

Reproduced and confirmed on DSpace 9.1, DSpace 10.0 and DSpace 11.0-SNAPSHOT.

List of changes

  • dso-edit-metadata-value.component.ts: Moved fieldType$ initialization to ngOnInit using the existing _mdField$ BehaviorSubject with a reactive pipeline: debounceTimeWorkaround(300) + distinctUntilChanged() + regex guard + validateMetadataField() before calling findDsoFieldVocabulary(). Replaced includes('.') with the same regex guard in ngOnChanges. Removed unused getFieldType() method.
  • dso-edit-metadata-field.service.ts: Added VALID_METADATA_FIELD_PATTERN regex as a defensive guard in findDsoFieldVocabulary(), rejecting inputs that don't match schema.element or schema.element.qualifier format before making any HTTP request.
  • dso-edit-metadata-value.component.spec.ts: Added 10 new unit tests for the fieldType$ pipeline using fakeAsync/tick(300), consistent with the project's debounceTimeWorkaround testing approach.

Before

Typing dc.contributor.author (20 chars) generated ~40 requests and thousands of log lines per session, e.g.:

[422] dc.c is not a valid metadata
[422] dc.co is not a valid metadata
[422] dc.con is not a valid metadata
[422] dc.cont is not a valid metadata
... (stack trace repeating for each keystroke)

After

Typing dc.contributor.author generates exactly 1 request to byMetadataAndCollection, fired only after the field is confirmed valid:

GET /server/api/core/metadatafields/search/byFieldName  ← field confirmed valid
GET /server/api/submission/vocabularies/search/byMetadataAndCollection  ← 200 OK

How to Test

  1. Start DSpace backend and frontend
  2. Navigate to an item's edit metadata page: /items/{uuid}/edit/metadata
  3. Click "+ Add"
  4. Slowly type dc.contributor.author in the metadata field name input, pausing between keystrokes
  5. Monitor backend logs: docker logs -f dspace | grep -E "422|byMetadataAndCollection"

Expected result: No 422 errors appear in the logs during typing. A single byMetadataAndCollection request fires only after the complete field name has been confirmed as valid.

Checklist

  • My PR is created against the main branch
  • My PR is small in size (3 files modified)
  • My PR passes ESLintnpm run lint fails with a pre-existing error unrelated to this fix (src/themes/custom/eager-theme-components.ts). ESLint was run directly on the 3 modified files and passes without errors.
  • My PR doesn't introduce circular dependencies (verified via npx madge --circular on the affected directory)
  • My PR includes TypeDoc comments for modified methods
  • My PR passes all specs/tests and includes new/updated specs
  • My PR aligns with Accessibility guidelines (no UI changes)
  • My PR uses i18n keys (no hardcoded English text added)
  • My PR includes details on how to test it

@shernandez-dev shernandez-dev force-pushed the fix/5109-debounce-metadata-field-keystroke branch from a17f984 to f51c21b Compare June 26, 2026 21:08
@shernandez-dev

Copy link
Copy Markdown
Author

The failing test (AuthService > should return false when token is not expired) is unrelated to this PR. All tests related to the changes introduced in this PR pass successfully on both Node 20.x and 22.x.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

DsoEditMetadataValueComponent#ngOnChanges fires vocabulary requests on incomplete metadata fields, spamming 422 errors in dspace.log

1 participant