1
0

[CST-4591] Use search collection dropdown when importing from external source with lookup modal

This commit is contained in:
Giuseppe Digilio
2021-09-24 13:20:36 +02:00
parent c6a73f2dcb
commit d29c27b400
9 changed files with 90 additions and 32 deletions

View File

@@ -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<RemoteData<PaginatedList<ItemType>>>;
/**
* The {@link HALLink}s for this ExternalSource
*/
@@ -45,5 +57,6 @@ export class ExternalSource extends CacheableObject {
_links: {
self: HALLink;
entries: HALLink;
entityTypes: HALLink;
};
}

View File

@@ -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()
);

View File

@@ -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({

View File

@@ -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<PaginatedList<ItemType>>) => {
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);

View File

@@ -17,13 +17,6 @@
<div id="external-source-entry-entities" class="mb-3">
<h5 class="font-weight-bold">{{ (labelPrefix + 'entities' | translate) }}</h5>
<div id="external-source-entry-collection" class="mb-3">
<div class="form-group">
<label for="collection">{{ (labelPrefix + 'collection' | translate) }}</label>
<input type="text" class="form-control" id="collection" placeholder="Enter collection ID" [(ngModel)]="collectionId">
</div>
</div>
<ds-search-results *ngIf="(localEntitiesRD$ | async)?.payload?.page?.length > 0"
[searchResults]="(localEntitiesRD$ | async)"
[sortConfig]="this.lookupRelationService.searchConfig?.sort"

View File

@@ -86,7 +86,6 @@ describe('DsDynamicLookupRelationExternalSourceTabComponent', () => {
component.externalSourceEntry = entry;
component.label = label;
component.relationship = relationship;
component.collection = submissionCollection;
component.item = submissionItem;
fixture.detectChanges();
});

View File

@@ -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(
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(), {

View File

@@ -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'
}

View File

@@ -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",