…olumn on the edit-bitstreams table
Source: no single commit - the fork delta is measured against dspace-7.6.5, and the
v9 upgrade took both payload files wholesale from vanilla 9.3, so the fork hunks were
never applied (guard X1 sweep 2026-09-10, card X-02b).
- bitstream.model.ts: SYNCHRONIZED_STORES_NUMBER = 77, @autoserialize storeNumber,
the checksum HALLink and the @link(BITSTREAM_CHECKSUM) follow-link.
- item-bitstreams.service.ts: fifth ResponsiveColumnSizes and the rebalanced widths
(the MAX_PAGE_SIZE half of the same fork hunk had already landed).
- item-edit-bitstream-bundle.component.{ts,html}: the Sync | Checksum column, the four
popover templates, and BitstreamChecksumDataService wired in directly (it is
providedIn:'root' on this base; core.module.ts no longer exists).
v9 adaptations, each deliberate:
- computeChecksum(entry) and isBitstreamSynchronized(entry) take the table row instead of
itemBitstreamsService.getSelectedBitstream(), which returns null on v9 when no row is
selected - the fork form throws a TypeError from any unselected row's button.
- computeChecksum() returns early when the row has no checksum link.
- _links.checksum is optional: the fork's required key breaks the strict object literal in
the vanilla thumbnail.component.spec.ts, and the link is genuinely CLARIN-only.
- @if / @for control flow, Bootstrap 5 utilities (ps-1, ps-2, fw-bold), NgbPopover and
VarDirective added to the standalone imports[].
- [ngTemplateOutletContext] and [popoverContext] pass the row down; the fork sends none, so
its let-entry is always undefined.
- The five column ids/headers are suffixed with sanitizedBundleName, as the card requires -
9-base emits duplicate DOM ids when an item has more than one bundle.
Five new karma tests, each proven load-bearing by a production-code negative control.
en.json5 is untouched: all nine item.edit.bitstreams.checksum.* keys were already there
with no consumer (finding X-03).
Closes card X-02b.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
What
Restores the CLARIN bitstream-checksum column on
Edit item → Bitstreams, which the v9 upgrade dropped by taking both of its payload files wholesale from vanilla 9.3. Sync card X-02b (guard X1 sweep, 2026-09-10).The table gains a fifth
Sync | Checksumcolumn. For every row it shows (a) whether the bitstream is stored in both stores at once (storeNumber === SYNCHRONIZED_STORES_NUMBER, i.e. 77 = local + S3) and (b) on demand, the checksum of the bitstream fetched over_links.checksum, comparing the database checksum against the active store — and, for a synchronized bitstream, against the other store too. The result is a tick or a cross plus a popover with the algorithm and value for DB / active store / sync store.This is a textbook wiring-dropped: everything around the feature survived the upgrade and only the join was lost. The backend already has all of it on
dtq-dev-9-base(BitstreamRest.storeNumber,@LinkRest(name = BitstreamRest.CHECKSUM),BitstreamCheckSumLinkRepository,BitstreamChecksumConverter), the frontend already has the whole data layer (bitstream-checksum-data.service.ts,bitstream-checksum.model.ts,bitstream-checksum.resource.ts— fork-only files that survived and are already v9-adapted), and all nineitem.edit.bitstreams.checksum.*/headers.synchronizedi18n keys are already inen.json5. What was missing was the field on the model and the component that reads it.There is no single source commit to cherry-pick: the fork delta is measured against
dspace-7.6.5, and both payload files were byte-identical withdspace-9.3on this base, so the hunks were re-applied by hand fromorigin/dtq-dev.Changes
core/shared/bitstream.model.tsSYNCHRONIZED_STORES_NUMBER = 77,@autoserialize storeNumber, thechecksumHALLink and the@link(BITSTREAM_CHECKSUM)follow-linkitem-bitstreams/item-bitstreams.service.tsResponsiveColumnSizes(2,2,2,2,2)ingetColumnSizes()and the four existing widths rebalanced to(3,3,3,3,3)/(3,3,3,3,3)/(2,2,2,2,2)/(2,2,2,2,2)so they still sum to 12item-edit-bitstream-bundle.component.tssanitizedBundleName,showChecksumValues,checkSum$,computedChecksum,loading,compareChecksums(),checksumsAreEqual(),isBitstreamSynchronized(),computeChecksum()item-edit-bitstream-bundle.component.html#checksum/#checksumWarning/#computeChecksumInfo/#checksumPopovertemplatesitem-bitstreams.service.stub.ts,…component.spec.tsBitstreamChecksumDataServicespy, and five new testssrc/assets/i18n/*is deliberately untouched —git diff --numstat origin/dtq-dev-9-base HEAD -- src/assets/i18n/is empty. The nine keys were already there with zero consumers (finding X-03); this PR gives them one back.v9 adaptations, and why each one is not a literal copy
BitstreamChecksumDataServiceis injected directly, with no provider registration. The fork registers it insrc/app/core/core.module.ts; that file does not exist on this base (v9 usesprovide-core.ts) and the service is already@Injectable({ providedIn: 'root' }). Porting the registration would have added a duplicate provider.computeChecksum(entry)andisBitstreamSynchronized(entry)take the table row. The fork readsitemBitstreamsService.getSelectedBitstream()?.bitstream?.bitstreamand dereferences_links.checksumstraight away. On v9getSelectedBitstream()returnsnullwhen no row is selected (item-bitstreams.service.ts:191), and the button is in every row, not only the selected one — so the fork form throwsTypeError: Cannot read properties of undefined (reading '_links')on the first click.checksumsAreEqual(checksum, entry)gained the same row argument for the same reason.computeChecksum()returns early when the row has no checksum link, instead of calling the service withundefined._links.checksumis optional. The fork declares it required; on this base that breaks the strict object literal in the vanillathumbnail.component.spec.ts(error TS2741: Property 'checksum' is missing). The link is CLARIN-only and the paired follow-link was already optional, sochecksum?: HALLinkis both correct and confined to this PR's own file — the alternative was editing an unrelated vanilla spec.[ngTemplateOutletContext]="{ entry: entry }"and[popoverContext]="{ entry: entry }". The fork's#checksumand#checksumPopoverdeclarelet-entry="entry"but nothing ever passes a context, so itsentryis alwaysundefined.@if/@forcontrol flow (prefer-control-flowis an error here),*ngVarkept, Bootstrap 5 utilities (pl-1→ps-1,pl-2→ps-2,font-weight-bold→fw-bold), andNgbPopover+VarDirectiveadded to the standaloneimports[]— without them[ngbPopover]and*ngVarare a silent no-op at runtime.headers=are suffixed withsanitizedBundleName. This base emits duplicate DOM ids (name,description,format,actions) once an item has more than one bundle. The card asks for the scheme to be kept because the new column'sheaders=needs it.[queryParams]hunk that FE-28 added to this template is untouched (regression-guarded by an AC grep).Deliberately not ported from the same fork diff, as out of scope for this card: the
dont-break-outspans and thepaginationControlsid changes (a11y themes owned elsewhere), andgetParentHierarchyTitle/getAllParentsRecursive(a different feature entirely).Known fork limitation kept as-is:
checkSum$,computedChecksumandloadingare component-level, not per-row, so computing a checksum switches every row of that bundle into the "computed" state. That is the fork's own design; fixing it is a behaviour change beyond this card.Why
Without the model field the component does not compile (
Property 'storeNumber' does not exist on type 'Bitstream'); without the component the model field is dead code. The backend has servedstoreNumberand/checksumon this base since the v9 upgrade with nothing on the frontend consuming them, and nine translated i18n keys have been sitting unreferenced.Testing
The fork ships zero tests for this feature, and its one spec hunk is six lines of dead DI plumbing that wires the
BitstreamChecksumDataServiceprovider to a different stub (useValue: itemBitstreamsService). All five tests here are new, and each was proven load-bearing by breaking the production code and watching the named test go red:isBitstreamSynchronized()hardcoded totrue2 FAILED, 22 SUCCESScompareChecksums()reduced to a value-only comparison1 FAILED, 23 SUCCESSchecksumsAreEqual()drops the synchronized-store comparison1 FAILED, 23 SUCCESScomputeChecksum()readsgetSelectedBitstream()(the fork form)1 FAILED, 23 SUCCESScomputeChecksum()loses the missing-href guard (the fork form)1 FAILED, 23 SUCCESSThe template itself is not covered by karma — the spec stubs
viewContainerRef.createEmbeddedView, song-template #bundleViewnever renders. Its only real gate is the AOTbuild:prodabove, which also confirmsNgbPopoverandVarDirectiveare genuinely used (an unused standalone import would have raisedNG8113for this component, and none did).Not verified here
AC-X-02b-6is a[live]criterion: it needs the branch merged, an FE deploy to dev-6:8603 and an admin session there to check the tick againststore_numberin the database and the/checksumendpoint. The card stays PARTIAL on that one AC.🤖 Generated with Claude Code