diff --git a/src/app/core/data/relationship-type.service.spec.ts b/src/app/core/data/relationship-type.service.spec.ts index 8a4d31bd6c..12ad82e374 100644 --- a/src/app/core/data/relationship-type.service.spec.ts +++ b/src/app/core/data/relationship-type.service.spec.ts @@ -10,41 +10,59 @@ import { RelationshipTypeService } from './relationship-type.service'; import { of as observableOf } from 'rxjs'; import { ItemType } from '../shared/item-relationships/item-type.model'; -fdescribe('RelationshipTypeService', () => { +describe('RelationshipTypeService', () => { let service: RelationshipTypeService; - let requestService: RequestService; + let requestService : RequestService; + let restEndpointURL; + let halService: any; + let publicationTypeString; + let personTypeString; + let orgUnitTypeString; + let publicationType; + let personType; + let orgUnitType; - const restEndpointURL = 'https://rest.api/relationshiptypes'; - const halService: any = new HALEndpointServiceStub(restEndpointURL); - const publicationTypeString = 'Publication'; - const personTypeString = 'Person'; - const orgUnitTypeString = 'OrgUnit'; - const publicationType = Object.assign(new ItemType(), {label: publicationTypeString}); - const personType = Object.assign(new ItemType(), {label: personTypeString}); - const orgUnitType = Object.assign(new ItemType(), {label: orgUnitTypeString}); - - const relationshipType1 = Object.assign(new RelationshipType(), { - id: '1', - uuid: '1', - leftwardType: 'isAuthorOfPublication', - rightwardType: 'isPublicationOfAuthor', - leftType: createSuccessfulRemoteDataObject$(publicationType), - rightType: createSuccessfulRemoteDataObject$(personType) - }); + let relationshipType1; - const relationshipType2 = Object.assign(new RelationshipType(), { - id: '2', - uuid: '2', - leftwardType: 'isOrgUnitOfPublication', - rightwardType: 'isPublicationOfOrgUnit', - leftType: createSuccessfulRemoteDataObject$(publicationType), - rightType: createSuccessfulRemoteDataObject$(orgUnitType) - }); + let relationshipType2; - const buildList = createSuccessfulRemoteDataObject(new PaginatedList(new PageInfo(), [relationshipType1, relationshipType2])); - const rdbService = getMockRemoteDataBuildService(undefined, observableOf(buildList)); + let buildList; + let rdbService; + function init() { + restEndpointURL = 'https://rest.api/relationshiptypes'; + halService = new HALEndpointServiceStub(restEndpointURL); + publicationTypeString = 'Publication'; + personTypeString = 'Person'; + orgUnitTypeString = 'OrgUnit'; + publicationType = Object.assign(new ItemType(), {label: publicationTypeString}); + personType = Object.assign(new ItemType(), {label: personTypeString}); + orgUnitType = Object.assign(new ItemType(), {label: orgUnitTypeString}); + + relationshipType1 = Object.assign(new RelationshipType(), { + id: '1', + uuid: '1', + leftwardType: 'isAuthorOfPublication', + rightwardType: 'isPublicationOfAuthor', + leftType: createSuccessfulRemoteDataObject$(publicationType), + rightType: createSuccessfulRemoteDataObject$(personType) + }); + + + relationshipType2 = Object.assign(new RelationshipType(), { + id: '2', + uuid: '2', + leftwardType: 'isOrgUnitOfPublication', + rightwardType: 'isPublicationOfOrgUnit', + leftType: createSuccessfulRemoteDataObject$(publicationType), + rightType: createSuccessfulRemoteDataObject$(orgUnitType) + }); + + buildList = createSuccessfulRemoteDataObject(new PaginatedList(new PageInfo(), [relationshipType1, relationshipType2])); + rdbService = getMockRemoteDataBuildService(undefined, observableOf(buildList)); + + } function initTestService() { return new RelationshipTypeService( requestService, @@ -54,6 +72,7 @@ fdescribe('RelationshipTypeService', () => { } beforeEach(() => { + init(); requestService = getMockRequestService(); service = initTestService(); }); diff --git a/src/app/core/data/relationship.service.ts b/src/app/core/data/relationship.service.ts index 74723bfc3d..b57b0b924e 100644 --- a/src/app/core/data/relationship.service.ts +++ b/src/app/core/data/relationship.service.ts @@ -137,7 +137,7 @@ export class RelationshipService extends DataService { this.requestService.hasByHrefObservable(item.self) ).pipe( filter(([existsInOC, existsInRC]) => !existsInOC && !existsInRC), - tap(t => console.log(t)), + take(1), switchMap(() => this.itemService.findByHref(item.self).pipe(take(1))) ).subscribe(); } @@ -330,7 +330,6 @@ export class RelationshipService extends DataService { }), // skipWhile((relationshipRD: RemoteData) => !relationshipRD.isSuccessful) tap((relationshipRD: RemoteData) => { - console.log(relationshipRD.payload); if (relationshipRD.hasSucceeded) { this.removeRelationshipItemsFromCache(item1); this.removeRelationshipItemsFromCache(item2); diff --git a/src/app/entity-groups/research-entities/research-entities.module.ts b/src/app/entity-groups/research-entities/research-entities.module.ts index 1ac4828bb9..86c2a375da 100644 --- a/src/app/entity-groups/research-entities/research-entities.module.ts +++ b/src/app/entity-groups/research-entities/research-entities.module.ts @@ -22,7 +22,9 @@ import { PersonItemMetadataListElementComponent } from './metadata-representatio import { OrgUnitItemMetadataListElementComponent } from './metadata-representations/org-unit/org-unit-item-metadata-list-element.component'; import { PersonSearchResultListSubmissionElementComponent } from './submission/item-list-elements/person/person-search-result-list-submission-element.component'; import { PersonInputSuggestionsComponent } from './submission/item-list-elements/person/person-suggestions/person-input-suggestions.component'; -import { NameVariantModalComponent } from './submission/item-list-elements/person/name-variant-modal/name-variant-modal.component'; +import { NameVariantModalComponent } from './submission/name-variant-modal/name-variant-modal.component'; +import { OrgUnitInputSuggestionsComponent } from './submission/item-list-elements/org-unit/org-unit-suggestions/org-unit-input-suggestions.component'; +import { OrgUnitSearchResultListSubmissionElementComponent } from './submission/item-list-elements/org-unit/org-unit-search-result-list-submission-element.component'; const ENTRY_COMPONENTS = [ OrgUnitComponent, @@ -44,7 +46,9 @@ const ENTRY_COMPONENTS = [ ProjectSearchResultGridElementComponent, PersonSearchResultListSubmissionElementComponent, PersonInputSuggestionsComponent, - NameVariantModalComponent + NameVariantModalComponent, + OrgUnitSearchResultListSubmissionElementComponent, + OrgUnitInputSuggestionsComponent ]; @NgModule({ diff --git a/src/app/entity-groups/research-entities/submission/item-list-elements/org-unit/org-unit-search-result-list-submission-element.component.html b/src/app/entity-groups/research-entities/submission/item-list-elements/org-unit/org-unit-search-result-list-submission-element.component.html new file mode 100644 index 0000000000..723ce0adbe --- /dev/null +++ b/src/app/entity-groups/research-entities/submission/item-list-elements/org-unit/org-unit-search-result-list-submission-element.component.html @@ -0,0 +1,20 @@ +
+
+ +
+
+ + + + + , + + + + + +
+
diff --git a/src/app/entity-groups/research-entities/submission/item-list-elements/org-unit/org-unit-search-result-list-submission-element.component.scss b/src/app/entity-groups/research-entities/submission/item-list-elements/org-unit/org-unit-search-result-list-submission-element.component.scss new file mode 100644 index 0000000000..8fc6d2138d --- /dev/null +++ b/src/app/entity-groups/research-entities/submission/item-list-elements/org-unit/org-unit-search-result-list-submission-element.component.scss @@ -0,0 +1,7 @@ +@import '../../../../../../styles/variables'; + +$submission-relationship-thumbnail-width: 80px; + +.person-thumbnail { + width: $submission-relationship-thumbnail-width; +} \ No newline at end of file diff --git a/src/app/entity-groups/research-entities/submission/item-list-elements/org-unit/org-unit-search-result-list-submission-element.component.spec.ts b/src/app/entity-groups/research-entities/submission/item-list-elements/org-unit/org-unit-search-result-list-submission-element.component.spec.ts new file mode 100644 index 0000000000..f94154e870 --- /dev/null +++ b/src/app/entity-groups/research-entities/submission/item-list-elements/org-unit/org-unit-search-result-list-submission-element.component.spec.ts @@ -0,0 +1,125 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core'; +import { By } from '@angular/platform-browser'; +import { of as observableOf } from 'rxjs'; +import { ItemSearchResult } from '../../../../../shared/object-collection/shared/item-search-result.model'; +import { OrgUnitSearchResultListSubmissionElementComponent } from './org-unit-search-result-list-submission-element.component'; +import { Item } from '../../../../../core/shared/item.model'; +import { TruncatePipe } from '../../../../../shared/utils/truncate.pipe'; +import { TruncatableService } from '../../../../../shared/truncatable/truncatable.service'; +import { RelationshipService } from '../../../../../core/data/relationship.service'; +import { NotificationsService } from '../../../../../shared/notifications/notifications.service'; +import { TranslateService } from '@ngx-translate/core'; +import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; +import { ItemDataService } from '../../../../../core/data/item-data.service'; +import { SelectableListService } from '../../../../../shared/object-list/selectable-list/selectable-list.service'; +import { Store } from '@ngrx/store'; +import { createSuccessfulRemoteDataObject$ } from '../../../../../shared/testing/utils'; +import { PaginatedList } from '../../../../../core/data/paginated-list'; + +let personListElementComponent: OrgUnitSearchResultListSubmissionElementComponent; +let fixture: ComponentFixture; + +let mockItemWithMetadata: ItemSearchResult; +let mockItemWithoutMetadata: ItemSearchResult; + +let nameVariant; +let mockRelationshipService; + + +function init() { + mockItemWithMetadata = Object.assign( + new ItemSearchResult(), + { + indexableObject: Object.assign(new Item(), { + bundles: createSuccessfulRemoteDataObject$(new PaginatedList(undefined, [])), + metadata: { + 'dc.title': [ + { + language: 'en_US', + value: 'This is just another title' + } + ], + 'person.jobTitle': [ + { + language: 'en_US', + value: 'Developer' + } + ] + } + }) + }); + mockItemWithoutMetadata = Object.assign( + new ItemSearchResult(), + { + indexableObject: Object.assign(new Item(), { + bundles: createSuccessfulRemoteDataObject$(new PaginatedList(undefined, [])), + metadata: { + 'dc.title': [ + { + language: 'en_US', + value: 'This is just another title' + } + ] + } + }) + }); + + nameVariant = "Doe J."; + mockRelationshipService = { + getNameVariant: () => observableOf(nameVariant) + }; +} + +describe('PersonSearchResultListElementSubmissionComponent', () => { + beforeEach(async(() => { + init(); + TestBed.configureTestingModule({ + declarations: [OrgUnitSearchResultListSubmissionElementComponent, TruncatePipe], + providers: [ + { provide: TruncatableService, useValue: {} }, + { provide: RelationshipService, useValue: mockRelationshipService }, + { provide: NotificationsService, useValue: {} }, + { provide: TranslateService, useValue: {} }, + { provide: NgbModal, useValue: {} }, + { provide: ItemDataService, useValue: {} }, + { provide: SelectableListService, useValue: {} }, + { provide: Store, useValue: {}} + ], + + schemas: [NO_ERRORS_SCHEMA] + }).overrideComponent(OrgUnitSearchResultListSubmissionElementComponent, { + set: { changeDetection: ChangeDetectionStrategy.Default } + }).compileComponents(); + })); + + beforeEach(async(() => { + fixture = TestBed.createComponent(OrgUnitSearchResultListSubmissionElementComponent); + personListElementComponent = fixture.componentInstance; + + })); + + describe('When the item has a job title', () => { + beforeEach(() => { + personListElementComponent.object = mockItemWithMetadata; + fixture.detectChanges(); + }); + + it('should show the job title span', () => { + const jobTitleField = fixture.debugElement.query(By.css('span.item-list-job-title')); + expect(jobTitleField).not.toBeNull(); + }); + }); + + describe('When the item has no job title', () => { + beforeEach(() => { + personListElementComponent.object = mockItemWithoutMetadata; + fixture.detectChanges(); + }); + + it('should not show the job title span', () => { + const jobTitleField = fixture.debugElement.query(By.css('span.item-list-job-title')); + expect(jobTitleField).toBeNull(); + }); + }); +}); diff --git a/src/app/entity-groups/research-entities/submission/item-list-elements/org-unit/org-unit-search-result-list-submission-element.component.ts b/src/app/entity-groups/research-entities/submission/item-list-elements/org-unit/org-unit-search-result-list-submission-element.component.ts new file mode 100644 index 0000000000..7f4e7295b9 --- /dev/null +++ b/src/app/entity-groups/research-entities/submission/item-list-elements/org-unit/org-unit-search-result-list-submission-element.component.ts @@ -0,0 +1,98 @@ +import { Component, OnInit } from '@angular/core'; +import { SearchResultListElementComponent } from '../../../../../shared/object-list/search-result-list-element/search-result-list-element.component'; +import { ItemSearchResult } from '../../../../../shared/object-collection/shared/item-search-result.model'; +import { listableObjectComponent } from '../../../../../shared/object-collection/shared/listable-object/listable-object.decorator'; +import { ViewMode } from '../../../../../core/shared/view-mode.model'; +import { Item } from '../../../../../core/shared/item.model'; +import { Context } from '../../../../../core/shared/context.model'; +import { RelationshipService } from '../../../../../core/data/relationship.service'; +import { TruncatableService } from '../../../../../shared/truncatable/truncatable.service'; +import { take } from 'rxjs/operators'; +import { NotificationsService } from '../../../../../shared/notifications/notifications.service'; +import { TranslateService } from '@ngx-translate/core'; +import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; +import { MetadataValue } from '../../../../../core/shared/metadata.models'; +import { ItemDataService } from '../../../../../core/data/item-data.service'; +import { SelectableListService } from '../../../../../shared/object-list/selectable-list/selectable-list.service'; +import { NameVariantModalComponent } from '../../name-variant-modal/name-variant-modal.component'; + +@listableObjectComponent('OrgUnitSearchResult', ViewMode.ListElement, Context.Workspace) +@Component({ + selector: 'ds-person-search-result-list-submission-element', + styleUrls: ['./org-unit-search-result-list-submission-element.component.scss'], + templateUrl: './org-unit-search-result-list-submission-element.component.html' +}) + +/** + * The component for displaying a list element for an item search result of the type Person + */ +export class OrgUnitSearchResultListSubmissionElementComponent extends SearchResultListElementComponent implements OnInit { + allSuggestions: string[]; + selectedName: string; + alternativeField = 'dc.title.alternative'; + + constructor(protected truncatableService: TruncatableService, + private relationshipService: RelationshipService, + private notificationsService: NotificationsService, + private translateService: TranslateService, + private modalService: NgbModal, + private itemDataService: ItemDataService, + private selectableListService: SelectableListService) { + super(truncatableService); + } + + ngOnInit() { + super.ngOnInit(); + const defaultValue = this.firstMetadataValue('organization.legalName'); + const alternatives = this.allMetadataValues(this.alternativeField); + this.allSuggestions = [defaultValue, ...alternatives]; + + this.relationshipService.getNameVariant(this.listID, this.dso.uuid) + .pipe(take(1)) + .subscribe((nameVariant: string) => { + this.selectedName = nameVariant || defaultValue; + } + ); + } + + select(value) { + this.selectableListService.isObjectSelected(this.listID, this.object) + .pipe(take(1)) + .subscribe((selected) => { + if (!selected) { + this.selectableListService.selectSingle(this.listID, this.object); + } + }); + this.relationshipService.setNameVariant(this.listID, this.dso.uuid, value); + } + + selectCustom(value) { + if (!this.allSuggestions.includes(value)) { + this.openModal(value) + .then(() => { + + const newName: MetadataValue = new MetadataValue(); + newName.value = value; + + const existingNames: MetadataValue[] = this.dso.metadata[this.alternativeField] || []; + const alternativeNames = { [this.alternativeField]: [...existingNames, newName] }; + const updatedItem = + Object.assign({}, this.dso, { + metadata: { + ...this.dso.metadata, + ...alternativeNames + }, + }); + this.itemDataService.update(updatedItem).pipe(take(1)).subscribe(); + }) + } + this.select(value); + } + + openModal(value): Promise { + const modalRef = this.modalService.open(NameVariantModalComponent, { centered: true }); + const modalComp = modalRef.componentInstance; + modalComp.value = value; + return modalRef.result; + } +} diff --git a/src/app/entity-groups/research-entities/submission/item-list-elements/org-unit/org-unit-suggestions/org-unit-input-suggestions.component.html b/src/app/entity-groups/research-entities/submission/item-list-elements/org-unit/org-unit-suggestions/org-unit-input-suggestions.component.html new file mode 100644 index 0000000000..e177b2b561 --- /dev/null +++ b/src/app/entity-groups/research-entities/submission/item-list-elements/org-unit/org-unit-suggestions/org-unit-input-suggestions.component.html @@ -0,0 +1,24 @@ +
+ + + +
\ No newline at end of file diff --git a/src/app/entity-groups/research-entities/submission/item-list-elements/org-unit/org-unit-suggestions/org-unit-input-suggestions.component.scss b/src/app/entity-groups/research-entities/submission/item-list-elements/org-unit/org-unit-suggestions/org-unit-input-suggestions.component.scss new file mode 100644 index 0000000000..8301e12c5f --- /dev/null +++ b/src/app/entity-groups/research-entities/submission/item-list-elements/org-unit/org-unit-suggestions/org-unit-input-suggestions.component.scss @@ -0,0 +1,18 @@ +form { + z-index: 1; + &:before { + position: absolute; + font-weight: 900; + font-family: "Font Awesome 5 Free"; + content: "\f0d7"; + top: 7px; + right: 0; + height: 20px; + width: 20px; + z-index: -1; + } + + input.suggestion_input { + background: transparent; + } +} \ No newline at end of file diff --git a/src/app/entity-groups/research-entities/submission/item-list-elements/org-unit/org-unit-suggestions/org-unit-input-suggestions.component.ts b/src/app/entity-groups/research-entities/submission/item-list-elements/org-unit/org-unit-suggestions/org-unit-input-suggestions.component.ts new file mode 100644 index 0000000000..c868281e00 --- /dev/null +++ b/src/app/entity-groups/research-entities/submission/item-list-elements/org-unit/org-unit-suggestions/org-unit-input-suggestions.component.ts @@ -0,0 +1,48 @@ +import { Component, forwardRef, Input, OnInit } from '@angular/core'; +import { NG_VALUE_ACCESSOR } from '@angular/forms'; +import { InputSuggestionsComponent } from '../../../../../../shared/input-suggestions/input-suggestions.component'; + +@Component({ + selector: 'ds-org-unit-input-suggestions', + styleUrls: ['./org-unit-input-suggestions.component.scss', './../../../../../../shared/input-suggestions/input-suggestions.component.scss'], + templateUrl: './org-unit-input-suggestions.component.html', + providers: [ + { + provide: NG_VALUE_ACCESSOR, + // Usage of forwardRef necessary https://github.com/angular/angular.io/issues/1151 + // tslint:disable-next-line:no-forward-ref + useExisting: forwardRef(() => OrgUnitInputSuggestionsComponent), + multi: true + } + ] +}) + +/** + * Component representing a form with a autocomplete functionality + */ +export class OrgUnitInputSuggestionsComponent extends InputSuggestionsComponent implements OnInit { + /** + * The suggestions that should be shown + */ + @Input() suggestions: string[] = []; + + ngOnInit() { + if (this.suggestions.length > 0) { + this.value = this.suggestions[0] + } + } + + onSubmit(data) { + this.value = data; + this.submitSuggestion.emit(data); + } + + onClickSuggestion(data) { + this.value = data; + this.clickSuggestion.emit(data); + this.close(); + this.blockReopen = true; + this.queryInput.nativeElement.focus(); + return false; + } +} diff --git a/src/app/entity-groups/research-entities/submission/item-list-elements/person/person-search-result-list-submission-element.component.html b/src/app/entity-groups/research-entities/submission/item-list-elements/person/person-search-result-list-submission-element.component.html index df93c2f4f3..da87db0d30 100644 --- a/src/app/entity-groups/research-entities/submission/item-list-elements/person/person-search-result-list-submission-element.component.html +++ b/src/app/entity-groups/research-entities/submission/item-list-elements/person/person-search-result-list-submission-element.component.html @@ -1,6 +1,6 @@
- +
diff --git a/src/app/entity-groups/research-entities/submission/item-list-elements/person/person-search-result-list-submission-element.component.spec.ts b/src/app/entity-groups/research-entities/submission/item-list-elements/person/person-search-result-list-submission-element.component.spec.ts index d126be527e..76a7fe3dd7 100644 --- a/src/app/entity-groups/research-entities/submission/item-list-elements/person/person-search-result-list-submission-element.component.spec.ts +++ b/src/app/entity-groups/research-entities/submission/item-list-elements/person/person-search-result-list-submission-element.component.spec.ts @@ -20,50 +20,60 @@ import { PaginatedList } from '../../../../../core/data/paginated-list'; let personListElementComponent: PersonSearchResultListSubmissionElementComponent; let fixture: ComponentFixture; -const mockItemWithMetadata: ItemSearchResult = Object.assign( - new ItemSearchResult(), - { - indexableObject: Object.assign(new Item(), { - bundles: createSuccessfulRemoteDataObject$(new PaginatedList(undefined, [])), - metadata: { - 'dc.title': [ - { - language: 'en_US', - value: 'This is just another title' - } - ], - 'person.jobTitle': [ - { - language: 'en_US', - value: 'Developer' - } - ] - } - }) - }); -const mockItemWithoutMetadata: ItemSearchResult = Object.assign( - new ItemSearchResult(), - { - indexableObject: Object.assign(new Item(), { - bundles: createSuccessfulRemoteDataObject$(new PaginatedList(undefined, [])), - metadata: { - 'dc.title': [ - { - language: 'en_US', - value: 'This is just another title' - } - ] - } - }) - }); +let mockItemWithMetadata: ItemSearchResult; +let mockItemWithoutMetadata: ItemSearchResult; -const nameVariant = "Doe J."; -const mockRelationshipService = { - getNameVariant: () => observableOf(nameVariant) -}; +let nameVariant; +let mockRelationshipService; + + +function init() { + mockItemWithMetadata = Object.assign( + new ItemSearchResult(), + { + indexableObject: Object.assign(new Item(), { + bundles: createSuccessfulRemoteDataObject$(new PaginatedList(undefined, [])), + metadata: { + 'dc.title': [ + { + language: 'en_US', + value: 'This is just another title' + } + ], + 'person.jobTitle': [ + { + language: 'en_US', + value: 'Developer' + } + ] + } + }) + }); + mockItemWithoutMetadata = Object.assign( + new ItemSearchResult(), + { + indexableObject: Object.assign(new Item(), { + bundles: createSuccessfulRemoteDataObject$(new PaginatedList(undefined, [])), + metadata: { + 'dc.title': [ + { + language: 'en_US', + value: 'This is just another title' + } + ] + } + }) + }); + + nameVariant = "Doe J."; + mockRelationshipService = { + getNameVariant: () => observableOf(nameVariant) + }; +} describe('PersonSearchResultListElementSubmissionComponent', () => { beforeEach(async(() => { + init(); TestBed.configureTestingModule({ declarations: [PersonSearchResultListSubmissionElementComponent, TruncatePipe], providers: [ diff --git a/src/app/entity-groups/research-entities/submission/item-list-elements/person/person-search-result-list-submission-element.component.ts b/src/app/entity-groups/research-entities/submission/item-list-elements/person/person-search-result-list-submission-element.component.ts index 590b8c3920..1bcea16020 100644 --- a/src/app/entity-groups/research-entities/submission/item-list-elements/person/person-search-result-list-submission-element.component.ts +++ b/src/app/entity-groups/research-entities/submission/item-list-elements/person/person-search-result-list-submission-element.component.ts @@ -11,7 +11,7 @@ import { take } from 'rxjs/operators'; import { NotificationsService } from '../../../../../shared/notifications/notifications.service'; import { TranslateService } from '@ngx-translate/core'; import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; -import { NameVariantModalComponent } from './name-variant-modal/name-variant-modal.component'; +import { NameVariantModalComponent } from '../../name-variant-modal/name-variant-modal.component'; import { MetadataValue } from '../../../../../core/shared/metadata.models'; import { ItemDataService } from '../../../../../core/data/item-data.service'; import { SelectableListService } from '../../../../../shared/object-list/selectable-list/selectable-list.service'; diff --git a/src/app/entity-groups/research-entities/submission/item-list-elements/person/name-variant-modal/name-variant-modal.component.html b/src/app/entity-groups/research-entities/submission/name-variant-modal/name-variant-modal.component.html similarity index 100% rename from src/app/entity-groups/research-entities/submission/item-list-elements/person/name-variant-modal/name-variant-modal.component.html rename to src/app/entity-groups/research-entities/submission/name-variant-modal/name-variant-modal.component.html diff --git a/src/app/entity-groups/research-entities/submission/item-list-elements/person/name-variant-modal/name-variant-modal.component.scss b/src/app/entity-groups/research-entities/submission/name-variant-modal/name-variant-modal.component.scss similarity index 100% rename from src/app/entity-groups/research-entities/submission/item-list-elements/person/name-variant-modal/name-variant-modal.component.scss rename to src/app/entity-groups/research-entities/submission/name-variant-modal/name-variant-modal.component.scss diff --git a/src/app/entity-groups/research-entities/submission/item-list-elements/person/name-variant-modal/name-variant-modal.component.spec.ts b/src/app/entity-groups/research-entities/submission/name-variant-modal/name-variant-modal.component.spec.ts similarity index 100% rename from src/app/entity-groups/research-entities/submission/item-list-elements/person/name-variant-modal/name-variant-modal.component.spec.ts rename to src/app/entity-groups/research-entities/submission/name-variant-modal/name-variant-modal.component.spec.ts diff --git a/src/app/entity-groups/research-entities/submission/item-list-elements/person/name-variant-modal/name-variant-modal.component.ts b/src/app/entity-groups/research-entities/submission/name-variant-modal/name-variant-modal.component.ts similarity index 100% rename from src/app/entity-groups/research-entities/submission/item-list-elements/person/name-variant-modal/name-variant-modal.component.ts rename to src/app/entity-groups/research-entities/submission/name-variant-modal/name-variant-modal.component.ts diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component.ts index aedbe31fd2..c65105a092 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component.ts @@ -81,7 +81,7 @@ import { SelectableListService } from '../../../object-list/selectable-list/sele import { DsDynamicDisabledComponent } from './models/disabled/dynamic-disabled.component'; import { DYNAMIC_FORM_CONTROL_TYPE_DISABLED } from './models/disabled/dynamic-disabled.model'; import { DsDynamicLookupRelationModalComponent } from './relation-lookup-modal/dynamic-lookup-relation-modal.component'; -import { getAllSucceededRemoteData, getRemoteDataPayload, getSucceededRemoteData } from '../../../../core/shared/operators'; +import { getAllSucceededRemoteData, getRemoteDataPayload, getSucceededRemoteData, obsLog } from '../../../../core/shared/operators'; import { RemoteData } from '../../../../core/data/remote-data'; import { Item } from '../../../../core/shared/item.model'; import { ItemDataService } from '../../../../core/data/item-data.service'; @@ -94,6 +94,7 @@ import { PaginatedList } from '../../../../core/data/paginated-list'; import { ItemSearchResult } from '../../../object-collection/shared/item-search-result.model'; import { ItemMetadataRepresentation } from '../../../../core/shared/metadata-representation/item/item-metadata-representation.model'; import { MetadataValue } from '../../../../core/shared/metadata.models'; +import * as uuidv4 from 'uuid/v4'; export function dsDynamicFormControlMapFn(model: DynamicFormControlModel): Type | null { switch (model.type) { @@ -205,6 +206,7 @@ export class DsDynamicFormControlContainerComponent extends DynamicFormControlCo protected validationService: DynamicFormValidationService, protected translateService: TranslateService, private modalService: NgbModal, + private relationService: RelationshipService, private selectableListService: SelectableListService, private itemService: ItemDataService, private relationshipService: RelationshipService, @@ -216,6 +218,7 @@ export class DsDynamicFormControlContainerComponent extends DynamicFormControlCo } ngOnInit(): void { + const q = uuidv4(); this.hasRelationLookup = hasValue(this.model.relationship); if (this.hasRelationLookup) { this.listId = 'list-' + this.model.relationship.relationshipType; @@ -226,7 +229,7 @@ export class DsDynamicFormControlContainerComponent extends DynamicFormControlCo switchMap((submissionObject: SubmissionObject) => (submissionObject.item as Observable>).pipe(getAllSucceededRemoteData(), getRemoteDataPayload()))); this.item$.pipe( take(1), - switchMap((item: Item) => this.relationshipService.getRelatedItemsByLabel(item, this.model.relationship.relationshipType)), + switchMap((item: Item) => this.relationService.getRelatedItemsByLabel(item, this.model.relationship.relationshipType)), map((items: RemoteData>) => items.payload.page.map((item) => Object.assign(new ItemSearchResult(), { indexableObject: item }))), ).subscribe((relatedItems: SearchResult[]) => this.selectableListService.select(this.listId, relatedItems)); diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/dynamic-lookup-relation-modal.component.spec.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/dynamic-lookup-relation-modal.component.spec.ts new file mode 100644 index 0000000000..7c28f77572 --- /dev/null +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/dynamic-lookup-relation-modal.component.spec.ts @@ -0,0 +1,129 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { TranslateModule } from '@ngx-translate/core'; +import { RouterTestingModule } from '@angular/router/testing'; +import { NgZone, NO_ERRORS_SCHEMA } from '@angular/core'; +import { of as observableOf, Subscription } from 'rxjs'; +import { DsDynamicLookupRelationModalComponent } from './dynamic-lookup-relation-modal.component'; +import { NgbActiveModal, NgbModule } from '@ng-bootstrap/ng-bootstrap'; +import { SelectableListService } from '../../../../object-list/selectable-list/selectable-list.service'; +import { RelationshipService } from '../../../../../core/data/relationship.service'; +import { RelationshipTypeService } from '../../../../../core/data/relationship-type.service'; +import { Store } from '@ngrx/store'; +import { Item } from '../../../../../core/shared/item.model'; +import { ItemSearchResult } from '../../../../object-collection/shared/item-search-result.model'; +import { RelationshipOptions } from '../../models/relationship-options.model'; +import { AddRelationshipAction, RemoveRelationshipAction } from './relationship.actions'; + +describe('DsDynamicLookupRelationModalComponent', () => { + let component: DsDynamicLookupRelationModalComponent; + let fixture: ComponentFixture; + let item; + let item1; + let item2; + let searchResult1; + let searchResult2; + let listID; + let selection$; + let selectableListService; + let relationship; + let nameVariant; + let metadataField; + + function init() { + item = Object.assign(new Item(), { uuid: '7680ca97-e2bd-4398-bfa7-139a8673dc42', metadata: {} }); + item1 = Object.assign(new Item(), { uuid: 'e1c51c69-896d-42dc-8221-1d5f2ad5516e' }); + item2 = Object.assign(new Item(), { uuid: 'c8279647-1acc-41ae-b036-951d5f65649b' }); + searchResult1 = Object.assign(new ItemSearchResult(), { indexableObject: item1 }); + searchResult2 = Object.assign(new ItemSearchResult(), { indexableObject: item2 }); + listID = '6b0c8221-fcb4-47a8-b483-ca32363fffb3'; + selection$ = observableOf([searchResult1, searchResult2]); + selectableListService = { getSelectableList: () => selection$ }; + relationship = { filter: 'filter', relationshipType: 'isAuthorOfPublication', nameVariants: true } as RelationshipOptions; + nameVariant = 'Doe, J.'; + metadataField = 'dc.contributor.author'; + } + + beforeEach(async(() => { + init(); + TestBed.configureTestingModule({ + declarations: [DsDynamicLookupRelationModalComponent], + imports: [TranslateModule.forRoot(), RouterTestingModule.withRoutes([]), NgbModule.forRoot()], + providers: [ + { + provide: SelectableListService, useValue: selectableListService + }, + { + provide: RelationshipService, useValue: { getNameVariant: () => observableOf(nameVariant) } + }, + { provide: RelationshipTypeService, useValue: {} }, + { + provide: Store, useValue: { + dispatch: () => { + } + } + }, + { provide: NgZone, useValue: new NgZone({}) }, + NgbActiveModal + ], + schemas: [NO_ERRORS_SCHEMA] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(DsDynamicLookupRelationModalComponent); + component = fixture.componentInstance; + component.listId = listID; + component.relationshipOptions = relationship; + component.item = item; + component.metadataFields = metadataField; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + describe('close', () => { + beforeEach(() => { + spyOn(component.modal, 'close'); + }); + + it('should call close on the modal', () => { + component.close(); + expect(component.modal.close).toHaveBeenCalled(); + }) + }); + + describe('select', () => { + beforeEach(() => { + spyOn((component as any).store, 'dispatch'); + }); + + it('should dispatch an AddRelationshipAction for each selected object', () => { + component.select(searchResult1, searchResult2); + const action = new AddRelationshipAction(component.item, searchResult1.indexableObject, relationship.relationshipType, nameVariant); + const action2 = new AddRelationshipAction(component.item, searchResult2.indexableObject, relationship.relationshipType, nameVariant); + + expect((component as any).store.dispatch).toHaveBeenCalledWith(action); + expect((component as any).store.dispatch).toHaveBeenCalledWith(action2); + }) + }); + + describe('deselect', () => { + beforeEach(() => { + component.subMap[searchResult1.indexableObject.uuid] = new Subscription(); + component.subMap[searchResult2.indexableObject.uuid] = new Subscription(); + spyOn((component as any).store, 'dispatch'); + }); + + it('should dispatch an RemoveRelationshipAction for each deselected object', () => { + component.deselect(searchResult1, searchResult2); + const action = new RemoveRelationshipAction(component.item, searchResult1.indexableObject, relationship.relationshipType); + const action2 = new RemoveRelationshipAction(component.item, searchResult2.indexableObject, relationship.relationshipType); + + expect((component as any).store.dispatch).toHaveBeenCalledWith(action); + expect((component as any).store.dispatch).toHaveBeenCalledWith(action2); + }) + }); +}); diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/dynamic-lookup-relation-modal.component.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/dynamic-lookup-relation-modal.component.ts index e008f839e6..6a3bf798ad 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/dynamic-lookup-relation-modal.component.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/dynamic-lookup-relation-modal.component.ts @@ -66,6 +66,8 @@ export class DsDynamicLookupRelationModalComponent implements OnInit, OnDestroy if (this.relationshipOptions.nameVariants) { this.context = Context.Workspace; } + + // this.setExistingNameVariants(); } close() { @@ -99,7 +101,7 @@ export class DsDynamicLookupRelationModalComponent implements OnInit, OnDestroy }); } - addNameVariantSubscription(sri: SearchResult) { + private addNameVariantSubscription(sri: SearchResult) { const nameVariant$ = this.relationshipService.getNameVariant(this.listId, sri.indexableObject.uuid); this.subMap[sri.indexableObject.uuid] = nameVariant$.pipe( skip(1), @@ -115,25 +117,26 @@ export class DsDynamicLookupRelationModalComponent implements OnInit, OnDestroy ); } - setExistingNameVariants() { - const virtualMDs$: Observable = this.item.allMetadata(this.metadataFields).filter((mdValue) => mdValue.isVirtual); + private setExistingNameVariants() { + const virtualMDs: MetadataValue[] = this.item.allMetadata(this.metadataFields).filter((mdValue) => mdValue.isVirtual); - const relatedItemPairs$: Observable<[Item, Item][]> = virtualMDs$.pipe( - switchMap((mds: MetadataValue[]) => combineLatest(mds.map((md: MetadataValue) => this.relationshipService.findById(md.virtualValue).pipe(getSucceededRemoteData(), getRemoteDataPayload())))), - switchMap((relationships: Relationship[]) => combineLatest(relationships.map((relationship: Relationship) => - combineLatest( - relationship.leftItem.pipe(getSucceededRemoteData(), getRemoteDataPayload()), - relationship.rightItem.pipe(getSucceededRemoteData(), getRemoteDataPayload()) - )) - ) - ) - ); + const relatedItemPairs$: Observable<[Item, Item][]> = + combineLatest(virtualMDs.map((md: MetadataValue) => this.relationshipService.findById(md.virtualValue).pipe(getSucceededRemoteData(), getRemoteDataPayload()))) + .pipe( + switchMap((relationships: Relationship[]) => combineLatest(relationships.map((relationship: Relationship) => + combineLatest( + relationship.leftItem.pipe(getSucceededRemoteData(), getRemoteDataPayload()), + relationship.rightItem.pipe(getSucceededRemoteData(), getRemoteDataPayload()) + )) + ) + ) + ); const relatedItems$: Observable = relatedItemPairs$.pipe( map(([relatedItemPairs,]: [[Item, Item][]]) => relatedItemPairs.map(([left, right]: [Item, Item]) => left.uuid === this.item.uuid ? left : right)) ); - combineLatest(virtualMDs$, relatedItems$).pipe(take(1)).subscribe(([virtualMDs, relatedItems]) => { + relatedItems$.pipe(take(1)).subscribe((relatedItems) => { let index: number = 0; virtualMDs.forEach( (md: MetadataValue) => { @@ -145,7 +148,6 @@ export class DsDynamicLookupRelationModalComponent implements OnInit, OnDestroy ) } - ngOnDestroy() { Object.values(this.subMap).forEach((subscription) => subscription.unsubscribe()); } diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/name-variant.reducer.spec.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/name-variant.reducer.spec.ts index 0f8f08fdd2..42c9d6c9b5 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/name-variant.reducer.spec.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/name-variant.reducer.spec.ts @@ -7,15 +7,29 @@ class NullAction implements Action { type = null; } -const listID1 = 'dbfb81de-2930-4de6-ba2e-ea21c8534ee9'; -const listID2 = 'd7f2c48d-e1e2-4996-ab8d-e271cabec78a'; -const itemID1 = 'd1c81d4f-6b05-4844-986b-372d2e39c6aa'; -const itemID2 = 'fe4ca421-d897-417f-9436-9724262d5c69'; -const variantList1Item1 = 'Test Name Variant 1'; -const variantList1Item1Update = 'Test Name Variant 1 Update'; -const variantList1Item2 = 'Test Name Variant 2'; +let listID1; +let listID2; +let itemID1; +let itemID2; +let variantList1Item1; +let variantList1Item1Update; +let variantList1Item2; + +function init() { + listID1 = 'dbfb81de-2930-4de6-ba2e-ea21c8534ee9'; + listID2 = 'd7f2c48d-e1e2-4996-ab8d-e271cabec78a'; + itemID1 = 'd1c81d4f-6b05-4844-986b-372d2e39c6aa'; + itemID2 = 'fe4ca421-d897-417f-9436-9724262d5c69'; + variantList1Item1 = 'Test Name Variant 1'; + variantList1Item1Update = 'Test Name Variant 1 Update'; + variantList1Item2 = 'Test Name Variant 2'; +} + describe('nameVariantReducer', () => { + beforeEach(() => { + init(); + }); it('should return the current state when no valid actions have been made', () => { const state = { [listID1]: { [itemID1]: variantList1Item1 } }; diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/relationship.effects.spec.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/relationship.effects.spec.ts index bb5e61d32d..ec47f88c6c 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/relationship.effects.spec.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/relationship.effects.spec.ts @@ -19,57 +19,80 @@ describe('RelationshipEffects', () => { let relationEffects: RelationshipEffects; let actions: Observable; - const testUUID1 = '20e24c2f-a00a-467c-bdee-c929e79bf08d'; - const testUUID2 = '7f66a4d0-8557-4e77-8b1e-19930895f10a'; - const leftTypeString = 'Publication'; - const rightTypeString = 'Person'; - const leftType = Object.assign(new ItemType(), {label: leftTypeString}); - const rightType = Object.assign(new ItemType(), {label: rightTypeString}); - const leftTypeMD = Object.assign(new MetadataValue(), { value: leftTypeString }); - const rightTypeMD = Object.assign(new MetadataValue(), { value: rightTypeString }); - const relationshipID = '1234'; + let testUUID1; + let testUUID2; + let leftTypeString; + let rightTypeString; + let leftType; + let rightType; + let leftTypeMD; + let rightTypeMD; + let relationshipID; let identifier; - let leftItem = Object.assign(new Item(), { - uuid: testUUID1, - metadata: { 'relationship.type': [leftTypeMD] } - }); + let leftItem; - let rightItem = Object.assign(new Item(), { - uuid: testUUID2, - metadata: { 'relationship.type': [rightTypeMD] } - }); + let rightItem; - let relationshipType: RelationshipType = Object.assign(new RelationshipType(), { - leftwardType: 'isAuthorOfPublication', - rightwardType: 'isPublicationOfAuthor', - leftType: createSuccessfulRemoteDataObject$(leftType), - rightType: createSuccessfulRemoteDataObject$(rightType) - }); + let relationshipType: RelationshipType; - let relationship = Object.assign(new Relationship(), - { - uuid: relationshipID, - leftItem: createSuccessfulRemoteDataObject$(leftItem), - rightItem: createSuccessfulRemoteDataObject$(rightItem), - relationshipType: createSuccessfulRemoteDataObject$(relationshipType) + let relationship; + let mockRelationshipService; + let mockRelationshipTypeService; + + + function init() { + testUUID1 = '20e24c2f-a00a-467c-bdee-c929e79bf08d'; + testUUID2 = '7f66a4d0-8557-4e77-8b1e-19930895f10a'; + leftTypeString = 'Publication'; + rightTypeString = 'Person'; + leftType = Object.assign(new ItemType(), {label: leftTypeString}); + rightType = Object.assign(new ItemType(), {label: rightTypeString}); + leftTypeMD = Object.assign(new MetadataValue(), { value: leftTypeString }); + rightTypeMD = Object.assign(new MetadataValue(), { value: rightTypeString }); + relationshipID = '1234'; + + leftItem = Object.assign(new Item(), { + uuid: testUUID1, + metadata: { 'relationship.type': [leftTypeMD] } }); - const mockRelationshipService = { - getRelationshipByItemsAndLabel: - () => observableOf(relationship), - deleteRelationship: () => { - /* Do nothing */ - }, - addRelationship: () => { - /* Do nothing */ - } - }; - const mockRelationshipTypeService = { - getRelationshipTypeByLabelAndTypes: - () => observableOf(relationshipType) - }; + rightItem = Object.assign(new Item(), { + uuid: testUUID2, + metadata: { 'relationship.type': [rightTypeMD] } + }); + + relationshipType = Object.assign(new RelationshipType(), { + leftwardType: 'isAuthorOfPublication', + rightwardType: 'isPublicationOfAuthor', + leftType: createSuccessfulRemoteDataObject$(leftType), + rightType: createSuccessfulRemoteDataObject$(rightType) + }); + + relationship = Object.assign(new Relationship(), + { + uuid: relationshipID, + leftItem: createSuccessfulRemoteDataObject$(leftItem), + rightItem: createSuccessfulRemoteDataObject$(rightItem), + relationshipType: createSuccessfulRemoteDataObject$(relationshipType) + }); + mockRelationshipService = { + getRelationshipByItemsAndLabel: + () => observableOf(relationship), + deleteRelationship: () => { + /* Do nothing */ + }, + addRelationship: () => { + /* Do nothing */ + } + }; + mockRelationshipTypeService = { + getRelationshipTypeByLabelAndTypes: + () => observableOf(relationshipType) + }; + } beforeEach(async(() => { + init(); TestBed.configureTestingModule({ providers: [ RelationshipEffects, diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/relationship.effects.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/relationship.effects.ts index 174945dd06..bdd0bd64b5 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/relationship.effects.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/relationship.effects.ts @@ -51,7 +51,6 @@ export class RelationshipEffects { take(1) ).subscribe( (type) => { - debugger; if (this.initialActionMap[identifier] === type) { if (type === RelationshipActionTypes.ADD_RELATIONSHIP) { let nameVariant = (action as AddRelationshipAction).payload.nameVariant; diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/search-tab/dynamic-lookup-relation-search-tab.component.spec.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/search-tab/dynamic-lookup-relation-search-tab.component.spec.ts new file mode 100644 index 0000000000..241d022dc3 --- /dev/null +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/search-tab/dynamic-lookup-relation-search-tab.component.spec.ts @@ -0,0 +1,140 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { TranslateModule } from '@ngx-translate/core'; +import { DsDynamicLookupRelationSearchTabComponent } from './dynamic-lookup-relation-search-tab.component'; +import { SearchService } from '../../../../../../core/shared/search/search.service'; +import { SelectableListService } from '../../../../../object-list/selectable-list/selectable-list.service'; +import { SearchConfigurationService } from '../../../../../../core/shared/search/search-configuration.service'; +import { RouteService } from '../../../../../../core/services/route.service'; +import { RouterTestingModule } from '@angular/router/testing'; +import { NO_ERRORS_SCHEMA } from '@angular/core'; +import { VarDirective } from '../../../../../utils/var.directive'; +import { RelationshipOptions } from '../../../models/relationship-options.model'; +import { of as observableOf } from 'rxjs'; +import { PaginatedSearchOptions } from '../../../../../search/paginated-search-options.model'; +import { createSuccessfulRemoteDataObject$ } from '../../../../../testing/utils'; +import { PaginatedList } from '../../../../../../core/data/paginated-list'; +import { ItemSearchResult } from '../../../../../object-collection/shared/item-search-result.model'; +import { Item } from '../../../../../../core/shared/item.model'; + +describe('DsDynamicLookupRelationSearchTabComponent', () => { + let component: DsDynamicLookupRelationSearchTabComponent; + let fixture: ComponentFixture; + let relationship; + let pSearchOptions; + let item1; + let item2; + let item3; + let searchResult1; + let searchResult2; + let searchResult3; + let listID; + let selection$; + + let results; + let selectableListService; + + function init() { + relationship = { filter: 'filter', relationshipType: 'isAuthorOfPublication', nameVariants: true } as RelationshipOptions; + pSearchOptions = new PaginatedSearchOptions({}); + item1 = Object.assign(new Item(), { uuid: 'e1c51c69-896d-42dc-8221-1d5f2ad5516e' }); + item2 = Object.assign(new Item(), { uuid: 'c8279647-1acc-41ae-b036-951d5f65649b' }); + item3 = Object.assign(new Item(), { uuid: 'c3bcbff5-ec0c-4831-8e4c-94b9c933ccac' }); + searchResult1 = Object.assign(new ItemSearchResult(), { indexableObject: item1 }); + searchResult2 = Object.assign(new ItemSearchResult(), { indexableObject: item2 }); + searchResult3 = Object.assign(new ItemSearchResult(), { indexableObject: item3 }); + listID = '6b0c8221-fcb4-47a8-b483-ca32363fffb3'; + selection$ = observableOf([searchResult1, searchResult2]); + + results = new PaginatedList(undefined, [searchResult1, searchResult2, searchResult3]); + selectableListService = jasmine.createSpyObj('selectableListService', ['deselect', 'select', 'deselectAll']); + } + + beforeEach(async(() => { + init(); + TestBed.configureTestingModule({ + declarations: [DsDynamicLookupRelationSearchTabComponent, VarDirective], + imports: [TranslateModule.forRoot(), RouterTestingModule.withRoutes([])], + providers: [ + { provide: SearchService, useValue: { search: () => createSuccessfulRemoteDataObject$(results) } }, + { + provide: SelectableListService, useValue: selectableListService + }, + { + provide: SearchConfigurationService, useValue: { + paginatedSearchOptions: observableOf(pSearchOptions) + } + }, + { + provide: RouteService, useValue: { + setParameter: () => { + // do nothing + } + } + }, + ], + schemas: [NO_ERRORS_SCHEMA] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(DsDynamicLookupRelationSearchTabComponent); + component = fixture.componentInstance; + component.relationship = relationship; + component.selection$ = selection$; + component.listId = listID; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + describe('selectPage', () => { + beforeEach(() => { + spyOn(component.selectObject, 'emit'); + component.selectPage([searchResult1, searchResult2, searchResult3]); + }); + + it('should emit the page filtered from already selected objects and call select on the service for all objects', () => { + expect(component.selectObject.emit).toHaveBeenCalledWith(searchResult3); + expect(selectableListService.select).toHaveBeenCalledWith(listID, [searchResult1, searchResult2, searchResult3]); + }); + }); + + describe('deselectPage', () => { + beforeEach(() => { + spyOn(component.deselectObject, 'emit'); + component.deselectPage([searchResult1, searchResult2, searchResult3]); + }); + + it('should emit the page filtered from not yet selected objects and call select on the service for all objects', () => { + expect(component.deselectObject.emit).toHaveBeenCalledWith(searchResult1, searchResult2); + expect(selectableListService.deselect).toHaveBeenCalledWith(listID, [searchResult1, searchResult2, searchResult3]); + }); + }); + + describe('selectAll', () => { + beforeEach(() => { + spyOn(component.selectObject, 'emit'); + component.selectAll(); + }); + + it('should emit the page filtered from already selected objects and call select on the service for all objects', () => { + expect(component.selectObject.emit).toHaveBeenCalledWith(searchResult3); + expect(selectableListService.select).toHaveBeenCalledWith(listID, [searchResult1, searchResult2, searchResult3]); + }); + }); + + describe('deselectAll', () => { + beforeEach(() => { + spyOn(component.deselectObject, 'emit'); + component.deselectAll(); + }); + + it('should emit the page filtered from not yet selected objects and call select on the service for all objects', () => { + expect(component.deselectObject.emit).toHaveBeenCalledWith(searchResult1, searchResult2); + expect(selectableListService.deselectAll).toHaveBeenCalledWith(listID); + }); + }); +}); diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/search-tab/dynamic-lookup-relation-search-tab.component.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/search-tab/dynamic-lookup-relation-search-tab.component.ts index 4a9755fd63..745aa48b4e 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/search-tab/dynamic-lookup-relation-search-tab.component.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/search-tab/dynamic-lookup-relation-search-tab.component.ts @@ -100,7 +100,7 @@ export class DsDynamicLookupRelationSearchTabComponent implements OnInit, OnDest this.selection$ .pipe(take(1)) .subscribe((selection: SearchResult[]) => { - const filteredPage = page.filter((pageItem) => selection.findIndex((selected) => selected.equals(pageItem)) < 0) + const filteredPage = page.filter((pageItem) => selection.findIndex((selected) => selected.equals(pageItem)) < 0); this.selectObject.emit(...filteredPage); }); this.selectableListService.select(this.listId, page); @@ -111,7 +111,7 @@ export class DsDynamicLookupRelationSearchTabComponent implements OnInit, OnDest this.selection$ .pipe(take(1)) .subscribe((selection: SearchResult[]) => { - const filteredPage = page.filter((pageItem) => selection.findIndex((selected) => selected.equals(pageItem)) >= 0) + const filteredPage = page.filter((pageItem) => selection.findIndex((selected) => selected.equals(pageItem)) >= 0); this.deselectObject.emit(...filteredPage); }); this.selectableListService.deselect(this.listId, page); diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/selection-tab/dynamic-lookup-relation-selection-tab.component.spec.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/selection-tab/dynamic-lookup-relation-selection-tab.component.spec.ts new file mode 100644 index 0000000000..32c995ba94 --- /dev/null +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/selection-tab/dynamic-lookup-relation-selection-tab.component.spec.ts @@ -0,0 +1,62 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { TranslateModule } from '@ngx-translate/core'; +import { SearchConfigurationService } from '../../../../../../core/shared/search/search-configuration.service'; +import { RouterTestingModule } from '@angular/router/testing'; +import { NO_ERRORS_SCHEMA } from '@angular/core'; +import { VarDirective } from '../../../../../utils/var.directive'; +import { of as observableOf } from 'rxjs'; +import { PaginatedSearchOptions } from '../../../../../search/paginated-search-options.model'; +import { ItemSearchResult } from '../../../../../object-collection/shared/item-search-result.model'; +import { Item } from '../../../../../../core/shared/item.model'; +import { DsDynamicLookupRelationSelectionTabComponent } from './dynamic-lookup-relation-selection-tab.component'; +import { PaginationComponentOptions } from '../../../../../pagination/pagination-component-options.model'; + +describe('DsDynamicLookupRelationSelectionTabComponent', () => { + let component: DsDynamicLookupRelationSelectionTabComponent; + let fixture: ComponentFixture; + let pSearchOptions = new PaginatedSearchOptions({pagination: new PaginationComponentOptions()}); + let item1 = Object.assign(new Item(), { uuid: 'e1c51c69-896d-42dc-8221-1d5f2ad5516e' }); + let item2 = Object.assign(new Item(), { uuid: 'c8279647-1acc-41ae-b036-951d5f65649b' }); + let searchResult1 = Object.assign(new ItemSearchResult(), { indexableObject: item1 }); + let searchResult2 = Object.assign(new ItemSearchResult(), { indexableObject: item2 }); + let listID = '6b0c8221-fcb4-47a8-b483-ca32363fffb3'; + let selection$ = observableOf([searchResult1, searchResult2]); + + function init() { + pSearchOptions = new PaginatedSearchOptions({pagination: new PaginationComponentOptions()}); + item1 = Object.assign(new Item(), { uuid: 'e1c51c69-896d-42dc-8221-1d5f2ad5516e' }); + item2 = Object.assign(new Item(), { uuid: 'c8279647-1acc-41ae-b036-951d5f65649b' }); + searchResult1 = Object.assign(new ItemSearchResult(), { indexableObject: item1 }); + searchResult2 = Object.assign(new ItemSearchResult(), { indexableObject: item2 }); + listID = '6b0c8221-fcb4-47a8-b483-ca32363fffb3'; + selection$ = observableOf([searchResult1, searchResult2]); + } + beforeEach(async(() => { + init(); + TestBed.configureTestingModule({ + declarations: [DsDynamicLookupRelationSelectionTabComponent, VarDirective], + imports: [TranslateModule.forRoot(), RouterTestingModule.withRoutes([])], + providers: [ + { + provide: SearchConfigurationService, useValue: { + paginatedSearchOptions: observableOf(pSearchOptions) + } + } + ], + schemas: [NO_ERRORS_SCHEMA] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(DsDynamicLookupRelationSelectionTabComponent); + component = fixture.componentInstance; + component.selection$ = selection$; + component.listId = listID; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/shared/form/form.component.spec.ts b/src/app/shared/form/form.component.spec.ts index 669c416eb9..111e91364c 100644 --- a/src/app/shared/form/form.component.spec.ts +++ b/src/app/shared/form/form.component.spec.ts @@ -382,7 +382,6 @@ describe('FormComponent test suite', () => { describe('', () => { beforeEach(() => { - formFixture = TestBed.createComponent(FormComponent); store = TestBed.get(Store); formComp = formFixture.componentInstance; // FormComponent test instance diff --git a/src/app/shared/input-suggestions/input-suggestions.component.spec.ts b/src/app/shared/input-suggestions/input-suggestions.component.spec.ts index 1f16a84b2c..b20c015d9f 100644 --- a/src/app/shared/input-suggestions/input-suggestions.component.spec.ts +++ b/src/app/shared/input-suggestions/input-suggestions.component.spec.ts @@ -14,9 +14,11 @@ describe('InputSuggestionsComponent', () => { let fixture: ComponentFixture; let de: DebugElement; let el: HTMLElement; - const suggestions = [{displayValue: 'suggestion uno', value: 'suggestion uno'}, {displayValue: 'suggestion dos', value: 'suggestion dos'}, {displayValue: 'suggestion tres', value: 'suggestion tres'}]; + let suggestions; beforeEach(async(() => { + suggestions = [{displayValue: 'suggestion uno', value: 'suggestion uno'}, {displayValue: 'suggestion dos', value: 'suggestion dos'}, {displayValue: 'suggestion tres', value: 'suggestion tres'}]; + TestBed.configureTestingModule({ imports: [TranslateModule.forRoot(), RouterTestingModule.withRoutes([]), NoopAnimationsModule, FormsModule], declarations: [InputSuggestionsComponent],