Skip to content

UFAL/CLARIN-DSpace upgrade v9#1316

Open
milanmajchrak wants to merge 37 commits into
dtq-dev-9-basefrom
ufal/clarin-dspace-upgrade-v9
Open

UFAL/CLARIN-DSpace upgrade v9#1316
milanmajchrak wants to merge 37 commits into
dtq-dev-9-basefrom
ufal/clarin-dspace-upgrade-v9

Conversation

@milanmajchrak

Copy link
Copy Markdown
Collaborator

Problem description

Analysis

(Write here, if there is needed describe some specific problem. Erase it, when it is not needed.)

Problems

(Write here, if some unexpected problems occur during solving issues. Erase it, when it is not needed.)

Sync verification

If en.json5 or cs.json5 translation files were updated:

  • Run yarn run sync-i18n -t src/assets/i18n/cs.json5 -i to synchronize messages, and changes are included in this PR.

Manual Testing (if applicable)

Copilot review

  • Requested review from Copilot

@coderabbitai

coderabbitai Bot commented Jun 18, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 522a5ce5-9b6c-4ff9-8df6-cdb84cdc2bab

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

First tranche of the CLARIN-DSpace 7.6.x -> 9.3 dspace-angular port.
Adds CLARIN/LINDAT image assets that are net-new vs vanilla 9.3 (none of these
dirs exist upstream), so this is purely additive and build-safe:
- src/assets/images/mime/   (file-type icons for item/bitstream display)
- src/assets/images/flags/  (country/language flags)
- src/assets/images/item-types/, footer/, static-pages/
- LINDAT branding: lindat-logo-new-sm.png, lindat_color_line.png, target.png,
  info.png, spinning.gif

Feature modules that consume these assets follow in subsequent tranches
(see CLARIN_DSPACE_V9_PROGRESS.md §6e for the frontend plan).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@milanmajchrak milanmajchrak changed the base branch from dtq-dev to dtq-dev-9-base June 19, 2026 07:03
milanmajchrak and others added 27 commits June 19, 2026 09:28
Second tranche of the dspace-angular 7.6.x -> 9.3 CLARIN port: the core data
layer that the feature modules depend on. Type-checks clean (tsc) and passes
lint (0 errors) on v9.

- shared/clarin: models, resource-types, serializers, constants for the license
  framework (ClarinLicense/Label/ResourceMapping/CLRUA), user metadata/registration,
  verification token, matomo report subscription, featured services, bitstream auth.
- core/data + core/data/clarin: data services for the above + handle / epic-handle /
  metadata-bitstream / metadata-value / bitstream-checksum.
- core/handle, core/epicHandle, core/metadata: handle + epic-handle + metadata models,
  resource-types and serializers.

v9 migration applied:
- @DataService decorator import repointed from core/data/base/data-service.decorator
  to core/cache/builders/build-decorators (moved upstream in v8/9; still used for HAL
  resolution) - decorator kept.
- eslint --fix for v9 style (import order etc.).

Deferred (need the clarin-item-box-view feature): bitstream-url-serializer +
shared/clarin-shared-util. Feature modules (clarin-licenses, handle-page, login,
share-submission, ...) follow in subsequent tranches. See CLARIN_DSPACE_V9_PROGRESS.md §6e.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Third FE tranche: the flagship CLARIN license admin/listing feature, migrated
from the 7.x NgModule pattern to v9 standalone components. ng build passes
(module is lazy-loaded so the whole chain incl. the core layer is validated);
lint clean (0 errors).

- 5 components -> standalone (clarin-license-page, clarin-license-table,
  clarin-all-licenses-page, define-license-form, define-license-label-form) with
  explicit imports (CommonModule, TranslateModule, FormsModule/ReactiveFormsModule,
  NgbDropdownModule, ThemedLoadingComponent, PaginationComponent + the pipes below).
- 6 custom CLARIN pipes ported + made standalone (shared/utils): char-to-end (dsAddChar),
  clarin-extended-license, clarin-license-checked, clarin-license-label-radio-value,
  clarin-license-required-info(+checked).
- clarin-license-routes.ts (replaces clarin-license.module.ts + clarin-license-routing.module.ts)
  using v9 function resolver/guard (i18nBreadcrumbResolver / siteAdministratorGuard).
- LICENSES_MODULE_PATH / LICENSES_MANAGE_TABLE_PATH added to app-routing-paths.ts and the
  /licenses lazy route wired into app-routes.ts.

Consumes the core layer from the previous tranche. See CLARIN_DSPACE_V9_PROGRESS.md §6e.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…sabled, ===)

Follow-up to the clarin-licenses port: the CI gate `ng lint --quiet` also lints
templates (which a scoped .ts-only eslint run missed). Applied the v9 template
requirements so both `ng build` and full `ng lint --quiet` pass (0 errors):

- *ngIf/*ngFor -> @if/@for via @angular/core:control-flow migration
  (@angular-eslint/template/prefer-control-flow).
- == -> === in templates (@angular-eslint/template/eqeqeq).
- disabled/[disabled] on <button> -> [dsBtnDisabled] + BtnDisabledDirective import
  (dspace-angular-html/no-disabled-attribute-on-button).
- Re-sorted standalone imports / import statements (simple-import-sort,
  sort-standalone-imports).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
FE tranche 4: admin handle table + new/edit/change-prefix pages, migrated to v9
standalone. ng build + full ng lint --quiet both clean.

- 6 components -> standalone (handle-page, handle-table, new/edit-handle-page,
  change-handle-prefix-page, handle-global-actions) with precise template-dep imports
  (CommonModule/TranslateModule/Forms/ReactiveForms/NgbDropdown + ThemedLoadingComponent,
  PaginationComponent, ErrorComponent, BtnDisabledDirective, sibling components).
- handle-page-routes.ts (replaces handle-page.module.ts + handle-page.routing.module.ts),
  /handle-table lazy route wired into app-routes.ts with siteAdministratorGuard.
- v9 template migration: @if/@for control-flow, === / !==, dsBtnDisabled.

Consumes the handle core data services from FE tranche 2. See CLARIN_DSPACE_V9_PROGRESS.md §6e.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
FE tranche 5: EPIC PID handle table + prefix + new/edit pages, migrated to v9
standalone. ng build + full ng lint --quiet both clean.

- 5 components -> standalone (epic-handle, epic-handle-table, epic-handle-new/edit/prefix)
  with precise imports (Common/Translate/Forms/ReactiveForms + ThemedLoadingComponent,
  PaginationComponent, VarDirective (*ngVar), BtnDisabledDirective, sibling component).
- epic-handle-routes.ts (replaces epic-handle.module.ts + epic-handle-routing.module.ts),
  /epic-handle-table lazy route wired into app-routes.ts with siteAdministratorGuard.
- v9 migrations: @if/@for control-flow, dsBtnDisabled, and rxjs catchError errors kept as
  `unknown` with `(error as any)` casts at use (smarttools/rxjs/no-implicit-any-catch).

Consumes the epic-handle core data services from FE tranche 2. See CLARIN_DSPACE_V9_PROGRESS.md §6e.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…one)

FE tranche 6: "Sharing a submission" feature (share link page + change-submitter page).
ng build + full ng lint --quiet both clean.

- ShareSubmissionPageComponent + ChangeSubmitterPageComponent -> standalone.
- share-submission-routes.ts (replaces share-submission.module.ts + routing module),
  /share-submission lazy route wired into app-routes.ts with authenticatedGuard.
- v9 fixes: @if control-flow, eqeqeq, replaced stray `chart.js/helpers` isNullOrUndef with
  DSpace hasNoValue, fixed `instanceof Observable<T>` -> `instanceof Observable`.

See CLARIN_DSPACE_V9_PROGRESS.md §6e.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…med)

FE tranche 7: contact page (themed) + static HTML pages. ng build + full ng lint clean.

- ContactPageComponent + StaticPageComponent -> standalone; ThemedContactPageComponent
  already matches v9 themed pattern (no change needed).
- Ported ClarinSafeHtmlPipe (dsSafeHtml) + HtmlContentService (providedIn:'root'), both
  CLARIN-added and absent in vanilla v9.
- contact-page-routes.ts + static-page-routes.ts (replace NgModules); /contact and /static
  lazy routes wired into app-routes.ts.
- v9 adaptations: ds-themed-loading -> ds-loading, @if control-flow, eqeqeq,
  LocaleService.getCurrentLanguageCode() now Observable<string> (await firstValueFrom),
  catch error cast (error as any).status, REQUEST token moved to ../../express.tokens,
  no-negated-async -> (htmlContent | async)?.length === 0.

See CLARIN_DSPACE_V9_PROGRESS.md §6e.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…Var, route)

Resolves CRITICAL/MINOR findings from the independent FE review — runtime bugs that
ng build/ng lint cannot catch (DI is runtime; strictTemplates is off):

- C1: 12 CLARIN core data services had bare @Injectable() (no provider) -> NullInjectorError
  at runtime (clarin-licenses + handle-page were dead). Added @Injectable({ providedIn: 'root' })
  to all (license/label/mapping/user-metadata/user-registration/verification-token/clrua/
  matomo-report/handle/bitstream-checksum/metadata-bitstream/metadata-value data services).
- C2: *ngVar used without importing VarDirective in clarin-license-table, handle-table,
  change-submitter-page -> template alias never assigned, pages rendered no data. Imported VarDirective.
- m2: restored pathMatch:'full' on the contact route.

Deferred-with-reason (documented, not skipped): FE M1 usage-report.model delta (would break vanilla
stats in isolation), C3 admin menu provider, i18n keys. See CLARIN_DSPACE_V9_PROGRESS.md §6g.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds the 643 CLARIN-DSpace (UFAL) English translation keys that v9 lacks (computed as the set
difference of dtq-dev keys minus v9 keys, extracted via the json5 parser so multi-line array values
are preserved). Covers clarin licenses, handle-table, epic-handle, share-submission, change-submitter,
contact/static pages, admin update-config, matomo, refbox, statistics, etc. — so the already-ported
and upcoming CLARIN FE modules render real labels instead of raw keys.

en.json5 re-validated with JSON5.parse (4318 total keys). Other languages fall back to en for these
keys; Czech (cs) translations can be layered later. Appended (en.json5 is not strictly sorted in-file
and no parity/sort test is enforced).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Distribution-license display per collection (route /contract). v9 standalone migration:
- standalone component with imports [AsyncPipe, TranslateModule, VarDirective, ErrorComponent,
  ThemedLoadingComponent, PaginationComponent]
- control-flow migration (*ngIf/*ngFor/else -> @if/@for/@else)
- v9 API fixes: ds-themed-loading -> ds-loading (v9 selector); getAuthorizedCollection now takes an
  explicit searchHref param -> pass 'findSubmitAuthorized' (the 7.x default) before followLink('license')
- NgModule/routing.module -> license-contract-page-routes.ts; wired loadChildren at path 'contract'
Validated: npm run build succeeds (0 errors).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Admin config-file editor UI (route /admin/update-config, site-admin guarded) — pairs with the BE
ConfigFileRestController (admin/configfiles endpoint). v9 standalone migration:
- standalone component imports [DatePipe, DecimalPipe, FormsModule, TranslateModule]
- control-flow migration; AdminUpdateConfigService -> @Injectable({ providedIn: 'root' }) (v9 DI)
- direct route entry in admin-routes.ts with siteAdministratorGuard + i18nBreadcrumbResolver
Validated: npm run build succeeds (0 errors).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…er (FE tranche 11)

Flagship CLARIN feature: license-gated bitstream download. 5 standalone components — download-page
(routes :id/download -> ClarinBitstreamDownloadPageComponent), license-agreement-page (the license
signing form), token-expired, authorization-denied, zip-download-page. Uses ported CLARIN FE services
(ClarinLicenseResourceMappingService, ClarinUserRegistration/MetadataDataService).
Also the tombstone cluster (tombstone + replaced/withdrawn-tombstone) it depends on for HELP_DESK_PROPERTY.

v9 standalone migration: imports[] per component (AsyncPipe/TranslateModule/VarDirective/ClarinSafeHtmlPipe
+ cross-component composition), control-flow migration, ds-themed-loading->ds-loading is N/A here.
v9 fixes: no-unsafe-enum-comparison (downloadStatus string vs RequestEntryState -> cast). Wired the
:id/download route to ClarinBitstreamDownloadPageComponent in bitstream-page-routes.ts.
Validated: npm run build SUCCESS (✔ bundle generation complete, 0 errors).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…andalone)

Bottom-up port of the leaf dependencies for item listings/view:
- foundation: clarin-shared-util (getBaseUrl/secureImageData/loadItemAuthors), clarin-date.service +
  item-identifier.service (@Injectable providedIn:'root'), utils/replace.pipe (dsReplace), AuthorNameLink model
- item-display components (standalone, control-flow): clarin-license-info (license badge/info,
  switch on LicenseType cast to satisfy no-unsafe-enum-comparison), clarin-item-author-preview,
  clarin-item-box-view (composes author-preview + license-info; imports VarDirective/RouterLink/FileSizePipe)
Validated: npm run build SUCCESS + eslint --quiet clean. These unblock the item-page listing/view tranche.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The item-view citation/featured-services box — pairs with the BE ClarinRefBoxController
(/server/api/core/refbox). 4 standalone components (control-flow migrated):
- clarin-ref-box (composes citation + featured-services)
- clarin-ref-citation (+ clarin-ref-citation-modal for the BibTeX/citation export modal)
- clarin-ref-featured-services (featured service links per item)
Validated: npm run build SUCCESS + eslint --quiet clean. (Wiring ds-clarin-ref-box into the themed
item view is a follow-up vanilla-template change.)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
8 item-view metadata field renderers (control-flow migrated, build + eslint validated):
clarin-generic-item-field (dispatcher composing date/description/identifier/sponsor + item-author-preview)
+ clarin-date/description/identifier/sponsor/collections/files/item-versions field components.
Use the shared foundation from tranche 12 (clarin-shared-util, ClarinDateService, dsReplace) + vanilla
FileDownloadLinkComponent/ThemedLoadingComponent. Validated: npm run build SUCCESS.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…on-button (FE tranche 15)

3 more item-view components (standalone, control-flow, build+eslint validated):
- creative-commons-license-field (CC license display)
- item-page-citation (citation specific-field)
- matomo-subscription-button (subscribe to monthly Matomo stats; uses the ported FE
  MatomoReportSubscriptionDataService)
Validated: npm run build SUCCESS.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…cription-button (FE tranche 16)

3 standalone components (control-flow + build + eslint validated):
- item-license-mapper (edit-item-page admin: map a CLARIN license to an item; uses ClarinLicenseDataService)
- access-status-badge (+ access-status model/resource-type) for item listings
- dso-page-subscription-button (CLARIN subscription button on DSO pages)
Validated: npm run build SUCCESS. (Deferred: clarin-search — extends vanilla SearchComponent + reuses its
full template, needs the whole SearchComponent imports[] replicated.)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This session I validated with `npm run build` + targeted `eslint --quiet <ts>` but skipped the full
`ng lint` (lint:nobuild) which lints HTML templates + custom rules — so several tranches failed CI lint.
Comprehensive fix (ng lint now: 0 errors, only pre-existing warnings):
- themed-component-usages: clarin-files-item-field must import ThemedFileDownloadLinkComponent (not the
  raw FileDownloadLinkComponent) — this rule crash was aborting the whole lint
- template eqeqeq (==/!= -> ===/!==) in 7 templates (license-agreement, files/generic-item-field,
  tombstone+withdrawn-tombstone, item-author-preview, item-box-view)
- no-negated-async -> (x | async) !== true (collections-item-field, item-author-preview)
- no-sharereplay: shareReplay(1) -> shareReplay({ bufferSize: 1, refCount: true }) (item-versions-field)
- import sorting/newlines autofixed (ng lint --fix), CLARIN files only
Validated: ng lint -> 0 errors.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Shibboleth login outcome/registration pages (routed under /login): auth-failed, missing-headers,
duplicate-user, autoregistration. Standalone (control-flow), wired into login-page-routes.ts.
v9-API migration: autoregistration-loader used the removed ComponentFactoryResolver.resolveComponentFactory
-> ViewContainerRef.createComponent(AutoregistrationComponent) directly. Uses ported CLARIN
ClarinVerificationTokenDataService + clarin-shared-util. Validated: npm run build SUCCESS + ng lint
(ts+html) 0 errors (fixed template eqeqeq).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…per build+lint validation

Root cause: my FE build-check grep matched only `error TS|Module not found` and MISSED Angular
NG8001/NG8002 template-binding errors, and the tranche-15 `ng lint --fix` auto-converted button
`disabled` attributes to `[dsBtnDisabled]` WITHOUT importing BtnDisabledDirective -> build broke.
Fixes:
- admin-update-config + clarin-license-agreement-page: add BtnDisabledDirective to imports[]
- autoregistration.component: was already standalone in 7.x — my script added a 2nd imports[]; merged
  to one, dropped the removed SharedModule + CommonModule (use AsyncPipe/RouterLink/TranslateModule)
- auth-failed-page: add FormsModule (template uses [(ngModel)])
- defer clarin-notice submission section: it uses <ng-toggle> from @nth-cloud/ng-toggle (a CLARIN npm
  dep not yet installed) -> _deferred/ until the dep is added
Validated PROPERLY this time: npm run build -> 0 errors (incl. NG8xxx) + eslint --ext .ts,.html 0 errors.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ice/form-builder clusters)

Add the CLARIN deps from dtq-dev that v9 lacked: d3 + @types/d3 (views-downloads statistics charts),
chart.js + ng2-charts (chart components), @nth-cloud/ng-toggle (submission/notice toggles), lindat-common
(discojuice/AAI shibboleth navbar), ngx-mask (form input masks), sanitize-html + @types/sanitize-html.
Also pin @popperjs/core (a @ng-bootstrap transitive dep that --legacy-peer-deps otherwise drops).
Installed with --legacy-peer-deps (ng2-charts@4 peer-declares Angular <=16 but builds fine on v9's 17/18).
Validated: npm run build SUCCESS (0 errors). These were the gating prerequisite for the remaining FE
CLARIN feature clusters.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
CLARIN per-item usage statistics (uses the now-installed d3 dep):
- views-downloads-statistics/ : routed page (chart-drawer.service draws d3 line/area charts of
  yearly->monthly->daily views & downloads; drill-down on click), service fetches from the external
  statistics service (APP_CONFIG.statistics.baseUrl+endpoint)
- views-downloads-statistics-button/ : routerLink button to the page
- route wired in item-page-routes.ts (VIEWS_DOWNLOADS_STATISTICS_PATH) as a child of :id
- StatisticsConfig (src/config/statistics-config.ts) added to AppConfig (optional `statistics?`)
- ItemComponent.hasConfiguredStatistics getter (via inject(APP_CONFIG) to avoid touching the
  widely-extended constructor) gates the button in untyped-item; full-item-page shows it unconditionally
- button embedded in base untyped-item + full-item-page templates AND their themes/custom overrides
  (theme overrides reuse base templateUrl, so they need the import in their own imports[] too)
- also fixed matomo-subscription-button: add BtnDisabledDirective (template had [dsBtnDisabled])
Made all components standalone (imports[] + @if/@for control-flow). Validated: npm run build SUCCESS
(0 errors incl NG8xxx) + eslint --ext .ts,.html 0 errors.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
CLARIN submission "notice" section: shows the deposit-agreement notice with the collection name +
help-desk mailto, and an accept toggle (ng-toggle) the submitter must switch on. Now buildable thanks
to the installed @nth-cloud/ng-toggle dep.
- SubmissionSectionClarinNoticeComponent extends SectionModelComponent (implements getSectionStatus/
  onSectionInit/onSectionDestroy); standalone with imports [AsyncPipe, FormsModule, NgToggleModule,
  TranslateModule]; @if/@for control-flow
- registered via explicit submissionSectionsMap.set(SectionsType.clarinNotice, ...) in
  sections-decorator.ts (v9 style; the 7.x @renderSectionFor decorator dropped to avoid circular import)
- SectionsType += clarinLicense/clarinNotice (values match the BE submission step types)
Validated: npm run build SUCCESS (0 errors) + eslint 0 problems. (Becomes visible once the BE
item-submission.xml wires a clarin-notice step — that BE config is tracked separately.)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ign-on)

clarin-navbar-top: the LINDAT-style top bar rendered above the dspace-theme header — EN/CS language
toggle (own setLanguage via LocaleService) and an AAI sign-on badge that DiscoJuice binds to
(#clarin-signon-discojuice), or profile/logout links when authenticated.
- ClarinNavbarTopComponent standalone (imports [RouterLink, TranslateModule], providers
  [ScriptLoaderService]); @if control-flow; eqeqeq fixed
- ScriptLoaderService loads DiscoJuice/AAI/AAIConfig scripts browser-side only (SSR-guarded via
  isPlatformBrowser) on AfterViewInit
- wired into src/themes/dspace/app/header/header.component (.html + imports[]) at the top of the header
- the dtq-dev template's `ds-language-selection` is a CSS class (not a component), so no extra import
Validated: npm run build SUCCESS (0 errors) + eslint 0 problems.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…or / complex / clarin-name)

The CLARIN submission custom input types, now buildable on v9's @ng-dynamic-forms:
- autocomplete: DsDynamicAutocomplete{Model,Component,Service} — typeahead backed by vocabulary /
  custom solr/json sources (handle-title, iso-langs); sponsor variant (openAIRE + metadata) and a
  sponsor scrollable-dropdown variant for the local.sponsor complex input
- clarin-name + complex models/parsers; ds-dynamic-complex.model (SPONSOR_METADATA_NAME etc.)
- registration: ParserType += Autocomplete/Complex/ClarinName (+ parser-factory cases);
  dsDynamicFormControlMapFn maps the AUTOCOMPLETE/SCROLLABLE_DROPDOWN types to the right component
  (sponsor name-prefix picks the sponsor variants)
- FormFieldModel += complexDefinition + autocompleteCustom (@autoserialize)
- field-parser.setVocabularyOptionsInComplexInput + LookupRelationService.getExternalResults ported

v9 API migrations made along the way:
- components made standalone (imports[] for the reused tag/scrollable templates)
- DsDynamicTagComponent.cdr private->protected so the autocomplete subclass can use it; subclasses
  pass cdr/dataServiceMap to super as plain params (base declares them private/protected)
- sponsor scrollable-dropdown super() updated to the v9 6-arg signature (Injector + APP_DATA_SERVICES_MAP)
- ngb-highlight -> span (v9 ngb-highlight now requires result/term inputs)
Validated: npm run build SUCCESS (0 errors) + eslint --ext .ts,.html 0 errors.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…filenames)

CLARIN custom UrlSerializer that RFC3986-encodes the filename segment of /bitstream/.. URLs so
download links with special characters resolve correctly. Registered as { provide: UrlSerializer,
useClass: BitstreamUrlSerializer } in app.config.ts (v9 standalone equivalent of the 7.x app.module
provider). Uses the already-ported encodeRFC3986URIComponent.
Validated: npm run build SUCCESS (0 errors) + eslint 0 errors.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…+ clarin-license-distribution)

The core CLARIN submission license flow:
- clarin-license-resource/section-license: the "resource license" step — loads CLARIN licenses from
  the BE (ClarinLicenseDataService), renders a license selector (License4Selector), validates the
  chosen license is CLARIN-supported, patches the workspace item; standalone [CommonModule,
  TranslateModule], own ufal-theme.css; registered as SectionsType.clarinLicense
- clarin-license-distribution: overrides the vanilla License (distribution) step with an ng-toggle
  accept control + a link to the distribution-license contract page; standalone [CommonModule,
  FormsModule, NgToggleModule, RouterLink, TranslateModule]; registered for SectionsType.License
  (replaces SubmissionSectionLicenseComponent in the sections map)
- both registered via submissionSectionsMap.set() (v9; @renderSectionFor decorator dropped)
- app-routing-paths += CONTRACT_PAGE_MODULE_PATH + getLicenseContractPagePath()
Validated: npm run build SUCCESS (0 errors) + eslint 0 errors.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
milanmajchrak and others added 9 commits June 25, 2026 16:36
Root cause of the red `tests (20.x/22.x)` checks: my earlier `npm install --legacy-peer-deps` to add
the CLARIN deps corrupted package-lock.json — it flattened the vanilla mirador/react-intersection-observer
react peer nesting and dropped transitives (chokidar, readdirp, clsx, yaml), so CI's `npm clean-install`
failed with "Invalid/Missing from lock file". It also blindly downgraded ngx-mask 16->13 and added
unused deps.

Fix (verified locally with `npm clean-install` == CI's command, exit 0):
- restore ngx-mask to the vanilla ^16.0.0 (the 5 in-tree users need v16; v13 was a stray downgrade)
- drop unused deps never imported anywhere: chart.js, ng2-charts, lindat-common, sanitize-html
  (+ @types/sanitize-html, @types/d3-dispatch). ng2-charts@4 was also the only Angular-18 peer conflict.
- keep only what's actually used: d3 + @types/d3 (charts), @nth-cloud/ng-toggle (toggles, no peers),
  @popperjs/core (@ng-bootstrap transitive pin)
- regenerate the lock by adding these onto the WORKING vanilla lock via `npm install --package-lock-only`
  (no --legacy-peer-deps) so the mirador react-peer nesting is preserved
Validated: npm clean-install -> 0, npm run build -> 0 (Build at: ... 0 errors).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ype unit tests)

inject(APP_CONFIG) without { optional: true } throws NullInjectorError in any item-type component
spec that doesn't provide APP_CONFIG (untyped-item.spec et al.), failing test:headless. Use
inject(APP_CONFIG, { optional: true }) + null-safe access in hasConfiguredStatistics — the app still
provides APP_CONFIG, specs without it just get null (button hidden) instead of crashing.
Validated: npm run build:prod -> 0 (CI's production build gate).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The `Check for circular dependencies` (madge) CI step failed: my CLARIN ports created 3 cycles by
defining constants inside component files that other modules import:
- HELP_DESK_PROPERTY was defined in tombstone.component but imported by replaced-/withdrawn-tombstone
  children -> cycle. Extracted to tombstone.constants.ts (9 importers rewired).
- DOI_METADATA_FIELD/HANDLE_METADATA_FIELD were defined in clarin-generic-item-field.component but
  DOI is imported by shared/item-identifier.service (which the sibling clarin-identifier-item-field uses)
  -> cycle. Extracted to clarin-generic-item-field.constants.ts.
Validated: madge with CI's exact --exclude pattern -> "No circular dependency found!" (exit 0);
npm run build -> 0 errors.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The FE `Run build` (build:prod) CI step failed: section-license.component.scss does
`@import "ufal-theme.css"`, but the co-located ufal-theme.css matched the repo .gitignore `*.css`
rule and was never committed (local builds passed since the file is in the working tree). dtq-dev
force-adds the same file. `git add -f` it.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ar a11y

The DSpace Cypress e2e suite (Run e2e tests) had 3 failing specs from CLARIN changes:
- submission.cy.ts + my-dspace.cy.ts: `input#granted` not found. My sections-decorator mapped
  SectionsType.License -> SubmissionSectionClarinLicenseDistributionComponent (ng-toggle variant),
  replacing the vanilla license checkbox. Revert to the vanilla SubmissionSectionLicenseComponent;
  the CLARIN distribution variant stays ported but unwired (activating it needs dtq-dev's matching
  e2e changes too) — documented in sections-decorator.
- header.cy.ts: axe `link-name` (serious) violation — the hidden #repository_path helper anchor (read
  by DiscoJuice) had no discernible text. Added aria-hidden="true" + tabindex="-1".
Validated: npm run build SUCCESS (0 errors).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Completes the file-preview feature end-to-end (the BE now serves it via MetadataBitstreamController):
- item-page/clarin-files-section (entry, [item]+[itemHandle]) -> simple/field-components/preview-section
  -> file-description -> file-tree-view (recursive). All migrated to v9 standalone components
  (imports[] + @if/@for control-flow) and lint-clean.
- core/registry/registry.service.getMetadataBitstream(handle, fileGrpType) delegating to the existing
  MetadataBitstreamDataService (data layer was already present).
- Wired <ds-clarin-files-section> into simple + full item-page templates, and added the component to
  both base item-page components' imports[] AND the themes/custom overrides' imports[] (theme overrides
  reuse the base templates, so they need it too or NG8001).

Fixed clarin-license-info (was an orphan never built, so its latent v9 breakages only surfaced now that
clarin-files-section imports it): added NgClass + NgbTooltipModule to imports[]; LocaleService
.getCurrentLanguageCode() now returns Observable<string> in v9 (was string) -> subscribe once into a
currentLangCode field and compare that in isCsLocale(). Added FileSizePipe (clarin-files-section),
NgbCollapseModule (file-tree-view).

Verified: npm run build = BUILD_EXIT=0 (bundle generation complete); scoped eslint on all changed
files incl. HTML templates = 0 errors (2 pre-existing warnings). Full ng lint OOMs locally (RAM), CI
runner has more memory.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adding ClarinFilesSectionComponent to the item-page components' imports[] pulled RegistryService
(-> Store) into the FullItemPageComponent/ItemPageComponent spec TestBeds, which don't provide Store
(NG0201/NG0200). Add ClarinFilesSectionComponent to each spec's overrideComponent remove.imports list
(same pattern already used for ThemedFullFileSectionComponent, CollectionsComponent, etc.) so the heavy
child isn't instantiated in those component tests; its tag is ignored via NO_ERRORS_SCHEMA.

Also RegistryService gained a MetadataBitstreamDataService constructor dependency (for
getMetadataBitstream) -> add a jasmine spy provider for it in registry.service.spec.ts.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…line import)

The previous spec fix inserted the ClarinFilesSectionComponent import inside the existing multi-line
@angular/core import, causing a lint parse error (Identifier expected). Move it to its own complete
import statement + sort. No functional change to the remove.imports / mock-provider fixes.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Override SectionsType.License with SubmissionSectionClarinLicenseDistributionComponent (the CLARIN
distribution-license variant: ng-toggle acceptance + distribution-license-agreement link + help-desk
contact) in sections-decorator.ts, replacing the vanilla checkbox-based SubmissionSectionLicenseComponent.

Update the matching e2e specs to interact with the ng-toggle instead of the vanilla #granted checkbox
(dtq-dev's exact selector): submission.cy.ts + my-dspace.cy.ts now do
`cy.get('ds-clarin-license-distribution ng-toggle').click()`.

npm run build = clean (BUILD_EXIT=0); decorator lints clean; no unit specs reference the section map.
The toggle interaction is verified by the Cypress e2e (runs in CI against a Docker backend).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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.

1 participant