Skip to content

CLARIN-DSpace v9/Port #1269 (Add bitstream from URL on MyDSpace) to the v9 base - #1507

Merged
milanmajchrak merged 1 commit into
dtq-dev-9-basefrom
ufal/port-1269-9-base
Sep 10, 2026
Merged

CLARIN-DSpace v9/Port #1269 (Add bitstream from URL on MyDSpace) to the v9 base#1507
milanmajchrak merged 1 commit into
dtq-dev-9-basefrom
ufal/port-1269-9-base

Conversation

@milanmajchrak

Copy link
Copy Markdown
Collaborator

What

Ports dataquest-dev/dspace-angular #1269 (1c285b4a6b, "UFAL/[Port to dtq-dev] Add 'Add URL
bitstream' feature to workspace items") to dtq-dev-9-base. Sync card FE-27 (tranche T4).

An editable workspace item in /mydspace gains an "Add bitstream from URL" action (link icon +
tooltip), shown when the user can edit the item and the file-downloader script exists and is
executable for them. It opens a modal with a required URL and an optional bitstream name, invokes
the script with -u <url> -w <workspaceitem id> (plus -n <name> only when a name was given),
notifies, and navigates to /processes/<id>.

Changes

File Change
shared/mydspace-actions/workspaceitem/workspaceitem-actions.component.ts FILE_DOWNLOADER_SCRIPT_NAME, canUseFileDownloader$, processingAddFromUrl$, bitstreamFromUrl, bitstreamName, openAddBitstreamFromUrlModal(), addBitstreamFromUrl(); ScriptDataService injected
…workspaceitem-actions.component.html the action button + the #addBitstreamFromUrlModal template
…workspaceitem-actions.component.spec.ts 8 → 13 it(), ScriptDataService spy
assets/i18n/en.json5, cs.json5 the 9 submission.workflow.generic.add-url-bitstream* keys

Front-end only — the backend half is already on dtq-dev-9-base:

$ git -C DSpace grep -n 'file-downloader' origin/dtq-dev-9-base -- dspace/config/spring/rest/scripts.xml
:82:    <bean id="file-downloader" class="org.dspace.administer.FileDownloaderConfiguration" primary="true">
$ git -C DSpace diff --stat origin/dtq-dev origin/dtq-dev-9-base -- '*FileDownloader.java' '*FileDownloaderConfiguration.java'
(empty — byte-identical)

(The July audit that reported the script beans as missing is stale.)

Why

The feature is entirely absent on the v9 base — not "present by name with the body gone", genuinely
absent:

$ git grep -c "add-url\|url-bitstream\|file-downloader\|ScriptDataService" origin/dtq-dev-9-base -- src/app/shared/mydspace-actions/workspaceitem/
(no output, exit 1)
$ git grep -c "add-url-bitstream" origin/dtq-dev-9-base -- src/assets/i18n/en.json5 src/assets/i18n/cs.json5
(no output, exit 1)

v9 adaptations (translate, not transplant)

The 9-base pre-image is not vanilla — it already carries the CLARIN share-submission action — so
this is a partial-port file, and each hunk was re-derived against the real target:

  • standalone component: FormsModule (for [(ngModel)]) and BtnDisabledDirective added to
    imports[]; 7.x reached both through SharedModule, which does not exist on v9.
  • [disabled][dsBtnDisabled] on the modal's Add button —
    dspace-angular-html/no-disabled-attribute-on-button is an eslint error on 9-base
    (.eslintrc.json:345), and the directive is the accessible replacement (it sets aria-disabled
    and swallows the click rather than removing the button from the a11y tree).
  • class="close" + &times;class="btn-close" (Bootstrap 5) — identical to the sibling
    discard modal already in this template.
  • form-groupmb-3 (Bootstrap 5), ×2.
  • every *ngIf@if, matching the rest of the file after the v9 control-flow migration.
  • getProcessDetailRoute(String(rd.payload.processId))Process.processId is declared
    string on both branches, so nothing fails to compile without String(); the reason is runtime:
    the REST payload delivers a JSON number, which is exactly why the source's own spec fixtures are
    { processId: 202 }. String() keeps the produced route stable either way.
  • void this.router.navigateByUrl(...) — the neighbouring shareSubmission() on 9-base already
    writes void this.router.navigate(...); without void this port would add a new
    no-floating-promises warning (measured: 7 warnings without it, 6 with — and those 6 are all
    pre-existing).
  • spec on the existing 9-base standalone TestBed plus a ScriptDataService spy; of instead of
    of as observableOf; trailing commas where 7.x omitted them (comma-dangle is an error here).
  • en.json5: the 9 keys go in the source's relative position (right after
    submission.workflow.generic.share-submission.tooltip) but without blank lines between them,
    matching the compact style of the CLARIN block they land in — 9 lines rather than the source's 18.
    cs.json5 keeps the // "<key>": "<EN>" convention and is +27, exactly as in the source.

Hunk-level parity was checked line by line: after normalising whitespace, every added line in
en.json5 and cs.json5 is identical to the source's, and the only differences in the other three
files are the adaptations listed above.

Testing

$ npm run test:headless -- --include='src/app/shared/mydspace-actions/workspaceitem/workspaceitem-actions.component.spec.ts' --code-coverage=false
13 tests completed
TOTAL: 13 SUCCESS

$ npx ng lint --lint-file-patterns 'src/app/shared/mydspace-actions/workspaceitem/**/*.{ts,html}'
6 problems (0 errors, 6 warnings)    # all pre-existing (4 no-floating-promises + 1 no-deprecated in
                                     # the old tests, 1 no-floating-promises in confirmDiscard)

$ npx madge --exclude '(bitstream|bundle|collection|config-submission-form|eperson|item|version)\.model\.ts$' --circular --extensions ts ./
Processed 3356 files — No circular dependency found!

$ NODE_OPTIONS=--max-old-space-size=4096 npm run build:prod
EXIT=0     # grep 'error TS|Module not found|NG[0-9]{4}|Error:' -> 8 hits, all the same 4 pre-existing
           # NG8113 warnings (once per bundle) in files this PR does not touch

Negative control — both mutations revert production code only; the spec was never touched:

  • delete the whole add_url_bitstream button block from the template and make
    addBitstreamFromUrl an early-return no-op → 4 FAILED, 9 SUCCESS
    (should display add URL bitstream button when script is executable,
    should invoke file-downloader with -u and -w and optional -n,
    should navigate to process detail and close modal on add from URL success,
    should show error notification on add from URL failure);
  • drop canUseFileDownloader$ from the button's @if guard → 1 FAILED, 12 SUCCESS
    (should not display add URL bitstream button when script is not executable).

All five new cases fail under one of the two, so none is vacuous — worth stating for the second one,
whose expect(btn).toBeNull() shape is the same one that produced a vacuous test elsewhere in this
sync.

Manual verification on dev-6 is scenario LINDAT-123; not run here — this branch is not deployed,
and the authenticated system/scripts/file-downloader probe needs the admin secret
(anonymously it correctly returns 401).

Source: 1c285b4a6b (dtq-dev PR #1269, itself a port of ufal/dspace-angular#110).
Sync card: FE-27.

🤖 Generated with Claude Code

… workspace items

An editable workspace item in /mydspace gains an "Add bitstream from URL" action
(link icon + tooltip), shown when the user can edit the item AND the
`file-downloader` script exists and is executable for them. It opens a modal
with a required URL and an optional bitstream name, invokes the script with
`-u <url> -w <workspaceitem id>` (plus `-n <name>` only when a name was given),
notifies, and navigates to `/processes/<id>`.

The backend half is already on 9-base: `dspace/config/spring/rest/scripts.xml`
declares the `file-downloader` bean and `FileDownloader.java` is byte-identical
with dtq-dev, so this is a front-end-only port.

v9 adaptations against the 9-base pre-image (which is NOT vanilla - it already
carries the CLARIN share-submission action, so this is a partial-port file, not
a vanilla-wholesale one):

* standalone component: `FormsModule` (for `[(ngModel)]`) and
  `BtnDisabledDirective` added to `imports[]`.
* `[disabled]` -> `[dsBtnDisabled]` on the modal's Add button - 9-base's
  `dspace-angular-html/no-disabled-attribute-on-button` is an eslint *error*.
* modal close button `class="close"` + `&times;` -> Bootstrap 5 `btn-close`,
  matching the sibling discard modal in the same template.
* `form-group` -> `mb-3` (Bootstrap 5).
* every `*ngIf` -> `@if`, matching the rest of the file after the v9 migration.
* `getProcessDetailRoute(String(rd.payload.processId))` - `Process.processId` is
  declared `string` but the REST payload delivers a JSON number (the spec's own
  fixtures use `{ processId: 202 }`), so `String()` keeps the route stable.
* `void this.router.navigateByUrl(...)` - the neighbouring `shareSubmission()`
  on 9-base already writes `void this.router.navigate(...)`; without it the port
  would add a new `no-floating-promises` warning.
* spec: the existing 9-base standalone TestBed plus a `ScriptDataService` spy;
  `of` instead of `of as observableOf`. 8 -> 13 `it()`.
* en.json5: the 9 keys are added in the source's relative position (after
  `submission.workflow.generic.share-submission.tooltip`) but without blank lines
  between them, matching the compact style of the CLARIN block they land in;
  cs.json5 keeps the `// "<key>": "<EN>"` comment convention (+27 lines, exactly
  as in the source).

Source: 1c285b4 (dtq-dev PR #1269)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@milanmajchrak
milanmajchrak merged commit 8c91f8b into dtq-dev-9-base Sep 10, 2026
9 checks passed
@milanmajchrak
milanmajchrak deleted the ufal/port-1269-9-base branch September 10, 2026 11:09
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