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
47 changes: 44 additions & 3 deletions src/app/core/data/bundle-data.service.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
import { Injectable } from '@angular/core';
import { RestRequestMethod } from '@dspace/config/rest-request-method';
import { hasValue } from '@dspace/shared/utils/empty.util';
import { Operation } from 'fast-json-patch';
import { Observable } from 'rxjs';
import {
Operation,
RemoveOperation,
} from 'fast-json-patch';
import {
combineLatest as observableCombineLatest,
Observable,
} from 'rxjs';
import {
find,
map,
switchMap,
take,
Expand All @@ -16,6 +23,7 @@ import { Bundle } from '../shared/bundle.model';
import { FollowLinkConfig } from '../shared/follow-link-config.model';
import { HALEndpointService } from '../shared/hal-endpoint.service';
import { Item } from '../shared/item.model';
import { NoContent } from '../shared/NoContent.model';
import { PaginatedSearchOptions } from '../shared/search/models/paginated-search-options.model';
import { IdentifiableDataService } from './base/identifiable-data.service';
import {
Expand All @@ -26,7 +34,10 @@ import { DSOChangeAnalyzer } from './dso-change-analyzer.service';
import { FindListOptions } from './find-list-options.model';
import { PaginatedList } from './paginated-list.model';
import { RemoteData } from './remote-data';
import { GetRequest } from './request.models';
import {
GetRequest,
PatchRequest,
} from './request.models';
import { RequestService } from './request.service';
import { RequestEntryState } from './request-entry-state.model';

Expand Down Expand Up @@ -182,4 +193,34 @@ export class BundleDataService extends IdentifiableDataService<Bundle> implement
public createPatchFromCache(object: Bundle): Observable<Operation[]> {
return this.patchData.createPatchFromCache(object);
}

/**
* Delete multiple {@link Bundle}s at once by sending a PATCH request to the backend
* This will also delete all bitstreams contained in the bundles.
*
* @param bundles The bundles that should be removed
*/
removeMultiple(bundles: Bundle[]): Observable<RemoteData<NoContent>> {
const operations: RemoveOperation[] = bundles.map((bundle: Bundle) => {
return {
op: 'remove',
path: `/bundles/${bundle.id}`,
};
});
const requestId: string = this.requestService.generateRequestId();

const hrefObs: Observable<string> = this.getBrowseEndpoint();

hrefObs.pipe(
find((href: string) => hasValue(href)),
).subscribe((href: string) => {
const request = new PatchRequest(requestId, href, operations);
if (hasValue(this.responseMsToLive)) {
request.responseMsToLive = this.responseMsToLive;
}
this.requestService.send(request);
});

return this.rdbService.buildFromRequestUUIDAndAwait(requestId, () => observableCombineLatest(bundles.map((bundle: Bundle) => this.invalidateByHref(bundle._links.self.href))));
}
}
24 changes: 24 additions & 0 deletions src/app/core/data/item-data.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,30 @@ describe('ItemDataService', () => {
done();
});
});

it('should call setStaleByHrefSubstring on the bundles endpoint', (done) => {
const rdbServiceWithSpy = Object.assign({}, rdbService, {
buildFromRequestUUIDAndAwait: (requestUUID$: any, callback: any) => {
// Execute callback and subscribe to verify cache invalidation
callback().subscribe();
return createSuccessfulRemoteDataObject$({});
},
});
service = new ItemDataService(
requestService,
rdbServiceWithSpy as any,
objectCache,
halEndpointService,
notificationsService,
comparator,
browseService,
bundleService,
);
service.createBundle(itemId, bundleName).subscribe(() => {
expect(requestService.setStaleByHrefSubstring).toHaveBeenCalled();
done();
});
});
});

describe('when cache is invalidated', () => {
Expand Down
7 changes: 6 additions & 1 deletion src/app/core/data/item-data.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,12 @@ export abstract class BaseItemDataService extends IdentifiableDataService<Item>
this.requestService.send(request);
});

return this.rdbService.buildFromRequestUUID(requestId);
return this.rdbService.buildFromRequestUUIDAndAwait(requestId, () =>
hrefObs.pipe(
take(1),
switchMap((href: string) => this.requestService.setStaleByHrefSubstring(href)),
),
);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import {
Subscription,
} from 'rxjs';
import {
distinctUntilKeyChanged,
map,
switchMap,
take,
Expand Down Expand Up @@ -96,6 +97,7 @@ export class AbstractItemUpdateComponent extends AbstractTrackableComponent impl
return this.itemService.findByHref(rd.payload._links.self.href, true, true, ...getItemPageLinksToFollow());
}),
getAllSucceededRemoteData(),
distinctUntilKeyChanged('timeCompleted'),
).subscribe((rd: RemoteData<Item>) => {
this.setItem(rd.payload);
});
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<div class="item-bitstreams" *ngVar="(bundles$ | async) as bundles">
@let bundles = (bundles$ | async);
<div class="item-bitstreams">
<div class="mt-2" id="reorder-description">
<ds-alert [content]="'item.edit.bitstreams.info-alert'" [type]="AlertType.Info"></ds-alert>
</div>
Expand Down Expand Up @@ -37,20 +38,18 @@

@if (item && bundles?.length > 0) {
<div class="mt-4 table-border scrollable-table" [ngClass]="{'disabled-overlay': (isProcessingMoveRequest | async)}">
@for (bundle of bundles; track bundle; let isFirst = $first) {
@let bundleUpdates = (bundleFieldUpdates$ | async);
@for (bundle of bundles; track bundle.uuid; let isFirst = $first) {
<ds-item-edit-bitstream-bundle
[bundle]="bundle"
[item]="item"
[columnSizes]="columnSizes"
[isFirstTable]="isFirst"
[bundleUpdate]="bundleUpdates?.[bundle.uuid]"
[bundleUpdatesUrl]="bundleUpdatesUrl"
aria-describedby="reorder-description">
</ds-item-edit-bitstream-bundle>
}
@if (showLoadMoreLink$ | async) {
<div class="d-flex justify-content-center">
<button class="btn btn-link my-3" (click)="loadBundles()"> {{'item.edit.bitstreams.load-more.link' | translate}}</button>
</div>
}
</div>
}
@if (bundles?.length === 0) {
Expand Down Expand Up @@ -90,7 +89,6 @@
}
</div>
</div>
</div>

@if (isProcessingMoveRequest | async) {
<ds-loading class="loading-overlay"></ds-loading>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,21 @@
.header-row {
color: var(--bs-table-dark-color);
background-color: var(--bs-table-dark-bg);
border-color: var(--bs-table-dark-border-color);
}

.bundle-row:not(.table-danger) {
color: var(--bs-table-head-color);
background-color: var(--bs-table-head-bg);
border-color: var(--bs-table-border-color);
}

.row-element {
padding: 12px;
padding: 0.75em;
border-bottom: var(--bs-table-border-width) solid var(--bs-table-border-color);
}

.drag-handle {
&:hover {
cursor: move;
Expand Down Expand Up @@ -54,6 +72,15 @@
left: 50%;
}

.bundle-remove-warning {
white-space: nowrap;
font-size: 0.75rem;

@media (min-width: map-get($grid-breakpoints, sm)) {
font-size: 0.875rem;
}
}

tr.table-danger > * {
--bs-table-bg-type: var(--bs-table-bg);
}
Loading
Loading