Commit 508977c
UoE/WP2-2026-07-09 bugfixes (#6)
* feat: show file checksum instead of format in full item view
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>
* refactor: guard checksum display and show value only
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>
* refactor: align Bitstream checkSum with upstream ChecksumInfo
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>
* revert: drop non-en filesection.checksum i18n key
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>
* refactor: drop redundant optional chaining on checkSum
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>
* fix: changed - File checksum: - to - Checksum: -
* fix: added checksum algorithm (same style as upstream)
* Fix submission stuck on "Saving..." by serializing save effects (switchMap -> 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>
* Harden submission form/vocabulary loading against permanent stuck spinners
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>
* docs(repro): add before/after reproduction of the dropdown loading hang
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>
* docs(repro): add before/after reproduction of the stuck "Saving..." hang
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>
* docs(repro): add never-responding-backend (timeout backstop) before/after
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>
* fix(item-page): show DOI field on simple item view while DOI registration 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>
* Reduce vocab-load timeout to 15s + show a user-friendly error notification
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>
* docs(repro): refresh dropdown "after" clip to show the 15s + error-toast 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>
* docs(repro): refresh never-responding after clip for the 15s timeout (was 30s)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* refactor(item-page): collapse DOI/default URI rendering into a single 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>
* test: provide NotificationsService stub in vocabulary component specs
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>
* chore: remove reproduction media from the code branch
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>
* chore: remove reproduction media from the code branch
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>
* feat(item-page): load DOI resolver from backend config instead of hard-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>
* feat(item-page): show "DOI registration in progress" while a DOI is pending
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>
---------
Co-authored-by: Juraj Roka <95219754+jr-rk@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: milanmajchrak <minptai7@gmail.com>1 parent 0817ead commit 508977c
30 files changed
Lines changed: 512 additions & 96 deletions
File tree
- src
- app
- item-page
- field-components/metadata-uri-values
- full/field-components/file-section
- simple
- field-components/specific-field/uri
- item-types
- publication
- untyped-item
- submission
- form/collection
- objects
- sections
- cc-license
- form
- assets/i18n
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
21 | 21 | | |
22 | 22 | | |
23 | 23 | | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
24 | 29 | | |
25 | 30 | | |
26 | 31 | | |
| |||
38 | 43 | | |
39 | 44 | | |
40 | 45 | | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
41 | 52 | | |
42 | 53 | | |
43 | 54 | | |
| |||
Lines changed: 18 additions & 13 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | | - | |
3 | | - | |
4 | | - | |
5 | | - | |
6 | | - | |
7 | | - | |
8 | | - | |
9 | | - | |
10 | | - | |
11 | | - | |
12 | | - | |
13 | | - | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
14 | 19 | | |
15 | | - | |
| 20 | + | |
Lines changed: 155 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
16 | 16 | | |
17 | 17 | | |
18 | 18 | | |
| 19 | + | |
| 20 | + | |
19 | 21 | | |
20 | 22 | | |
21 | 23 | | |
| 24 | + | |
22 | 25 | | |
23 | 26 | | |
24 | 27 | | |
| |||
38 | 41 | | |
39 | 42 | | |
40 | 43 | | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
41 | 53 | | |
42 | 54 | | |
| 55 | + | |
43 | 56 | | |
44 | 57 | | |
45 | 58 | | |
| |||
49 | 62 | | |
50 | 63 | | |
51 | 64 | | |
| 65 | + | |
52 | 66 | | |
53 | 67 | | |
54 | 68 | | |
| |||
98 | 112 | | |
99 | 113 | | |
100 | 114 | | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
| 186 | + | |
| 187 | + | |
| 188 | + | |
| 189 | + | |
| 190 | + | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
| 196 | + | |
| 197 | + | |
| 198 | + | |
| 199 | + | |
| 200 | + | |
| 201 | + | |
| 202 | + | |
| 203 | + | |
| 204 | + | |
| 205 | + | |
| 206 | + | |
| 207 | + | |
| 208 | + | |
| 209 | + | |
| 210 | + | |
| 211 | + | |
| 212 | + | |
| 213 | + | |
| 214 | + | |
| 215 | + | |
| 216 | + | |
| 217 | + | |
| 218 | + | |
| 219 | + | |
| 220 | + | |
| 221 | + | |
| 222 | + | |
| 223 | + | |
| 224 | + | |
| 225 | + | |
| 226 | + | |
| 227 | + | |
| 228 | + | |
| 229 | + | |
| 230 | + | |
| 231 | + | |
| 232 | + | |
| 233 | + | |
| 234 | + | |
| 235 | + | |
| 236 | + | |
| 237 | + | |
| 238 | + | |
| 239 | + | |
| 240 | + | |
| 241 | + | |
| 242 | + | |
| 243 | + | |
| 244 | + | |
| 245 | + | |
| 246 | + | |
| 247 | + | |
| 248 | + | |
| 249 | + | |
| 250 | + | |
| 251 | + | |
| 252 | + | |
| 253 | + | |
| 254 | + | |
| 255 | + | |
101 | 256 | | |
102 | 257 | | |
103 | 258 | | |
| |||
Lines changed: 71 additions & 4 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
3 | 3 | | |
4 | 4 | | |
5 | 5 | | |
| 6 | + | |
6 | 7 | | |
| 8 | + | |
7 | 9 | | |
| 10 | + | |
8 | 11 | | |
9 | 12 | | |
10 | 13 | | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
11 | 19 | | |
| 20 | + | |
| 21 | + | |
12 | 22 | | |
13 | 23 | | |
14 | 24 | | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
15 | 38 | | |
16 | 39 | | |
17 | 40 | | |
| |||
31 | 54 | | |
32 | 55 | | |
33 | 56 | | |
34 | | - | |
| 57 | + | |
35 | 58 | | |
36 | 59 | | |
37 | 60 | | |
| |||
55 | 78 | | |
56 | 79 | | |
57 | 80 | | |
58 | | - | |
59 | | - | |
60 | | - | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
61 | 128 | | |
62 | 129 | | |
63 | 130 | | |
Lines changed: 8 additions & 4 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
23 | 23 | | |
24 | 24 | | |
25 | 25 | | |
26 | | - | |
27 | | - | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
28 | 30 | | |
29 | 31 | | |
30 | 32 | | |
| |||
64 | 66 | | |
65 | 67 | | |
66 | 68 | | |
67 | | - | |
68 | | - | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
69 | 73 | | |
70 | 74 | | |
71 | 75 | | |
| |||
Lines changed: 1 addition & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | | - | |
| 2 | + | |
3 | 3 | | |
0 commit comments