Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -420,8 +420,12 @@ export class EditBitstreamPageComponent implements OnInit, OnDestroy {
);

const bundle$ = bitstream$.pipe(
switchMap((bitstream: Bitstream) => bitstream.bundle),
getFirstSucceededRemoteDataPayload(),
switchMap((bitstream: Bitstream) => {
if (hasValue(bitstream) && hasValue(bitstream.bundle)) {
return bitstream.bundle.pipe(getFirstSucceededRemoteDataPayload());
}
return observableOf(undefined);
}),
);

const primaryBitstream$ = bundle$.pipe(
Expand All @@ -431,12 +435,20 @@ export class EditBitstreamPageComponent implements OnInit, OnDestroy {
);

const item$ = bundle$.pipe(
switchMap((bundle: Bundle) => bundle.item),
getFirstSucceededRemoteDataPayload(),
switchMap((bundle: Bundle) => {
if (hasValue(bundle) && hasValue(bundle.item)) {
return bundle.item.pipe(getFirstSucceededRemoteDataPayload());
}
return observableOf(undefined);
}),
);
const format$ = bitstream$.pipe(
switchMap(bitstream => bitstream.format),
getFirstSucceededRemoteDataPayload(),
switchMap((bitstream: Bitstream) => {
if (hasValue(bitstream) && hasValue(bitstream.format)) {
return bitstream.format.pipe(getFirstSucceededRemoteDataPayload());
}
return observableOf(undefined);
}),
);

this.subs.push(
Expand All @@ -449,15 +461,23 @@ export class EditBitstreamPageComponent implements OnInit, OnDestroy {
).subscribe(([bitstream, bundle, primaryBitstream, item, format]) => {
this.bitstream = bitstream as Bitstream;
this.bundle = bundle;
this.selectedFormat = format;
if (hasValue(format)) {
this.selectedFormat = format;
}
// hasValue(primaryBitstream) because if there's no primaryBitstream on the bundle it will
// be a success response, but empty
this.primaryBitstreamUUID = hasValue(primaryBitstream) ? primaryBitstream.uuid : null;
this.itemId = item.uuid;
if (hasValue(item)) {
this.itemId = item.uuid;
}
this.setIiifStatus(this.bitstream);
}),
format$.pipe(take(1)).subscribe(
(format) => this.originalFormat = format,
(format) => {
if (hasValue(format)) {
this.originalFormat = format;
}
},
),
);

Expand Down Expand Up @@ -732,6 +752,11 @@ export class EditBitstreamPageComponent implements OnInit, OnDestroy {
*/
setIiifStatus(bitstream: Bitstream) {

if (hasValue(bitstream) === false || hasValue(bitstream.bundle) === false || hasValue(bitstream.format) === false) {
this.isIIIF = false;
return;
}

const regexExcludeBundles = /OTHERCONTENT|THUMBNAIL|LICENSE/;
const regexIIIFItem = /true|yes/i;

Expand All @@ -745,13 +770,20 @@ export class EditBitstreamPageComponent implements OnInit, OnDestroy {
this.dsoNameService.getName(bundle.payload).match(regexExcludeBundles) == null));

const isEnabled$ = this.bitstream.bundle.pipe(
getFirstSucceededRemoteData(),
map((bundle: RemoteData<Bundle>) => bundle.payload.item.pipe(
getFirstSucceededRemoteData(),
map((item: RemoteData<Item>) =>
(item.payload.firstMetadataValue('dspace.iiif.enabled') &&
item.payload.firstMetadataValue('dspace.iiif.enabled').match(regexIIIFItem) !== null)
))));
getFirstSucceededRemoteDataPayload(),
switchMap((bundle: Bundle) => {
if (hasValue(bundle) && hasValue(bundle.item)) {
return bundle.item.pipe(
getFirstSucceededRemoteDataPayload(),
map((item: Item) => {
const iiifEnabledValue = item.firstMetadataValue('dspace.iiif.enabled');
return hasValue(iiifEnabledValue) && iiifEnabledValue.match(regexIIIFItem) !== null;
})
);
}
return observableOf(false);
})
);

const iiifSub = combineLatest(
isImage$,
Expand Down
4 changes: 2 additions & 2 deletions src/app/core/breadcrumbs/bitstream-breadcrumbs.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,12 +62,12 @@ export class BitstreamBreadcrumbsService extends DSOBreadcrumbsService {
getFirstCompletedRemoteData(),
getRemoteDataPayload(),
switchMap((bitstream: Bitstream) => {
if (hasValue(bitstream)) {
if (hasValue(bitstream) && hasValue(bitstream.bundle)) {
return bitstream.bundle.pipe(
getFirstCompletedRemoteData(),
getRemoteDataPayload(),
switchMap((bundle: Bundle) => {
if (hasValue(bundle)) {
if (hasValue(bundle) && hasValue(bundle.item)) {
return bundle.item.pipe(
getFirstCompletedRemoteData(),
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,11 @@ describe('UploadBitstreamComponent', () => {
const mockItem = Object.assign(new Item(), {
id: 'fake-id',
handle: 'fake/handle',
_links: {
self: {
href: '/api/core/items/fake-id'
}
},
metadata: {
'dc.title': [
{
Expand All @@ -83,6 +88,7 @@ describe('UploadBitstreamComponent', () => {
const restEndpoint = 'fake-rest-endpoint';
const mockItemDataService = jasmine.createSpyObj('mockItemDataService', {
getBitstreamsEndpoint: observableOf(restEndpoint),
getBundlesEndpoint: observableOf('/api/core/items/fake-id/bundles'),
createBundle: createSuccessfulRemoteDataObject$(createdBundle),
getBundles: createSuccessfulRemoteDataObject$(buildPaginatedList(new PageInfo(), [bundle])),
});
Expand All @@ -97,7 +103,7 @@ describe('UploadBitstreamComponent', () => {
const notificationsServiceStub = new NotificationsServiceStub();
const uploaderComponent = jasmine.createSpyObj('uploaderComponent', ['ngOnInit', 'ngAfterViewInit']);
const requestService = jasmine.createSpyObj('requestService', {
removeByHrefSubstring: {}
setStaleByHrefSubstring: {}
});

describe('when a file is uploaded', () => {
Expand Down Expand Up @@ -131,6 +137,28 @@ describe('UploadBitstreamComponent', () => {
it('should navigate the user to the next page', () => {
expect(routerStub.navigate).toHaveBeenCalled();
});

it('should clear cached requests for the selected bundle bitstreams endpoint', () => {
expect(requestService.setStaleByHrefSubstring).toHaveBeenCalledWith(restEndpoint);
});

it('should clear cached requests for the item bundles endpoint', () => {
expect(requestService.setStaleByHrefSubstring).toHaveBeenCalledWith('/api/core/items/fake-id/bundles');
});

it('should clear cached requests for the item self endpoint', () => {
expect(requestService.setStaleByHrefSubstring).toHaveBeenCalledWith('/api/core/items/fake-id');
});

it('should clear cached requests for the metadatabitstreams byHandle endpoint with encoded handle', () => {
expect(requestService.setStaleByHrefSubstring)
.toHaveBeenCalledWith('/api/core/metadatabitstreams/search/byHandle?handle=fake%2Fhandle&fileGrpType=ORIGINAL');
});

it('should clear cached requests for the metadatabitstreams byHandle endpoint with raw handle', () => {
expect(requestService.setStaleByHrefSubstring)
.toHaveBeenCalledWith('/api/core/metadatabitstreams/search/byHandle?handle=fake/handle&fileGrpType=ORIGINAL');
});
});
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,28 @@ export class UploadBitstreamComponent implements OnInit, OnDestroy {
public onCompleteItem(bitstream) {
// Clear cached requests for this bundle's bitstreams to ensure lists on all pages are up-to-date
this.bundleService.getBitstreamsEndpoint(this.selectedBundleId).pipe(take(1)).subscribe((href: string) => {
this.requestService.removeByHrefSubstring(href);
this.requestService.setStaleByHrefSubstring(href);
});

// Clear cached requests for this item's bundles to ensure bundle resolution uses fresh data
this.itemService.getBundlesEndpoint(this.itemId).pipe(take(1)).subscribe((href: string) => {
this.requestService.setStaleByHrefSubstring(href);
});

// Clear cached requests for this item to ensure breadcrumb navigation resolves a fresh item
this.itemRD$.pipe(
getFirstSucceededRemoteDataPayload(),
take(1),
).subscribe((item: Item) => {
this.requestService.setStaleByHrefSubstring(item._links.self.href);

// Clear metadatabitstreams search cache used by preview and CLARIN files sections
if (item?.handle) {
const byHandleBase = '/api/core/metadatabitstreams/search/byHandle';
const encodedHandle = encodeURIComponent(item.handle);
this.requestService.setStaleByHrefSubstring(`${byHandleBase}?handle=${encodedHandle}&fileGrpType=ORIGINAL`);
this.requestService.setStaleByHrefSubstring(`${byHandleBase}?handle=${item.handle}&fileGrpType=ORIGINAL`);
}
});

// Bring over the item ID as a query parameter
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Component, Input, OnInit } from '@angular/core';
import { Component, Input, OnChanges, OnDestroy, OnInit, SimpleChanges } from '@angular/core';
import { Item } from '../../core/shared/item.model';
import { getAllSucceededRemoteListPayload, getFirstSucceededRemoteDataPayload } from '../../core/shared/operators';
import { getItemPageRoute } from '../item-page-routing-paths';
Expand All @@ -7,15 +7,15 @@ import { RegistryService } from '../../core/registry/registry.service';
import { Router } from '@angular/router';
import { HALEndpointService } from '../../core/shared/hal-endpoint.service';
import { ConfigurationDataService } from '../../core/data/configuration-data.service';
import { BehaviorSubject } from 'rxjs';
import { BehaviorSubject, Subscription } from 'rxjs';
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';

@Component({
selector: 'ds-clarin-files-section',
templateUrl: './clarin-files-section.component.html',
styleUrls: ['./clarin-files-section.component.scss']
})
export class ClarinFilesSectionComponent implements OnInit {
export class ClarinFilesSectionComponent implements OnInit, OnChanges, OnDestroy {

/**
* The item to display files for
Expand Down Expand Up @@ -72,6 +72,9 @@ export class ClarinFilesSectionComponent implements OnInit {
*/
downloadZipMinFileCount: BehaviorSubject<number> = new BehaviorSubject<number>(-1);

private currentItemHandle: string;
private filesSubscription?: Subscription;


constructor(protected registryService: RegistryService,
protected router: Router,
Expand All @@ -81,17 +84,19 @@ export class ClarinFilesSectionComponent implements OnInit {
}

ngOnInit(): void {
this.registryService
.getMetadataBitstream(this.itemHandle, 'ORIGINAL')
.pipe(getAllSucceededRemoteListPayload())
.subscribe((data: MetadataBitstream[]) => {
this.listOfFiles.next(data);
this.generateCurlCommand();
});
this.totalFileSizes.next(Number(this.item.firstMetadataValue('local.files.size')));
this.loadDownloadZipConfigProperties();
}

ngOnChanges(changes: SimpleChanges): void {
if (changes.item || changes.itemHandle) {
this.refreshFromInputs(true);
}
}

ngOnDestroy(): void {
this.filesSubscription?.unsubscribe();
}

openCommandModal(content: any) {
this.commandCopied = false;
this.modalService.open(content, { size: 'lg', centered: true, ariaLabelledBy: 'commandModalTitle' });
Expand Down Expand Up @@ -161,4 +166,29 @@ export class ClarinFilesSectionComponent implements OnInit {
this.downloadZipMinFileSize.next(Number(config.values[0]));
});
}

private refreshFromInputs(force = false): void {
if (this.item) {
this.totalFileSizes.next(Number(this.item.firstMetadataValue('local.files.size')));
}

const handle = this.itemHandle || this.item?.handle;
if (!handle) {
return;
}

if (!force && handle === this.currentItemHandle) {
return;
}

this.currentItemHandle = handle;
this.filesSubscription?.unsubscribe();
this.filesSubscription = this.registryService
.getMetadataBitstream(handle, 'ORIGINAL')
.pipe(getAllSucceededRemoteListPayload())
.subscribe((data: MetadataBitstream[]) => {
this.listOfFiles.next(data);
this.generateCurlCommand();
});
}
}
2 changes: 1 addition & 1 deletion src/app/item-page/item.resolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ export class ItemResolver implements Resolve<RemoteData<Item>> {
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<RemoteData<Item>> {
const itemRD$ = this.itemService.findById(route.params.id,
true,
false,
true,
...getItemPageLinksToFollow(),
).pipe(
getFirstCompletedRemoteData(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { ComponentFixture, TestBed } from '@angular/core/testing';
import { BehaviorSubject, of } from 'rxjs';
import { MetadataBitstream } from 'src/app/core/metadata/metadata-bitstream.model';
import { RegistryService } from 'src/app/core/registry/registry.service';
import { SimpleChange } from '@angular/core';

import { PreviewSectionComponent } from './preview-section.component';
import { ResourceType } from 'src/app/core/shared/resource-type';
Expand Down Expand Up @@ -75,7 +76,10 @@ describe('PreviewSectionComponent', () => {
expect(component).toBeTruthy();
});

it('should call getMetadataBitstream on init', () => {
it('should call getMetadataBitstream on item input change', () => {
component.ngOnChanges({
item: new SimpleChange(undefined, component.item, true),
});
expect(mockRegistryService.getMetadataBitstream).toHaveBeenCalled();
});

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Component, Input, OnInit } from '@angular/core';
import { BehaviorSubject } from 'rxjs';
import { Component, Input, OnChanges, OnDestroy, OnInit, SimpleChanges } from '@angular/core';
import { BehaviorSubject, Subscription } from 'rxjs';
import { MetadataBitstream } from 'src/app/core/metadata/metadata-bitstream.model';
import { RegistryService } from 'src/app/core/registry/registry.service';
import { Item } from 'src/app/core/shared/item.model';
Expand All @@ -11,26 +11,53 @@ import { ConfigurationDataService } from '../../../../core/data/configuration-da
templateUrl: './preview-section.component.html',
styleUrls: ['./preview-section.component.scss'],
})
export class PreviewSectionComponent implements OnInit {
export class PreviewSectionComponent implements OnInit, OnChanges, OnDestroy {
@Input() item: Item;

listOfFiles: BehaviorSubject<MetadataBitstream[]> = new BehaviorSubject<MetadataBitstream[]>([] as any);
emailToContact: string;
hasNoFiles: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(true);

private currentItemHandle: string;
private filesSubscription?: Subscription;

constructor(protected registryService: RegistryService,
private configService: ConfigurationDataService) {} // Modified
private configService: ConfigurationDataService) {}

ngOnInit(): void {
this.registryService
.getMetadataBitstream(this.item.handle, 'ORIGINAL')
this.configService.findByPropertyName('lr.help.mail')?.subscribe(remoteData => {
this.emailToContact = remoteData.payload?.values?.[0];
});
}

ngOnChanges(changes: SimpleChanges): void {
if (changes.item) {
this.refreshFiles(true);
}
}

ngOnDestroy(): void {
this.filesSubscription?.unsubscribe();
}

private refreshFiles(force = false): void {
const handle = this.item?.handle;
if (!handle) {
return;
}

if (!force && handle === this.currentItemHandle) {
return;
}

this.currentItemHandle = handle;
this.filesSubscription?.unsubscribe();
this.filesSubscription = this.registryService
.getMetadataBitstream(handle, 'ORIGINAL')
.pipe(getAllSucceededRemoteListPayload())
.subscribe((data: MetadataBitstream[]) => {
this.listOfFiles.next(data);
this.hasNoFiles.next(!Array.isArray(data) || data.length === 0);
});
this.configService.findByPropertyName('lr.help.mail')?.subscribe(remoteData => {
this.emailToContact = remoteData.payload?.values?.[0];
});
}
}
Loading