65717: Edit-bitstreams bundle upload button + bitstream-upload component changes to include bundles

This commit is contained in:
Kristof De Langhe
2019-10-21 13:29:46 +02:00
parent b9754764b3
commit 9abc48960f
8 changed files with 119 additions and 57 deletions

View File

@@ -270,12 +270,14 @@
"home.top-level-communities.head": "Communities in DSpace",
"home.top-level-communities.help": "Select a community to browse its collections.",
"item.bitstreams.upload.bundle-name": "Bundle Name",
"item.bitstreams.upload.bundle": "Bundle",
"item.bitstreams.upload.bundles.empty": "This item doesn\'t contain any bundles to upload a bitstream to.",
"item.bitstreams.upload.drop-message": "Drop a file to upload",
"item.bitstreams.upload.failed": "Upload failed. Please verify the content before retrying.",
"item.bitstreams.upload.item": "Item: ",
"item.bitstreams.upload.title": "Upload bitstream",
"item.edit.bitstreams.bundle.edit.buttons.upload": "Upload",
"item.edit.bitstreams.bundle.name": "BUNDLE: {{ name }}",
"item.edit.bitstreams.discard-button": "Discard",
"item.edit.bitstreams.edit.buttons.download": "Download",

View File

@@ -1,28 +1,36 @@
<div class="container">
<div class="row">
<div class="col-12 mb-4">
<h2>{{'item.bitstreams.upload.title' | translate}}</h2>
<ng-container *ngVar="(itemRD$ | async)?.payload as item">
<div *ngIf="item">
<span class="font-weight-bold">{{'item.bitstreams.upload.item' | translate}}</span>
<span>{{item.name}}</span>
<div class="container" *ngVar="(bundlesRD$ | async)?.payload?.page as bundles">
<ng-container *ngIf="bundles">
<div class="row" *ngIf="bundles.length > 0">
<div class="col-12 mb-4">
<h2>{{'item.bitstreams.upload.title' | translate}}</h2>
<ng-container *ngVar="(itemRD$ | async)?.payload as item">
<div *ngIf="item">
<span class="font-weight-bold">{{'item.bitstreams.upload.item' | translate}}</span>
<span>{{item.name}}</span>
</div>
</ng-container>
</div>
<div class="col-12">
<label for="bundleName" class="font-weight-bold">{{'item.bitstreams.upload.bundle' | translate}}</label>
<select id="bundleName" class="form-control" [(ngModel)]="selectedBundleId" (change)="setUploadUrl()">
<option *ngFor="let bundle of bundles" [value]="bundle.id">{{bundle.name}}</option>
</select>
<ds-uploader class="w-100"
[dropMsg]="'item.bitstreams.upload.drop-message'"
[dropOverDocumentMsg]="'item.bitstreams.upload.drop-message'"
[enableDragOverDocument]="true"
[uploadFilesOptions]="uploadFilesOptions"
[uploadProperties]="uploadProperties"
(onCompleteItem)="onCompleteItem($event)"
(onUploadError)="onUploadError()"></ds-uploader>
</div>
</div>
<div class="row" *ngIf="bundles.length === 0">
<div class="col-12">
<div class="alert alert-info w-100 d-inline-block" role="alert">
{{'item.bitstreams.upload.bundles.empty' | translate}}
</div>
</ng-container>
</div>
</div>
<div class="col-12">
<label for="bundleName" class="font-weight-bold">{{'item.bitstreams.upload.bundle-name' | translate}}</label>
<input id="bundleName"
[(ngModel)]="uploadProperties.bundleName"
type="text"
class="form-control" />
<ds-uploader class="w-100"
[dropMsg]="'item.bitstreams.upload.drop-message'"
[dropOverDocumentMsg]="'item.bitstreams.upload.drop-message'"
[enableDragOverDocument]="true"
[uploadFilesOptions]="uploadFilesOptions"
[uploadProperties]="uploadProperties"
(onCompleteItem)="onCompleteItem($event)"
(onUploadError)="onUploadError()"></ds-uploader>
</div>
</div>
</ng-container>
</div>

View File

@@ -2,17 +2,20 @@ import { ChangeDetectionStrategy, Component, OnDestroy, OnInit } from '@angular/
import { Observable } from 'rxjs/internal/Observable';
import { RemoteData } from '../../../core/data/remote-data';
import { Item } from '../../../core/shared/item.model';
import { distinctUntilChanged, map, switchMap } from 'rxjs/operators';
import { map, switchMap, take } from 'rxjs/operators';
import { ActivatedRoute, Router } from '@angular/router';
import { UploaderOptions } from '../../../shared/uploader/uploader-options.model';
import { Subscription } from 'rxjs/internal/Subscription';
import { hasValue, hasValueOperator } from '../../../shared/empty.util';
import { hasValue, isEmpty } from '../../../shared/empty.util';
import { ItemDataService } from '../../../core/data/item-data.service';
import { AuthService } from '../../../core/auth/auth.service';
import { NotificationsService } from '../../../shared/notifications/notifications.service';
import { TranslateService } from '@ngx-translate/core';
import { UploaderProperties } from '../../../shared/uploader/uploader-properties.model';
import { getBitstreamModulePath } from '../../../app-routing.module';
import { PaginatedList } from '../../../core/data/paginated-list';
import { Bundle } from '../../../core/shared/bundle.model';
import { BundleDataService } from '../../../core/data/bundle-data.service';
import { getRemoteDataPayload, getSucceededRemoteData } from '../../../core/shared/operators';
@Component({
selector: 'ds-upload-bitstream',
@@ -29,12 +32,23 @@ export class UploadBitstreamComponent implements OnInit, OnDestroy {
*/
itemRD$: Observable<RemoteData<Item>>;
/**
* The item's bundles
*/
bundlesRD$: Observable<RemoteData<PaginatedList<Bundle>>>;
/**
* The ID of the currently selected bundle to upload a bitstream to
*/
selectedBundleId: string;
/**
* The uploader configuration options
* @type {UploaderOptions}
*/
uploadFilesOptions: UploaderOptions = {
url: '',
// URL needs to contain something to not produce any errors. This will be replaced once a bundle has been selected.
url: 'placeholder',
authToken: null,
disableMultipart: false,
itemAlias: null
@@ -46,16 +60,10 @@ export class UploadBitstreamComponent implements OnInit, OnDestroy {
*/
subs: Subscription[] = [];
/**
* Properties to send with the upload request
*/
uploadProperties = Object.assign(new UploaderProperties(), {
bundleName: 'ORIGINAL'
});
constructor(protected route: ActivatedRoute,
protected router: Router,
protected itemService: ItemDataService,
protected bundleService: BundleDataService,
protected authService: AuthService,
protected notificationsService: NotificationsService,
protected translate: TranslateService) {
@@ -63,25 +71,36 @@ export class UploadBitstreamComponent implements OnInit, OnDestroy {
ngOnInit(): void {
this.itemRD$ = this.route.data.pipe(map((data) => data.item));
this.subs.push(
this.route.queryParams.pipe(
map((params) => params.bundleName),
hasValueOperator(),
distinctUntilChanged()
).subscribe((bundleName: string) => {
this.uploadProperties.bundleName = bundleName;
})
this.bundlesRD$ = this.itemRD$.pipe(
switchMap((itemRD: RemoteData<Item>) => itemRD.payload.bundles)
);
this.subs.push(
this.itemRD$.pipe(
map((itemRD: RemoteData<Item>) => itemRD.payload),
switchMap((item: Item) => this.itemService.getBitstreamsEndpoint(item.id)),
distinctUntilChanged()
).subscribe((url: string) => {
this.uploadFilesOptions.url = url;
this.selectedBundleId = this.route.snapshot.queryParams.bundle;
if (isEmpty(this.selectedBundleId)) {
this.bundlesRD$.pipe(
getSucceededRemoteData(),
getRemoteDataPayload(),
take(1)
).subscribe((bundles: PaginatedList<Bundle>) => {
if (bundles.page.length > 0) {
this.selectedBundleId = bundles.page[0].id;
this.setUploadUrl();
}
});
} else {
this.setUploadUrl();
}
}
/**
* Set the upload url to match the selected bundle ID
*/
setUploadUrl() {
this.bundleService.getBitstreamsEndpoint(this.selectedBundleId).pipe(take(1)).subscribe((href: string) => {
this.uploadFilesOptions.url = href;
if (isEmpty(this.uploadFilesOptions.authToken)) {
this.uploadFilesOptions.authToken = this.authService.buildAuthHeader();
})
);
}
});
}
/**

View File

@@ -24,6 +24,7 @@ import { EditRelationshipListComponent } from './item-relationships/edit-relatio
import { AbstractItemUpdateComponent } from './abstract-item-update/abstract-item-update.component';
import { ItemMoveComponent } from './item-move/item-move.component';
import { ItemEditBitstreamBundleComponent } from './item-bitstreams/item-edit-bitstream-bundle/item-edit-bitstream-bundle.component';
import { BundleDataService } from '../../core/data/bundle-data.service';
/**
* Module that contains all components related to the Edit Item page administrator functionality
@@ -58,6 +59,9 @@ import { ItemEditBitstreamBundleComponent } from './item-bitstreams/item-edit-bi
EditRelationshipListComponent,
ItemCollectionMapperComponent,
ItemMoveComponent,
],
providers: [
BundleDataService
]
})
export class EditItemPageModule {

View File

@@ -23,7 +23,7 @@
</button>
</div>
<table *ngIf="bundles?.length > 0" class="table table-responsive table-striped table-bordered mt-4">
<table *ngIf="item && bundles?.length > 0" class="table table-responsive table-striped table-bordered mt-4">
<tbody>
<tr>
<th>{{'item.edit.bitstreams.headers.name' | translate}}</th>
@@ -33,7 +33,8 @@
</tr>
<ds-item-edit-bitstream-bundle *ngFor="let bundle of bundles"
[url]="url"
[bundle]="bundle">
[bundle]="bundle"
[item]="item">
</ds-item-edit-bitstream-bundle>
</tbody>
</table>

View File

@@ -1,6 +1,16 @@
<ng-template #bundleView>
<tr>
<td colspan="4">{{'item.edit.bitstreams.bundle.name' | translate:{ name: bundle.name } }}</td>
<td colspan="3" class="font-weight-bold">{{'item.edit.bitstreams.bundle.name' | translate:{ name: bundle.name } }}</td>
<td class="text-center">
<div class="btn-group bundle-action-buttons">
<button [routerLink]="['/items/', item.id, 'bitstreams', 'new']"
[queryParams]="{bundle: bundle.id}"
class="btn btn-outline-success btn-sm"
title="{{'item.edit.bitstreams.bundle.edit.buttons.upload' | translate}}">
<i class="fas fa-upload fa-fw"></i>
</button>
</div>
</td>
</tr>
<ng-container *ngVar="((updates$ | async) | dsObjectValues) as updateValues">
<tr *ngFor="let updateValue of updateValues"

View File

@@ -6,6 +6,7 @@ import { FieldUpdates } from '../../../../core/data/object-updates/object-update
import { toBitstreamsArray } from '../../../../core/shared/item-bitstreams-utils';
import { switchMap } from 'rxjs/operators';
import { Bitstream } from '../../../../core/shared/bitstream.model';
import { Item } from '../../../../core/shared/item.model';
@Component({
selector: 'ds-item-edit-bitstream-bundle',
@@ -26,6 +27,11 @@ export class ItemEditBitstreamBundleComponent implements OnInit {
*/
@Input() bundle: Bundle;
/**
* The item the bundle belongs to
*/
@Input() item: Item;
/**
* The current url of this page
*/

View File

@@ -13,6 +13,7 @@ import { HttpClient } from '@angular/common/http';
import { DefaultChangeAnalyzer } from './default-change-analyzer.service';
import { FindAllOptions } from './request.models';
import { Observable } from 'rxjs/internal/Observable';
import { switchMap } from 'rxjs/operators';
/**
* A service responsible for fetching/sending data from/to the REST API on the bundles endpoint
@@ -20,6 +21,7 @@ import { Observable } from 'rxjs/internal/Observable';
@Injectable()
export class BundleDataService extends DataService<Bundle> {
protected linkPath = 'bundles';
protected bitstreamsEndpoint = 'bitstreams';
protected forceBypassCache = false;
constructor(
@@ -43,4 +45,14 @@ export class BundleDataService extends DataService<Bundle> {
getBrowseEndpoint(options: FindAllOptions = {}, linkPath?: string): Observable<string> {
return this.halService.getEndpoint(this.linkPath);
}
/**
* Get the bitstreams endpoint for a bundle
* @param bundleId
*/
getBitstreamsEndpoint(bundleId: string): Observable<string> {
return this.getBrowseEndpoint().pipe(
switchMap((href: string) => this.halService.getEndpoint(this.bitstreamsEndpoint, `${href}/${bundleId}`))
);
}
}