UoE/WP2-2026-07-09 bugfixes #6
Merged
dspeed2 merged 22 commits intoJul 9, 2026
Merged
Conversation
Replace the per-file "Format" line in the full item view file listing with a "File checksum" line (algorithm + value). Add the checkSum field to the Bitstream model so the REST value deserializes, and add the item.page.filesection.checksum i18n key. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Wrap the full item view checksum dt/dd in *ngIf="file?.checkSum" and render only the checksum value (drop the algorithm prefix), so no stray colon shows when a bitstream has no checksum. Propagate item.page.filesection.checksum to all locale files with an English placeholder. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Match DSpace/dspace-angular@main (commit 4f72074): use the exported ChecksumInfo interface and `checkSum: ChecksumInfo` positioned after `description`, replacing the inline anonymous type, to minimize conflicts on a future DSpace 9 migration. Display and i18n key are unchanged (upstream renders no checksum row in the full item view). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
UoE instance only ships English; other locale .json5 files aren't maintained here. Revert the checksum key addition to all 27 non-en locales, keep it in en.json5 only. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
file is guaranteed by *ngFor and checkSum is truthy inside the *ngIf guard, so use plain file.checkSum / file.checkSum.value to match the surrounding template style. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…chMap -> concatMap) Backport of the save-effect change from upstream PR DSpace#5145 (commit a3c14c5, first released in DSpace 10.0; not present in 8.x/9.x). The four submission save effects used switchMap. When two save actions of the same type overlap (common during editing: unguarded section/upload/save-for-later saves, save-on-change on validation errors, or an enabled autosave timer), switchMap cancels the in-flight save's inner observable AFTER it dispatched StartTransactionPatchOperationsAction (commitPending=true) but BEFORE its response handler runs. Commit/Rollback are dispatched only inside that cancelled observable, so commitPending stays true forever; the next save is then dropped by the take(1)+filter(!commitPending) guard in submitJsonPatchOperations, no SAVE_*_SUCCESS/ERROR is emitted, savePending stays true, and the form is stuck on "Saving..." until the user reloads (losing unsaved metadata). concatMap serializes the save effects so each inner observable completes (dispatching Commit/Rollback and clearing commitPending) before the next save runs, eliminating the race. Only the four save effects are changed (saveSubmission$, saveForLaterSubmission$, saveSection$, saveAndDeposit$), matching upstream. deposit/discard/updateSection intentionally keep switchMap. The improved catchError from DSpace#5145 is not backported (it depends on parseErrorResponse and action signatures not present in 8.3). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…nners Fixes a class of "spinner spins forever, user must reload and loses typed metadata" bugs in the submission form. A component sets a loading/searching flag, loads data via a RemoteData pipe, and resets the flag ONLY on the success path using getFirstSucceededRemoteData()/...Payload()/...ListPayload(). DSpace turns HTTP errors into a NON-throwing failed RemoteData (state=Error), and the store-backed RemoteData observable never completes, so on a failed OR slow/ never-responding request the success-only operator never emits, the component's catchError (which only catches thrown errors) never fires, and the spinner stays forever. There is also no HTTP request timeout anywhere in the app. Inherited from vanilla DSpace 8.3 and NOT fixed upstream (the same pattern is still present on main/10.x), so there is no backport available -- this is a new hardening fix, following the same getFirstCompletedRemoteData approach upstream used for the whole-form loading fix (DSpace#4060). For each affected load: switch getFirstSucceededRemoteData* to getFirstCompletedRemoteData() (emits on success AND failure, then completes), extract the payload failure-safely, add timeout({ each: 30000 }) for never-responding requests, and reset the spinner flag in finalize() so it always clears. On failure/timeout the control shows an empty result instead of hanging. Sites fixed (all inherited from 8.3): - sections/form/section-form.component.ts (Describe section) -- bounded 30s timeout so it never spins forever; kept getFirstSucceededRemoteData for the item follow-link to avoid dereferencing an undefined submission object. - ds-dynamic-form-ui/models/list/dynamic-list.component.ts (radio/checkbox vocab, e.g. dc.type) - ds-dynamic-form-ui/models/scrollable-dropdown/dynamic-scrollable-dropdown.component.ts (vocabulary dropdowns) - ds-dynamic-form-ui/models/onebox/dynamic-onebox.component.ts (authority typeahead) - ds-dynamic-form-ui/models/tag/dynamic-tag.component.ts (keyword/tag authority) - ds-dynamic-form-ui/models/lookup/dynamic-lookup.component.ts (lookup authority) - vocabulary-treeview/vocabulary-treeview.service.ts (hierarchical vocabulary tree) - collection-dropdown/collection-dropdown.component.ts (collection picker; parentCommunity was hanging reduce()) - submission/form/collection/submission-form-collection.component.ts (change-collection selector) - sections/cc-license/submission-section-cc-licenses.component.ts (CC-license section) - ds-dynamic-form-ui/models/relation-group/dynamic-relation-group.components.ts (relation chips on edit) Verified locally: `tsc --noEmit -p tsconfig.app.json` and `eslint` both pass with 0 errors on the changed files. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Deterministic reproduction on a local DSpace 8.3 stack (published dspace-8_x-test
backend images + this frontend). A Playwright script simulates a failing/slow
controlled-vocabulary endpoint by returning HTTP 500 for
/api/submission/vocabularies/{name}/entries, then opens the "Type" dropdown on a
new submission's Describe form.
- before: getFirstSucceededRemoteData ignores the failed RemoteData, so the "Loading..."
indicator stays visible forever (measured stuck for the full 14s observation window).
- after: getFirstCompletedRemoteData + finalize handles the failed RemoteData, the
spinner clears immediately and the dropdown shows "No results found".
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Deterministic reproduction on a local DSpace 8.3 stack. A Playwright script delays every submission PATCH by ~3s (models a slow save) and fires two overlapping autosaves (two edits of the autosave-on-change dc.title field). - before (base, switchMap): the second save cancels the in-flight first save mid-transaction; commitPending is orphaned true; the second save is dropped by the take(1)+filter(!commitPending) guard (only 1 PATCH ever leaves the client); savePending never resets -> footer stuck on "Saving..." for the full 18s window. - after (this PR, concatMap): the saves are serialized; the first completes and clears commitPending before the second runs; "Saving..." clears within ~4s. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…fter
Second reproduction covering the slow/never-responding path (not just HTTP 500).
The vocabulary /entries request is held open forever (models a hung socket).
- before (no timeout): "Loading..." stays stuck past 45s (never recovers).
- after (timeout({each:30000})): the spinner clears ~30s after the request stalls
and the dropdown shows "No results found".
Clips are sped up ~3x. Confirms the timeout() backstop half of the fix, which the
HTTP-500 reproduction did not exercise.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…tion is pending
The DataShare simple item view renders the DOI ("Persistent Identifier") field
via ds-item-page-uri-field, which filtered dc.identifier.uri for values starting
with https://doi.org. The whole field wrapper was gated behind *ngIf="hasDoiLink",
so when a record's DOI has not been registered yet (the DOI value is only written
to dc.identifier.uri by the backend AFTER the doi-organiser scheduled task
registers it), the field was hidden entirely and users saw no indication that a
DOI exists or is coming.
Restore the previous behaviour where the DOI field is always shown (with an empty
value while registration is pending):
- MetadataUriValuesComponent / ItemPageUriFieldComponent: add an opt-in `doiField`
input. In DOI mode the field wrapper is always rendered (hideIfNoTextContent =
false) and only https://doi.org values are shown as links. When false (default)
the upstream generic behaviour is kept, which also repairs non-DOI URI fields in
the base theme that were unintentionally hidden by the previous global filter.
- datashare untyped-item: opt the DOI field into `[doiField]="true"`.
Test-driven: added specs for the pending (no DOI yet), registered, and empty cases,
plus the default (non-DOI) URI behaviour.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ation
Follow-up to the loading-spinner hardening:
- Lower the request timeout backstop from 30s to 15s on all the hardened loads
(a 30s spinner is too long for an interactive dropdown).
- On a failed OR timed-out controlled-vocabulary / authority lookup, show a
dismissible error toast ("Something went wrong while loading the options.
Please try again.") instead of silently showing an empty "No results found",
so the user knows to retry. Added a shared notifyVocabularyLoadError() helper on
the DsDynamicVocabularyComponent base (via inject()) and wired it into the
scrollable-dropdown and lookup loads. A genuinely empty (succeeded) result is
unchanged -> still "No results found", no error toast.
- Harden dynamic-onebox vocabulary$ (findVocabularyById): getFirstSucceededRemoteDataPayload
-> getFirstCompletedRemoteData, so a failed vocabulary-metadata lookup resolves
to "not hierarchical" (no tree button) instead of leaving isHierarchicalVocabulary$
pending forever. Null-safe guards on result?.hierarchical and vocabulary?.preloadLevel.
tsc --noEmit and eslint pass with 0 errors. Verified in the local repro: on a 500,
the Type dropdown now clears immediately, shows "No results found", AND a red
"Something went wrong ... Please try again." toast appears.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ast behaviour The after clip now shows the updated recovery: on a failed vocabulary load the Type dropdown clears immediately, shows "No results found", and a dismissible "Something went wrong ... Please try again." error toast appears. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…(was 30s) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… wrapper Address review nits on the pending-DOI fix without changing behaviour: - Merge the doiField and default template branches into one ds-metadata-field-wrapper ([hideIfNoTextContent]="!doiField"), removing the duplicated link markup. - Add a `doiValues` getter that filters mdValues to https://doi.org values (restoring the `typeof value === 'string'` guard). In DOI mode the *ngFor and the `!last` separator are computed against this visible-DOI subset, so a trailing non-DOI value can no longer emit a stray separator after the last DOI. - Tighten the registered-case spec to assert the label header, and add a regression spec for multiple DOIs followed by a non-DOI value (only one separator between the DOIs). Verified locally: metadata-uri-values + item-page-uri-field specs 23/23 green, lint clean, build:prod (SSR production build) exits 0. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The DsDynamicVocabularyComponent base now injects NotificationsService (for the "something went wrong" error notification on a failed vocabulary load). Its subclasses' unit tests (scrollable-dropdown, onebox, tag, lookup) did not provide it, so component construction failed with "NullInjectorError: NotificationsService -> Store -> No provider for Store" (NotificationsService is providedIn root and depends on the ngrx Store, which the isolated TestBeds don't set up). Provide the existing NotificationsServiceStub in each of the four specs. Verified locally: those 4 spec files now run 54/54 SUCCESS (were 54 FAILED). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The before/after clips are now hosted on the separate 'pr-repro-media' branch and referenced from this PR's description, so they are no longer part of the code diff. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The before/after clips are now hosted on the separate 'pr-repro-media' branch and referenced from this PR's description, so they are no longer part of the code diff. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…d-coding it The DOI field decides which dc.identifier.uri values are DOIs by matching the DOI resolver base URL. That URL is a backend setting (identifier.doi.resolver), so read it from the REST config endpoint instead of hard-coding "https://doi.org" in the UI. - MetadataUriValuesComponent now fetches identifier.doi.resolver via ConfigurationDataService on init (only in doiField mode) and uses it in doiValues. Falls back to the DSpace default https://doi.org (DOIServiceImpl#RESOLVER_DEFAULT) when the property is not exposed/defined, so it stays correct without any backend change. - Added a spec proving a value matching a custom configured resolver is treated as a DOI, and provided ConfigurationDataService stubs to the dependent specs (item-page-uri-field, publication, untyped-item). Requires the backend to expose identifier.doi.resolver in rest.properties.exposed (separate backend PR); until then the frontend uses the default resolver. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ending
Instead of showing an empty DOI ("Persistent Identifier") field while the DOI is still
queued for registration by the scheduled task, show a "DOI registration in progress"
message. Once registration completes and the resolver value appears in dc.identifier.uri,
the DOI link is shown instead.
- metadata-uri-values: in doiField mode, render the item.page.doi.pending message when
there is no DOI value yet (doiValues is empty).
- add the item.page.doi.pending i18n key to the datashare theme and core en.json5.
- specs: assert the message is shown when pending / no identifier, and NOT shown once a
DOI is present.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
508977c
into
UoEMainLibrary:datashare-UoEMainLibrary-dspace-8_x
5 checks passed
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.
This PR contains the following fixes:
Fix: Show
DOI registration in progresson the Item View when the DOI has not been registered yet.Fix: Propagated the fix from Vanilla. When select options take more than 15 seconds to load, an error message is shown asking the user to try again.