Skip to content

Commit 06665dc

Browse files
YanaDePauwalexandrevryghem
authored andcommitted
115284: Fix issue with same type relationships
1 parent 3fbc3dc commit 06665dc

18 files changed

Lines changed: 463 additions & 37 deletions

src/app/item-page/edit-item-page/item-relationships/edit-item-relationships.service.spec.ts

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,95 @@ describe('EditItemRelationshipsService', () => {
265265
});
266266
});
267267

268+
describe('isProvidedItemTypeLeftType', () => {
269+
it('should return true if the provided item corresponds to the left type of the relationship', (done) => {
270+
const relationshipType = Object.assign(new RelationshipType(), {
271+
leftType: createSuccessfulRemoteDataObject$({ id: 'leftType' }),
272+
rightType: createSuccessfulRemoteDataObject$({ id: 'rightType' }),
273+
});
274+
const itemType = Object.assign(new ItemType(), { id: 'leftType' } );
275+
const item = Object.assign(new Item(), { uuid: 'item-uuid' });
276+
277+
const result = service.isProvidedItemTypeLeftType(relationshipType, itemType, item);
278+
result.subscribe((resultValue) => {
279+
expect(resultValue).toBeTrue();
280+
done();
281+
});
282+
});
283+
284+
it('should return false if the provided item corresponds to the right type of the relationship', (done) => {
285+
const relationshipType = Object.assign(new RelationshipType(), {
286+
leftType: createSuccessfulRemoteDataObject$({ id: 'leftType' }),
287+
rightType: createSuccessfulRemoteDataObject$({ id: 'rightType' }),
288+
});
289+
const itemType = Object.assign(new ItemType(), { id: 'rightType' } );
290+
const item = Object.assign(new Item(), { uuid: 'item-uuid' });
291+
292+
const result = service.isProvidedItemTypeLeftType(relationshipType, itemType, item);
293+
result.subscribe((resultValue) => {
294+
expect(resultValue).toBeFalse();
295+
done();
296+
});
297+
});
298+
299+
it('should return undefined if the provided item corresponds does not match any of the relationship types', (done) => {
300+
const relationshipType = Object.assign(new RelationshipType(), {
301+
leftType: createSuccessfulRemoteDataObject$({ id: 'leftType' }),
302+
rightType: createSuccessfulRemoteDataObject$({ id: 'rightType' }),
303+
});
304+
const itemType = Object.assign(new ItemType(), { id: 'something-else' } );
305+
const item = Object.assign(new Item(), { uuid: 'item-uuid' });
306+
307+
const result = service.isProvidedItemTypeLeftType(relationshipType, itemType, item);
308+
result.subscribe((resultValue) => {
309+
expect(resultValue).toBeUndefined();
310+
done();
311+
});
312+
});
313+
});
314+
315+
describe('relationshipMatchesBothSameTypes', () => {
316+
it('should return true if both left and right type of the relationship type are the same and match the provided itemtype', (done) => {
317+
const relationshipType = Object.assign(new RelationshipType(), {
318+
leftType: createSuccessfulRemoteDataObject$({ id: 'sameType' }),
319+
rightType: createSuccessfulRemoteDataObject$({ id:'sameType' }),
320+
});
321+
const itemType = Object.assign(new ItemType(), { id: 'sameType' } );
322+
323+
const result = service.relationshipMatchesBothSameTypes(relationshipType, itemType);
324+
result.subscribe((resultValue) => {
325+
expect(resultValue).toBeTrue();
326+
done();
327+
});
328+
});
329+
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) => {
330+
const relationshipType = Object.assign(new RelationshipType(), {
331+
leftType: createSuccessfulRemoteDataObject$({ id: 'sameType' }),
332+
rightType: createSuccessfulRemoteDataObject$({ id: 'sameType' }),
333+
});
334+
const itemType = Object.assign(new ItemType(), { id: 'something-else' } );
335+
336+
const result = service.relationshipMatchesBothSameTypes(relationshipType, itemType);
337+
result.subscribe((resultValue) => {
338+
expect(resultValue).toBeFalse();
339+
done();
340+
});
341+
});
342+
it('should return false if both left and right type of the relationship type are different', (done) => {
343+
const relationshipType = Object.assign(new RelationshipType(), {
344+
leftType: createSuccessfulRemoteDataObject$({ id: 'leftType' }),
345+
rightType: createSuccessfulRemoteDataObject$({ id: 'rightType' }),
346+
});
347+
const itemType = Object.assign(new ItemType(), { id: 'leftType' } );
348+
349+
const result = service.relationshipMatchesBothSameTypes(relationshipType, itemType);
350+
result.subscribe((resultValue) => {
351+
expect(resultValue).toBeFalse();
352+
done();
353+
});
354+
});
355+
});
356+
268357
describe('displayNotifications', () => {
269358
it('should show one success notification when multiple requests succeeded', () => {
270359
service.displayNotifications([

src/app/item-page/edit-item-page/item-relationships/edit-item-relationships.service.ts

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
33
import { TranslateService } from '@ngx-translate/core';
44
import {
55
BehaviorSubject,
6+
combineLatest as observableCombineLatest,
67
EMPTY,
78
Observable,
89
Subscription,
@@ -28,8 +29,14 @@ import { ObjectUpdatesService } from '../../../core/data/object-updates/object-u
2829
import { RelationshipDataService } from '../../../core/data/relationship-data.service';
2930
import { RemoteData } from '../../../core/data/remote-data';
3031
import { Item } from '../../../core/shared/item.model';
32+
import { ItemType } from '../../../core/shared/item-relationships/item-type.model';
3133
import { Relationship } from '../../../core/shared/item-relationships/relationship.model';
34+
import { RelationshipType } from '../../../core/shared/item-relationships/relationship-type.model';
3235
import { NoContent } from '../../../core/shared/NoContent.model';
36+
import {
37+
getFirstSucceededRemoteData,
38+
getRemoteDataPayload,
39+
} from '../../../core/shared/operators';
3340
import { hasValue } from '../../../shared/empty.util';
3441
import { NotificationsService } from '../../../shared/notifications/notifications.service';
3542

@@ -181,6 +188,49 @@ export class EditItemRelationshipsService {
181188
}
182189
}
183190

191+
isProvidedItemTypeLeftType(relationshipType: RelationshipType, itemType: ItemType, item: Item): Observable<boolean> {
192+
return this.getRelationshipLeftAndRightType(relationshipType).pipe(
193+
map(([leftType, rightType]: [ItemType, ItemType]) => {
194+
if (leftType.id === itemType.id) {
195+
return true;
196+
}
197+
198+
if (rightType.id === itemType.id) {
199+
return false;
200+
}
201+
202+
// should never happen...
203+
console.warn(`The item ${item.uuid} is not on the right or the left side of relationship type ${relationshipType.uuid}`);
204+
return undefined;
205+
}),
206+
);
207+
}
208+
209+
relationshipMatchesBothSameTypes(relationshipType: RelationshipType, itemType: ItemType): Observable<boolean> {
210+
return this.getRelationshipLeftAndRightType(relationshipType).pipe(
211+
map(([leftType, rightType]: [ItemType, ItemType]) => {
212+
return leftType.id === itemType.id && rightType.id === itemType.id;
213+
}),
214+
);
215+
}
216+
217+
protected getRelationshipLeftAndRightType(relationshipType: RelationshipType): Observable<[ItemType, ItemType]> {
218+
const leftType$: Observable<ItemType> = relationshipType.leftType.pipe(
219+
getFirstSucceededRemoteData(),
220+
getRemoteDataPayload(),
221+
);
222+
223+
const rightType$: Observable<ItemType> = relationshipType.rightType.pipe(
224+
getFirstSucceededRemoteData(),
225+
getRemoteDataPayload(),
226+
);
227+
228+
return observableCombineLatest([
229+
leftType$,
230+
rightType$,
231+
]);
232+
}
233+
184234

185235

186236
/**
@@ -197,6 +247,5 @@ export class EditItemRelationshipsService {
197247
*/
198248
getNotificationContent(key: string): string {
199249
return this.translateService.instant(this.notificationsPrefix + key + '.content');
200-
201250
}
202251
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<ng-container *ngIf="bothItemsMatchType$ | async">
2+
<ds-edit-relationship-list
3+
[url]="url"
4+
[item]="item"
5+
[itemType]="itemType"
6+
[relationshipType]="relationshipType"
7+
[hasChanges]="hasChanges"
8+
[currentItemIsLeftItem$]="isLeftItem$"
9+
></ds-edit-relationship-list>
10+
<ds-edit-relationship-list
11+
[url]="url"
12+
[item]="item"
13+
[itemType]="itemType"
14+
[relationshipType]="relationshipType"
15+
[hasChanges]="hasChanges"
16+
[currentItemIsLeftItem$]="isRightItem$"
17+
></ds-edit-relationship-list>
18+
</ng-container>
19+
20+
<ng-container *ngIf="(bothItemsMatchType$ | async) === false">
21+
<ds-edit-relationship-list
22+
[url]="url"
23+
[item]="item"
24+
[itemType]="itemType"
25+
[relationshipType]="relationshipType"
26+
[hasChanges]="hasChanges"
27+
[currentItemIsLeftItem$]="currentItemIsLeftItem$"
28+
></ds-edit-relationship-list>
29+
</ng-container>
30+

src/app/item-page/edit-item-page/item-relationships/edit-relationship-list-wrapper/edit-relationship-list-wrapper.component.scss

Whitespace-only changes.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
2+
import {
3+
ComponentFixture,
4+
TestBed,
5+
waitForAsync,
6+
} from '@angular/core/testing';
7+
import { By } from '@angular/platform-browser';
8+
import { of as observableOf } from 'rxjs';
9+
10+
import { Item } from '../../../../core/shared/item.model';
11+
import { ItemType } from '../../../../core/shared/item-relationships/item-type.model';
12+
import { RelationshipType } from '../../../../core/shared/item-relationships/relationship-type.model';
13+
import { createSuccessfulRemoteDataObject$ } from '../../../../shared/remote-data.utils';
14+
import { EditItemRelationshipsService } from '../edit-item-relationships.service';
15+
import { EditRelationshipListComponent } from '../edit-relationship-list/edit-relationship-list.component';
16+
import { EditRelationshipListWrapperComponent } from './edit-relationship-list-wrapper.component';
17+
18+
describe('EditRelationshipListWrapperComponent', () => {
19+
let editItemRelationshipsService: EditItemRelationshipsService;
20+
let comp: EditRelationshipListWrapperComponent;
21+
let fixture: ComponentFixture<EditRelationshipListWrapperComponent>;
22+
23+
const leftType = Object.assign(new ItemType(), { id: 'leftType', label: 'leftTypeString' });
24+
const rightType = Object.assign(new ItemType(), { id: 'rightType', label: 'rightTypeString' });
25+
26+
const relationshipType = Object.assign(new RelationshipType(), {
27+
id: '1',
28+
leftMaxCardinality: null,
29+
leftMinCardinality: 0,
30+
leftType: createSuccessfulRemoteDataObject$(leftType),
31+
leftwardType: 'isOrgUnitOfOrgUnit',
32+
rightMaxCardinality: null,
33+
rightMinCardinality: 0,
34+
rightType: createSuccessfulRemoteDataObject$(rightType),
35+
rightwardType: 'isOrgUnitOfOrgUnit',
36+
uuid: 'relationshiptype-1',
37+
});
38+
39+
const item = Object.assign(new Item(), { uuid: 'item-uuid' });
40+
41+
beforeEach(waitForAsync(() => {
42+
43+
editItemRelationshipsService = jasmine.createSpyObj('editItemRelationshipsService', {
44+
isProvidedItemTypeLeftType: observableOf(true),
45+
relationshipMatchesBothSameTypes: observableOf(false),
46+
});
47+
48+
49+
TestBed.configureTestingModule({
50+
imports: [
51+
EditRelationshipListWrapperComponent,
52+
],
53+
providers: [
54+
{ provide: EditItemRelationshipsService, useValue: editItemRelationshipsService },
55+
],
56+
schemas: [
57+
CUSTOM_ELEMENTS_SCHEMA,
58+
],
59+
}).overrideComponent(EditRelationshipListWrapperComponent, {
60+
remove: {
61+
imports: [
62+
EditRelationshipListComponent,
63+
],
64+
},
65+
}).compileComponents();
66+
67+
}));
68+
69+
beforeEach(() => {
70+
fixture = TestBed.createComponent(EditRelationshipListWrapperComponent);
71+
comp = fixture.componentInstance;
72+
comp.relationshipType = relationshipType;
73+
comp.itemType = leftType;
74+
comp.item = item;
75+
76+
fixture.detectChanges();
77+
});
78+
79+
describe('onInit', () => {
80+
it('should render the component', () => {
81+
expect(comp).toBeTruthy();
82+
});
83+
it('should set currentItemIsLeftItem$ and bothItemsMatchType$ based on the provided relationshipType, itemType and item', () => {
84+
expect(editItemRelationshipsService.isProvidedItemTypeLeftType).toHaveBeenCalledWith(relationshipType, leftType, item);
85+
expect(editItemRelationshipsService.relationshipMatchesBothSameTypes).toHaveBeenCalledWith(relationshipType, leftType);
86+
87+
expect(comp.currentItemIsLeftItem$.getValue()).toEqual(true);
88+
expect(comp.bothItemsMatchType$.getValue()).toEqual(false);
89+
});
90+
});
91+
92+
describe('when the current item is left', () => {
93+
it('should render one relationship list section', () => {
94+
const relationshipLists = fixture.debugElement.queryAll(By.css('ds-edit-relationship-list'));
95+
expect(relationshipLists.length).toEqual(1);
96+
});
97+
});
98+
99+
describe('when the current item is right', () => {
100+
it('should render one relationship list section', () => {
101+
(editItemRelationshipsService.isProvidedItemTypeLeftType as jasmine.Spy).and.returnValue(observableOf(false));
102+
comp.ngOnInit();
103+
fixture.detectChanges();
104+
105+
const relationshipLists = fixture.debugElement.queryAll(By.css('ds-edit-relationship-list'));
106+
expect(relationshipLists.length).toEqual(1);
107+
});
108+
});
109+
110+
describe('when the current item is both left and right', () => {
111+
it('should render two relationship list sections', () => {
112+
(editItemRelationshipsService.relationshipMatchesBothSameTypes as jasmine.Spy).and.returnValue(observableOf(true));
113+
comp.ngOnInit();
114+
fixture.detectChanges();
115+
116+
const relationshipLists = fixture.debugElement.queryAll(By.css('ds-edit-relationship-list'));
117+
expect(relationshipLists.length).toEqual(2);
118+
});
119+
});
120+
121+
});

0 commit comments

Comments
 (0)