diff --git a/src/app/core/shared/external-source.model.ts b/src/app/core/shared/external-source.model.ts index e28c8953e9..9f20a732f4 100644 --- a/src/app/core/shared/external-source.model.ts +++ b/src/app/core/shared/external-source.model.ts @@ -1,10 +1,15 @@ import { autoserialize, deserialize } from 'cerialize'; -import { typedObject } from '../cache/builders/build-decorators'; +import { link, typedObject } from '../cache/builders/build-decorators'; import { CacheableObject } from '../cache/object-cache.reducer'; import { excludeFromEquals } from '../utilities/equals.decorators'; import { EXTERNAL_SOURCE } from './external-source.resource-type'; import { HALLink } from './hal-link.model'; import { ResourceType } from './resource-type'; +import { RemoteData } from '../data/remote-data'; +import { PaginatedList } from '../data/paginated-list.model'; +import { Observable } from 'rxjs/internal/Observable'; +import { ITEM_TYPE } from './item-relationships/item-type.resource-type'; +import { ItemType } from './item-relationships/item-type.model'; /** * Model class for an external source @@ -38,6 +43,13 @@ export class ExternalSource extends CacheableObject { @autoserialize hierarchical: boolean; + /** + * The list of entity types that are compatible with this external source + * Will be undefined unless the entityTypes {@link HALLink} has been resolved. + */ + @link(ITEM_TYPE, true) + entityTypes?: Observable>>; + /** * The {@link HALLink}s for this ExternalSource */ @@ -45,5 +57,6 @@ export class ExternalSource extends CacheableObject { _links: { self: HALLink; entries: HALLink; + entityTypes: HALLink; }; } 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 5ce451d6c2..b1afd08909 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 @@ -12,7 +12,9 @@ import { RelationshipOptions } from '../../models/relationship-options.model'; import { SearchResult } from '../../../../search/search-result.model'; import { Item } from '../../../../../core/shared/item.model'; import { - AddRelationshipAction, RemoveRelationshipAction, UpdateRelationshipNameVariantAction, + AddRelationshipAction, + RemoveRelationshipAction, + UpdateRelationshipNameVariantAction, } from './relationship.actions'; import { RelationshipService } from '../../../../../core/data/relationship.service'; import { RelationshipTypeService } from '../../../../../core/data/relationship-type.service'; @@ -25,6 +27,7 @@ import { ExternalSourceService } from '../../../../../core/data/external-source. import { Router } from '@angular/router'; import { RemoteDataBuildService } from '../../../../../core/cache/builders/remote-data-build.service'; import { getAllSucceededRemoteDataPayload } from '../../../../../core/shared/operators'; +import { followLink } from '../../../../utils/follow-link-config.model'; @Component({ selector: 'ds-dynamic-lookup-relation-modal', @@ -146,7 +149,14 @@ export class DsDynamicLookupRelationModalComponent implements OnInit, OnDestroy if (isNotEmpty(this.relationshipOptions.externalSources)) { this.externalSourcesRD$ = this.rdbService.aggregate( - this.relationshipOptions.externalSources.map((source) => this.externalSourceService.findById(source)) + this.relationshipOptions.externalSources.map((source) => { + return this.externalSourceService.findById( + source, + true, + true, + followLink('entityTypes') + ); + }) ).pipe( getAllSucceededRemoteDataPayload() ); diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/external-source-tab/dynamic-lookup-relation-external-source-tab.component.spec.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/external-source-tab/dynamic-lookup-relation-external-source-tab.component.spec.ts index 6309b74792..62c33bd967 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/external-source-tab/dynamic-lookup-relation-external-source-tab.component.spec.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/external-source-tab/dynamic-lookup-relation-external-source-tab.component.spec.ts @@ -26,6 +26,7 @@ import { ExternalSourceEntryImportModalComponent } from './external-source-entry import { createPaginatedList } from '../../../../../testing/utils.test'; import { PaginationService } from '../../../../../../core/pagination/pagination.service'; import { PaginationServiceStub } from '../../../../../testing/pagination-service.stub'; +import { ItemType } from '../../../../../../core/shared/item-relationships/item-type.model'; describe('DsDynamicLookupRelationExternalSourceTabComponent', () => { let component: DsDynamicLookupRelationExternalSourceTabComponent; @@ -35,10 +36,12 @@ describe('DsDynamicLookupRelationExternalSourceTabComponent', () => { let selectableListService; let modalService; + const itemType = Object.assign(new ItemType(), { label: 'Person' }); const externalSource = { id: 'orcidV2', name: 'orcidV2', - hierarchical: false + hierarchical: false, + entityTypes: createSuccessfulRemoteDataObject$(createPaginatedList([itemType])) } as ExternalSource; const externalEntries = [ Object.assign({ diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/external-source-tab/dynamic-lookup-relation-external-source-tab.component.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/external-source-tab/dynamic-lookup-relation-external-source-tab.component.ts index 57abdd1a32..48b9edc82a 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/external-source-tab/dynamic-lookup-relation-external-source-tab.component.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/external-source-tab/dynamic-lookup-relation-external-source-tab.component.ts @@ -7,7 +7,7 @@ import { RemoteData } from '../../../../../../core/data/remote-data'; import { PaginatedList } from '../../../../../../core/data/paginated-list.model'; import { ExternalSourceEntry } from '../../../../../../core/shared/external-source-entry.model'; import { ExternalSource } from '../../../../../../core/shared/external-source.model'; -import { startWith, switchMap } from 'rxjs/operators'; +import { map, startWith, switchMap } from 'rxjs/operators'; import { PaginatedSearchOptions } from '../../../../../search/paginated-search-options.model'; import { Context } from '../../../../../../core/shared/context.model'; import { ListableObject } from '../../../../../object-collection/shared/listable-object.model'; @@ -22,6 +22,8 @@ import { Item } from '../../../../../../core/shared/item.model'; import { Collection } from '../../../../../../core/shared/collection.model'; import { PaginationService } from '../../../../../../core/pagination/pagination.service'; import { Observable, Subscription } from 'rxjs'; +import { ItemType } from '../../../../../../core/shared/item-relationships/item-type.model'; +import { getFirstCompletedRemoteData } from '../../../../../../core/shared/operators'; @Component({ selector: 'ds-dynamic-lookup-relation-external-source-tab', @@ -116,6 +118,11 @@ export class DsDynamicLookupRelationExternalSourceTabComponent implements OnInit */ importObjectSub: Subscription; + /** + * The entity types compatible with the given external source + */ + relatedEntityType: ItemType; + constructor(private router: Router, public searchConfigService: SearchConfigurationService, private externalSourceService: ExternalSourceService, @@ -129,6 +136,15 @@ export class DsDynamicLookupRelationExternalSourceTabComponent implements OnInit * Get the entries for the selected external source */ ngOnInit(): void { + this.externalSource.entityTypes.pipe( + getFirstCompletedRemoteData(), + map((entityTypesRD: RemoteData>) => { + return (entityTypesRD.hasSucceeded && entityTypesRD.payload.totalElements > 0) ? entityTypesRD.payload.page[0] : null; + }) + ).subscribe((entityType: ItemType) => { + this.relatedEntityType = entityType; + }); + this.resetRoute(); this.entriesRD$ = this.searchConfigService.paginatedSearchOptions.pipe( switchMap((searchOptions: PaginatedSearchOptions) => @@ -155,6 +171,7 @@ export class DsDynamicLookupRelationExternalSourceTabComponent implements OnInit modalComp.collection = this.collection; modalComp.relationship = this.relationship; modalComp.label = this.label; + modalComp.relatedEntityType = this.relatedEntityType; this.importObjectSub = modalComp.importedObject.subscribe((object) => { this.selectableListService.selectSingle(this.listId, object); this.importedObject.emit(object); diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/external-source-tab/external-source-entry-import-modal/external-source-entry-import-modal.component.html b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/external-source-tab/external-source-entry-import-modal/external-source-entry-import-modal.component.html index a4fc356ef9..44f21fb4b4 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/external-source-tab/external-source-entry-import-modal/external-source-entry-import-modal.component.html +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/external-source-tab/external-source-entry-import-modal/external-source-entry-import-modal.component.html @@ -17,13 +17,6 @@
{{ (labelPrefix + 'entities' | translate) }}
-
-
- - -
-
- { component.externalSourceEntry = entry; component.label = label; component.relationship = relationship; - component.collection = submissionCollection; component.item = submissionItem; fixture.detectChanges(); }); diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/external-source-tab/external-source-entry-import-modal/external-source-entry-import-modal.component.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/external-source-tab/external-source-entry-import-modal/external-source-entry-import-modal.component.ts index ca179a8080..9a0b49e3f6 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/external-source-tab/external-source-entry-import-modal/external-source-entry-import-modal.component.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/external-source-tab/external-source-entry-import-modal/external-source-entry-import-modal.component.ts @@ -1,5 +1,5 @@ import { Component, EventEmitter, OnInit } from '@angular/core'; -import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; +import { NgbActiveModal, NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap'; import { ExternalSourceEntry } from '../../../../../../../core/shared/external-source-entry.model'; import { MetadataValue } from '../../../../../../../core/shared/metadata.models'; import { Metadata } from '../../../../../../../core/shared/metadata.utils'; @@ -15,14 +15,16 @@ import { CollectionElementLinkType } from '../../../../../../object-collection/c import { Context } from '../../../../../../../core/shared/context.model'; import { SelectableListService } from '../../../../../../object-list/selectable-list/selectable-list.service'; import { ListableObject } from '../../../../../../object-collection/shared/listable-object.model'; -import { Collection } from '../../../../../../../core/shared/collection.model'; import { ItemDataService } from '../../../../../../../core/data/item-data.service'; import { PaginationComponentOptions } from '../../../../../../pagination/pagination-component-options.model'; -import { getRemoteDataPayload, getFirstSucceededRemoteData } from '../../../../../../../core/shared/operators'; -import { take } from 'rxjs/operators'; +import { getFirstSucceededRemoteData, getRemoteDataPayload } from '../../../../../../../core/shared/operators'; +import { mergeMap, take } from 'rxjs/operators'; import { ItemSearchResult } from '../../../../../../object-collection/shared/item-search-result.model'; import { NotificationsService } from '../../../../../../notifications/notifications.service'; import { TranslateService } from '@ngx-translate/core'; +import { ItemType } from '../../../../../../../core/shared/item-relationships/item-type.model'; +import { SubmissionImportExternalCollectionComponent } from '../../../../../../../submission/import-external/import-external-collection/submission-import-external-collection.component'; +import { CollectionListEntry } from '../../../../../../collection-dropdown/collection-dropdown.component'; /** * The possible types of import for the external entry @@ -67,16 +69,6 @@ export class ExternalSourceEntryImportModalComponent implements OnInit { */ item: Item; - /** - * The collection the user is submitting in - */ - collection: Collection; - - /** - * The ID of the collection to import entries to - */ - collectionId: string; - /** * The current relationship-options used for filtering results */ @@ -147,8 +139,19 @@ export class ExternalSourceEntryImportModalComponent implements OnInit { */ authorityEnabled = false; + /** + * The entity types compatible with the given external source + */ + relatedEntityType: ItemType; + + /** + * The modal for the collection selection + */ + modalRef: NgbModalRef; + constructor(public modal: NgbActiveModal, public lookupRelationService: LookupRelationService, + private modalService: NgbModal, private selectService: SelectableListService, private itemService: ItemDataService, private notificationsService: NotificationsService, @@ -160,7 +163,6 @@ export class ExternalSourceEntryImportModalComponent implements OnInit { const pagination = Object.assign(new PaginationComponentOptions(), { id: 'external-entry-import', pageSize: 5 }); this.searchOptions = Object.assign(new PaginatedSearchOptions({ query: this.externalSourceEntry.value, pagination: pagination })); this.localEntitiesRD$ = this.lookupRelationService.getLocalResults(this.relationship, this.searchOptions); - this.collectionId = this.collection.id; } /** @@ -211,10 +213,19 @@ export class ExternalSourceEntryImportModalComponent implements OnInit { * Create and import a new entity from the external entry */ importNewEntity() { - this.itemService.importExternalSourceEntry(this.externalSourceEntry, this.collectionId).pipe( - getFirstSucceededRemoteData(), - getRemoteDataPayload(), - take(1) + this.modalRef = this.modalService.open(SubmissionImportExternalCollectionComponent, { + size: 'lg', + }); + this.modalRef.componentInstance.entityType = this.relatedEntityType.label; + + this.modalRef.componentInstance.selectedEvent.pipe( + mergeMap((collectionListEntry: CollectionListEntry) => { + return this.itemService.importExternalSourceEntry(this.externalSourceEntry, collectionListEntry.collection.id).pipe( + getFirstSucceededRemoteData(), + getRemoteDataPayload(), + take(1) + ); + }) ).subscribe((item: Item) => { this.lookupRelationService.removeLocalResultsCache(); const searchResult = Object.assign(new ItemSearchResult(), { diff --git a/src/app/shared/mocks/external-source.service.mock.ts b/src/app/shared/mocks/external-source.service.mock.ts index 89b2927939..f1afed19af 100644 --- a/src/app/shared/mocks/external-source.service.mock.ts +++ b/src/app/shared/mocks/external-source.service.mock.ts @@ -11,6 +11,9 @@ export const externalSourceOrcid: ExternalSource = { entries: { href: 'https://dspace7.4science.cloud/server/api/integration/externalsources/orcid/entries' }, + entityTypes: { + href: 'https://dspace7.4science.cloud/server/api/integration/externalsources/my_staff_db/entityTypes' + }, self: { href: 'https://dspace7.4science.cloud/server/api/integration/externalsources/orcid' } @@ -26,6 +29,9 @@ export const externalSourceCiencia: ExternalSource = { entries: { href: 'https://dspace7.4science.cloud/server/api/integration/externalsources/ciencia/entries' }, + entityTypes: { + href: 'https://dspace7.4science.cloud/server/api/integration/externalsources/my_staff_db/entityTypes' + }, self: { href: 'https://dspace7.4science.cloud/server/api/integration/externalsources/ciencia' } @@ -41,6 +47,9 @@ export const externalSourceMyStaffDb: ExternalSource = { entries: { href: 'https://dspace7.4science.cloud/server/api/integration/externalsources/my_staff_db/entries' }, + entityTypes: { + href: 'https://dspace7.4science.cloud/server/api/integration/externalsources/my_staff_db/entityTypes' + }, self: { href: 'https://dspace7.4science.cloud/server/api/integration/externalsources/my_staff_db' } diff --git a/src/assets/i18n/en.json5 b/src/assets/i18n/en.json5 index a90d6329bf..20f9b8ca30 100644 --- a/src/assets/i18n/en.json5 +++ b/src/assets/i18n/en.json5 @@ -1193,6 +1193,8 @@ "dso-selector.placeholder": "Search for a {{ type }}", + "dso-selector.select.collection.head": "Select a collection", + "confirmation-modal.export-metadata.header": "Export metadata for {{ dsoName }}", @@ -3730,6 +3732,7 @@ "vocabulary-treeview.tree.description.srsc": "Research Subject Categories", + "unset.listelement.badge": "Untyped", "uploader.browse": "browse",