Skip to content
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,26 +752,38 @@ export class EditBitstreamPageComponent implements OnInit, OnDestroy {
*/
setIiifStatus(bitstream: Bitstream) {

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

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

const isImage$ = this.bitstream.format.pipe(
const isImage$ = bitstream.format.pipe(
getFirstSucceededRemoteData(),
map((format: RemoteData<BitstreamFormat>) => format.payload.mimetype.includes('image/')));

const isIIIFBundle$ = this.bitstream.bundle.pipe(
const isIIIFBundle$ = bitstream.bundle.pipe(
getFirstSucceededRemoteData(),
map((bundle: RemoteData<Bundle>) =>
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)
))));
const isEnabled$ = bitstream.bundle.pipe(
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');
});
Comment thread
amadulhaxxani marked this conversation as resolved.
});
});

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) {
Comment thread
amadulhaxxani marked this conversation as resolved.
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();
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import { NoContent } from '../../../core/shared/NoContent.model';
import { ItemBitstreamsService } from './item-bitstreams.service';
import { AlertType } from '../../../shared/alert/alert-type';
import { PaginationComponentOptions } from '../../../shared/pagination/pagination-component-options.model';
import { hasValue } from '../../../shared/empty.util';

@Component({
selector: 'ds-item-bitstreams',
Expand Down Expand Up @@ -224,6 +225,24 @@ export class ItemBitstreamsComponent extends AbstractItemUpdateComponent impleme
removedResponses$.subscribe((responses: RemoteData<NoContent>) => {
this.itemBitstreamsService.displayNotifications('item.edit.bitstreams.notifications.remove', [responses]);
this.submitting = false;

// Clear caches to ensure file lists are refreshed after bitstream removal (same as upload)
this.bundles$.pipe(take(1)).subscribe((bundles: Bundle[]) => {
if (!hasValue(bundles)) { return; }
bundles.forEach((bundle: Bundle) => {
if (bundle?._links?.bitstreams?.href) {
this.requestService.setStaleByHrefSubstring(bundle._links.bitstreams.href);
}
});
});

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

Expand Down
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
Loading
Loading