Skip to content
Merged
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
11 changes: 11 additions & 0 deletions src/app/core/data/relationship-data.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ describe('RelationshipDataService', () => {
const itemService = jasmine.createSpyObj('itemService', {
findById: (uuid) => createSuccessfulRemoteDataObject(relatedItems.find((relatedItem) => relatedItem.id === uuid)),
findByHref: createSuccessfulRemoteDataObject$(relatedItems[0]),
getIDHrefObs: (uuid: string) => observableOf(`https://demo.dspace.org/server/api/core/items/${uuid}`),
});

const getRequestEntry$ = (successful: boolean) => {
Expand Down Expand Up @@ -244,6 +245,16 @@ describe('RelationshipDataService', () => {
});
});

describe('searchByItemsAndType', () => {
it('should call addDependency for each item to invalidate the request when one of the items is update', () => {
spyOn(service as any, 'addDependency');

service.searchByItemsAndType(relationshipType.id, item.id, relationshipType.leftwardType, ['item-id-1', 'item-id-2']);

expect((service as any).addDependency).toHaveBeenCalledTimes(2);
});
});

describe('resolveMetadataRepresentation', () => {
const parentItem: Item = Object.assign(new Item(), {
id: 'parent-item',
Expand Down
7 changes: 6 additions & 1 deletion src/app/core/data/relationship-data.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -574,13 +574,18 @@ export class RelationshipDataService extends IdentifiableDataService<Relationshi
);
});

return this.searchBy(
const searchRD$: Observable<RemoteData<PaginatedList<Relationship>>> = this.searchBy(
'byItemsAndType',
{
searchParams: searchParams,
},
) as Observable<RemoteData<PaginatedList<Relationship>>>;

arrayOfItemIds.forEach((itemId: string) => {
this.addDependency(searchRD$, this.itemService.getIDHrefObs(encodeURIComponent(itemId)));
});

return searchRD$;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,7 @@ describe('EditItemRelationshipsService', () => {

expect(itemService.invalidateByHref).toHaveBeenCalledWith(currentItem.self);
expect(itemService.invalidateByHref).toHaveBeenCalledWith(relationshipItem1.self);
expect(itemService.invalidateByHref).toHaveBeenCalledWith(relationshipItem2.self);

expect(notificationsService.success).toHaveBeenCalledTimes(1);
});
Expand Down Expand Up @@ -265,6 +266,116 @@ describe('EditItemRelationshipsService', () => {
});
});

describe('isProvidedItemTypeLeftType', () => {
it('should return true if the provided item corresponds to the left type of the relationship', (done) => {
const relationshipType = Object.assign(new RelationshipType(), {
leftType: createSuccessfulRemoteDataObject$({ id: 'leftType' }),
rightType: createSuccessfulRemoteDataObject$({ id: 'rightType' }),
});
const itemType = Object.assign(new ItemType(), { id: 'leftType' } );
const item = Object.assign(new Item(), { uuid: 'item-uuid' });

const result = service.isProvidedItemTypeLeftType(relationshipType, itemType, item);
result.subscribe((resultValue) => {
expect(resultValue).toBeTrue();
done();
});
});

it('should return false if the provided item corresponds to the right type of the relationship', (done) => {
const relationshipType = Object.assign(new RelationshipType(), {
leftType: createSuccessfulRemoteDataObject$({ id: 'leftType' }),
rightType: createSuccessfulRemoteDataObject$({ id: 'rightType' }),
});
const itemType = Object.assign(new ItemType(), { id: 'rightType' } );
const item = Object.assign(new Item(), { uuid: 'item-uuid' });

const result = service.isProvidedItemTypeLeftType(relationshipType, itemType, item);
result.subscribe((resultValue) => {
expect(resultValue).toBeFalse();
done();
});
});

it('should return undefined if the provided item corresponds does not match any of the relationship types', (done) => {
const relationshipType = Object.assign(new RelationshipType(), {
leftType: createSuccessfulRemoteDataObject$({ id: 'leftType' }),
rightType: createSuccessfulRemoteDataObject$({ id: 'rightType' }),
});
const itemType = Object.assign(new ItemType(), { id: 'something-else' } );
const item = Object.assign(new Item(), { uuid: 'item-uuid' });

const result = service.isProvidedItemTypeLeftType(relationshipType, itemType, item);
result.subscribe((resultValue) => {
expect(resultValue).toBeUndefined();
done();
});
});
});

describe('relationshipMatchesBothSameTypes', () => {
it('should return true if both left and right type of the relationship type are the same and match the provided itemtype', (done) => {
const relationshipType = Object.assign(new RelationshipType(), {
leftType: createSuccessfulRemoteDataObject$({ id: 'sameType' }),
rightType: createSuccessfulRemoteDataObject$({ id:'sameType' }),
leftwardType: 'isDepartmentOfDivision',
rightwardType: 'isDivisionOfDepartment',
});
const itemType = Object.assign(new ItemType(), { id: 'sameType' } );

const result = service.shouldDisplayBothRelationshipSides(relationshipType, itemType);
result.subscribe((resultValue) => {
expect(resultValue).toBeTrue();
done();
});
});
it('should return false if both left and right type of the relationship type are the same and match the provided itemtype but the leftwardType & rightwardType is identical', (done) => {
const relationshipType = Object.assign(new RelationshipType(), {
leftType: createSuccessfulRemoteDataObject$({ id: 'sameType' }),
rightType: createSuccessfulRemoteDataObject$({ id: 'sameType' }),
leftwardType: 'isOrgUnitOfOrgUnit',
rightwardType: 'isOrgUnitOfOrgUnit',
});
const itemType = Object.assign(new ItemType(), { id: 'sameType' });

const result = service.shouldDisplayBothRelationshipSides(relationshipType, itemType);
result.subscribe((resultValue) => {
expect(resultValue).toBeFalse();
done();
});
});
it('should return false if both left and right type of the relationship type are the same and do not match the provided itemtype', (done) => {
const relationshipType = Object.assign(new RelationshipType(), {
leftType: createSuccessfulRemoteDataObject$({ id: 'sameType' }),
rightType: createSuccessfulRemoteDataObject$({ id: 'sameType' }),
leftwardType: 'isDepartmentOfDivision',
rightwardType: 'isDivisionOfDepartment',
});
const itemType = Object.assign(new ItemType(), { id: 'something-else' } );

const result = service.shouldDisplayBothRelationshipSides(relationshipType, itemType);
result.subscribe((resultValue) => {
expect(resultValue).toBeFalse();
done();
});
});
it('should return false if both left and right type of the relationship type are different', (done) => {
const relationshipType = Object.assign(new RelationshipType(), {
leftType: createSuccessfulRemoteDataObject$({ id: 'leftType' }),
rightType: createSuccessfulRemoteDataObject$({ id: 'rightType' }),
leftwardType: 'isAuthorOfPublication',
rightwardType: 'isPublicationOfAuthor',
});
const itemType = Object.assign(new ItemType(), { id: 'leftType' } );

const result = service.shouldDisplayBothRelationshipSides(relationshipType, itemType);
result.subscribe((resultValue) => {
expect(resultValue).toBeFalse();
done();
});
});
});

describe('displayNotifications', () => {
it('should show one success notification when multiple requests succeeded', () => {
service.displayNotifications([
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
import { TranslateService } from '@ngx-translate/core';
import {
BehaviorSubject,
combineLatest as observableCombineLatest,
EMPTY,
Observable,
Subscription,
Expand All @@ -28,8 +29,14 @@ import { ObjectUpdatesService } from '../../../core/data/object-updates/object-u
import { RelationshipDataService } from '../../../core/data/relationship-data.service';
import { RemoteData } from '../../../core/data/remote-data';
import { Item } from '../../../core/shared/item.model';
import { ItemType } from '../../../core/shared/item-relationships/item-type.model';
import { Relationship } from '../../../core/shared/item-relationships/relationship.model';
import { RelationshipType } from '../../../core/shared/item-relationships/relationship-type.model';
import { NoContent } from '../../../core/shared/NoContent.model';
import {
getFirstSucceededRemoteData,
getRemoteDataPayload,
} from '../../../core/shared/operators';
import { hasValue } from '../../../shared/empty.util';
import { NotificationsService } from '../../../shared/notifications/notifications.service';

Expand Down Expand Up @@ -70,7 +77,17 @@ export class EditItemRelationshipsService {
// process each update one by one, while waiting for the previous to finish
concatMap((update: FieldUpdate) => {
if (update.changeType === FieldChangeType.REMOVE) {
return this.deleteRelationship(update.field as DeleteRelationship).pipe(take(1));
return this.deleteRelationship(update.field as DeleteRelationship).pipe(
take(1),
switchMap((deleteRD: RemoteData<NoContent>) => {
if (deleteRD.hasSucceeded) {
return this.itemService.invalidateByHref((update.field as DeleteRelationship).relatedItem._links.self.href).pipe(
map(() => deleteRD),
);
}
return [deleteRD];
}),
);
} else if (update.changeType === FieldChangeType.ADD) {
return this.addRelationship(update.field as RelationshipIdentifiable).pipe(
take(1),
Expand Down Expand Up @@ -181,6 +198,55 @@ export class EditItemRelationshipsService {
}
}

isProvidedItemTypeLeftType(relationshipType: RelationshipType, itemType: ItemType, item: Item): Observable<boolean> {
return this.getRelationshipLeftAndRightType(relationshipType).pipe(
map(([leftType, rightType]: [ItemType, ItemType]) => {
if (leftType.id === itemType.id) {
return true;
}

if (rightType.id === itemType.id) {
return false;
}

// should never happen...
console.warn(`The item ${item.uuid} is not on the right or the left side of relationship type ${relationshipType.uuid}`);
return undefined;
}),
);
}

/**
* Whether both side of the relationship need to be displayed on the edit relationship page or not.
*
* @param relationshipType The relationship type
* @param itemType The item type
*/
shouldDisplayBothRelationshipSides(relationshipType: RelationshipType, itemType: ItemType): Observable<boolean> {
return this.getRelationshipLeftAndRightType(relationshipType).pipe(
map(([leftType, rightType]: [ItemType, ItemType]) => {
return leftType.id === itemType.id && rightType.id === itemType.id && relationshipType.leftwardType !== relationshipType.rightwardType;
}),
);
}

protected getRelationshipLeftAndRightType(relationshipType: RelationshipType): Observable<[ItemType, ItemType]> {
const leftType$: Observable<ItemType> = relationshipType.leftType.pipe(
getFirstSucceededRemoteData(),
getRemoteDataPayload(),
);

const rightType$: Observable<ItemType> = relationshipType.rightType.pipe(
getFirstSucceededRemoteData(),
getRemoteDataPayload(),
);

return observableCombineLatest([
leftType$,
rightType$,
]);
}



/**
Expand All @@ -197,6 +263,5 @@ export class EditItemRelationshipsService {
*/
getNotificationContent(key: string): string {
return this.translateService.instant(this.notificationsPrefix + key + '.content');

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<ng-container *ngIf="shouldDisplayBothRelationshipSides$ | async">
<ds-edit-relationship-list
[url]="url"
[item]="item"
[itemType]="itemType"
[relationshipType]="relationshipType"
[hasChanges]="hasChanges"
[currentItemIsLeftItem$]="isLeftItem$"
class="d-block mb-4"
></ds-edit-relationship-list>
<ds-edit-relationship-list
[url]="url"
[item]="item"
[itemType]="itemType"
[relationshipType]="relationshipType"
[hasChanges]="hasChanges"
[currentItemIsLeftItem$]="isRightItem$"
></ds-edit-relationship-list>
</ng-container>

<ng-container *ngIf="(shouldDisplayBothRelationshipSides$ | async) === false">
<ds-edit-relationship-list
[url]="url"
[item]="item"
[itemType]="itemType"
[relationshipType]="relationshipType"
[hasChanges]="hasChanges"
[currentItemIsLeftItem$]="currentItemIsLeftItem$"
></ds-edit-relationship-list>
</ng-container>

Loading