diff --git a/resources/i18n/en.json b/resources/i18n/en.json
index 05d7e300b0..dcc19e6a21 100644
--- a/resources/i18n/en.json
+++ b/resources/i18n/en.json
@@ -135,19 +135,34 @@
"head": "Item Mapper - Map Item to Collections",
"item": "Item: \"{{name}}\"",
"description": "This is the item mapper tool that allows administrators to map this item to other collections. You can search for collections and map them, or browse the list of collections the item is currently mapped to.",
- "confirm": "Map item to selected collections",
"tabs": {
"browse": "Browse",
"map": "Map"
},
+ "buttons": {
+ "add": "Map item to selected collections",
+ "remove": "Remove item's mapping for selected collections"
+ },
"notifications": {
- "success": {
- "head": "Mapping completed",
- "content": "Successfully mapped item to {{amount}} collections."
+ "add": {
+ "success": {
+ "head": "Mapping completed",
+ "content": "Successfully mapped item to {{amount}} collections."
+ },
+ "error": {
+ "head": "Mapping errors",
+ "content": "Errors occurred for mapping of item to {{amount}} collections."
+ }
},
- "error": {
- "head": "Mapping errors",
- "content": "Errors occurred for mapping of item to {{amount}} collections."
+ "remove": {
+ "success": {
+ "head": "Removal of mapping completed",
+ "content": "Successfully removed mapping of item to {{amount}} collections."
+ },
+ "error": {
+ "head": "Removal of mapping errors",
+ "content": "Errors occurred for the removal of the mapping to {{amount}} collections."
+ }
}
},
"return": "Return"
diff --git a/src/app/+item-page/edit-item-page/item-collection-mapper/item-collection-mapper.component.html b/src/app/+item-page/edit-item-page/item-collection-mapper/item-collection-mapper.component.html
index 990ac70c64..f02a62b769 100644
--- a/src/app/+item-page/edit-item-page/item-collection-mapper/item-collection-mapper.component.html
+++ b/src/app/+item-page/edit-item-page/item-collection-mapper/item-collection-mapper.component.html
@@ -19,7 +19,11 @@
@@ -29,7 +33,7 @@
diff --git a/src/app/+item-page/edit-item-page/item-collection-mapper/item-collection-mapper.component.ts b/src/app/+item-page/edit-item-page/item-collection-mapper/item-collection-mapper.component.ts
index 8708065488..95c2ffd361 100644
--- a/src/app/+item-page/edit-item-page/item-collection-mapper/item-collection-mapper.component.ts
+++ b/src/app/+item-page/edit-item-page/item-collection-mapper/item-collection-mapper.component.ts
@@ -18,6 +18,7 @@ import { ItemDataService } from '../../../core/data/item-data.service';
import { RestResponse } from '../../../core/cache/response-cache.models';
import { TranslateService } from '@ngx-translate/core';
import { NotificationsService } from '../../../shared/notifications/notifications.service';
+import { C } from '@angular/core/src/render3';
@Component({
selector: 'ds-item-collection-mapper',
@@ -47,7 +48,7 @@ export class ItemCollectionMapperComponent implements OnInit {
* List of collections to show under the "Browse" tab
* Collections that are mapped to the item
*/
- itemCollectionsRD$: Observable>;
+ itemCollectionsRD$: Observable>>;
/**
* List of collections to show under the "Map" tab
@@ -97,13 +98,36 @@ export class ItemCollectionMapperComponent implements OnInit {
switchMap((itemId: string) => Observable.combineLatest(ids.map((id: string) => this.itemDataService.mapToCollection(itemId, id))))
);
+ this.showNotifications(responses$, 'item.edit.item-mapper.notifications.add');
+ }
+
+ /**
+ * Remove the mapping of the item to the selected collections and display notifications
+ * @param {string[]} ids The list of collection UUID's to remove the mapping of the item for
+ */
+ removeMappings(ids: string[]) {
+ const responses$ = this.itemRD$.pipe(
+ getSucceededRemoteData(),
+ map((itemRD: RemoteData- ) => itemRD.payload.id),
+ switchMap((itemId: string) => Observable.combineLatest(ids.map((id: string) => this.itemDataService.removeMappingFromCollection(itemId, id))))
+ );
+
+ this.showNotifications(responses$, 'item.edit.item-mapper.notifications.remove');
+ }
+
+ /**
+ * Display notifications
+ * @param {Observable} responses$ The responses after adding/removing a mapping
+ * @param {string} messagePrefix The prefix to build the notification messages with
+ */
+ private showNotifications(responses$: Observable, messagePrefix: string) {
responses$.subscribe((responses: RestResponse[]) => {
const successful = responses.filter((response: RestResponse) => response.isSuccessful);
const unsuccessful = responses.filter((response: RestResponse) => !response.isSuccessful);
if (successful.length > 0) {
const successMessages = Observable.combineLatest(
- this.translateService.get('item.edit.item-mapper.notifications.success.head'),
- this.translateService.get('item.edit.item-mapper.notifications.success.content', { amount: successful.length })
+ this.translateService.get(`${messagePrefix}.success.head`),
+ this.translateService.get(`${messagePrefix}.success.content`, { amount: successful.length })
);
successMessages.subscribe(([head, content]) => {
@@ -112,8 +136,8 @@ export class ItemCollectionMapperComponent implements OnInit {
}
if (unsuccessful.length > 0) {
const unsuccessMessages = Observable.combineLatest(
- this.translateService.get('item.edit.item-mapper.notifications.error.head'),
- this.translateService.get('item.edit.item-mapper.notifications.error.content', { amount: unsuccessful.length })
+ this.translateService.get(`${messagePrefix}.error.head`),
+ this.translateService.get(`${messagePrefix}.error.content`, { amount: unsuccessful.length })
);
unsuccessMessages.subscribe(([head, content]) => {
diff --git a/src/app/core/data/item-data.service.ts b/src/app/core/data/item-data.service.ts
index 0fe9a690e2..3b6d3d90ab 100644
--- a/src/app/core/data/item-data.service.ts
+++ b/src/app/core/data/item-data.service.ts
@@ -15,7 +15,14 @@ import { URLCombiner } from '../url-combiner/url-combiner';
import { DataService } from './data.service';
import { RequestService } from './request.service';
import { HALEndpointService } from '../shared/hal-endpoint.service';
-import { FindAllOptions, GetRequest, MappingCollectionsRequest, PostRequest, RestRequest } from './request.models';
+import {
+ DeleteRequest,
+ FindAllOptions,
+ GetRequest,
+ MappingCollectionsRequest,
+ PostRequest,
+ RestRequest
+} from './request.models';
import { distinctUntilChanged, map } from 'rxjs/operators';
import {
configureRequest,
@@ -69,6 +76,18 @@ export class ItemDataService extends DataService {
);
}
+ public removeMappingFromCollection(itemId: string, collectionId: string): Observable {
+ return this.getMappingCollectionsEndpoint(itemId, collectionId).pipe(
+ isNotEmptyOperator(),
+ distinctUntilChanged(),
+ map((endpointURL: string) => new DeleteRequest(this.requestService.generateRequestId(), endpointURL)),
+ configureRequest(this.requestService),
+ map((request: RestRequest) => request.href),
+ getResponseFromSelflink(this.responseCache),
+ map((responseCacheEntry: ResponseCacheEntry) => responseCacheEntry.response)
+ );
+ }
+
public mapToCollection(itemId: string, collectionId: string): Observable {
return this.getMappingCollectionsEndpoint(itemId, collectionId).pipe(
isNotEmptyOperator(),
@@ -81,7 +100,7 @@ export class ItemDataService extends DataService {
);
}
- public getMappedCollections(itemId: string): Observable> {
+ public getMappedCollections(itemId: string): Observable>> {
const request$ = this.getMappingCollectionsEndpoint(itemId).pipe(
isNotEmptyOperator(),
distinctUntilChanged(),
@@ -95,8 +114,7 @@ export class ItemDataService extends DataService {
const payload$ = responseCache$.pipe(
filterSuccessfulResponses(),
map((entry: ResponseCacheEntry) => entry.response),
- map((response: GenericSuccessResponse) => response.payload),
- ensureArrayHasValue()
+ map((response: GenericSuccessResponse>) => response.payload)
);
return this.rdbService.toRemoteDataObservable(requestEntry$, responseCache$, payload$);
diff --git a/src/app/core/data/mapping-collections-reponse-parsing.service.ts b/src/app/core/data/mapping-collections-reponse-parsing.service.ts
index 1b1ff3368f..0ae014301c 100644
--- a/src/app/core/data/mapping-collections-reponse-parsing.service.ts
+++ b/src/app/core/data/mapping-collections-reponse-parsing.service.ts
@@ -3,6 +3,8 @@ import { ResponseParsingService } from './parsing.service';
import { RestRequest } from './request.models';
import { DSpaceRESTV2Response } from '../dspace-rest-v2/dspace-rest-v2-response.model';
import { ErrorResponse, GenericSuccessResponse, RestResponse } from '../cache/response-cache.models';
+import { PaginatedList } from './paginated-list';
+import { PageInfo } from '../shared/page-info.model';
@Injectable()
export class MappingCollectionsReponseParsingService implements ResponseParsingService {
@@ -11,7 +13,15 @@ export class MappingCollectionsReponseParsingService implements ResponseParsingS
if (payload._embedded && payload._embedded.mappingCollections) {
const mappingCollections = payload._embedded.mappingCollections;
- return new GenericSuccessResponse(mappingCollections, data.statusCode);
+ // TODO: When the API supports it, change this to fetch a paginated list, instead of creating static one
+ // Reason: Pagination is currently not supported on the mappingCollections endpoint
+ const paginatedMappingCollections = new PaginatedList(Object.assign(new PageInfo(), {
+ elementsPerPage: mappingCollections.length,
+ totalElements: mappingCollections.length,
+ totalPages: 1,
+ currentPage: 1
+ }), mappingCollections);
+ return new GenericSuccessResponse(paginatedMappingCollections, data.statusCode);
} else {
return new ErrorResponse(
Object.assign(