mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-07 01:54:15 +00:00
61142: RelationshipService
This commit is contained in:
@@ -1,22 +1,16 @@
|
|||||||
import { Component } from '@angular/core';
|
import { Component, Inject } from '@angular/core';
|
||||||
import { Item } from '../../../core/shared/item.model';
|
import { Item } from '../../../core/shared/item.model';
|
||||||
import { FieldUpdates } from '../../../core/data/object-updates/object-updates.reducer';
|
import { FieldUpdates } from '../../../core/data/object-updates/object-updates.reducer';
|
||||||
import { Observable } from 'rxjs/internal/Observable';
|
import { Observable } from 'rxjs/internal/Observable';
|
||||||
import { distinctUntilChanged, first, flatMap, map, switchMap } from 'rxjs/operators';
|
import { switchMap, take } from 'rxjs/operators';
|
||||||
import { zip as observableZip } from 'rxjs';
|
|
||||||
import { RemoteData } from '../../../core/data/remote-data';
|
|
||||||
import { PaginatedList } from '../../../core/data/paginated-list';
|
|
||||||
import { Relationship } from '../../../core/shared/item-relationships/relationship.model';
|
|
||||||
import { hasValue, hasValueOperator } from '../../../shared/empty.util';
|
|
||||||
import { getRemoteDataPayload, getSucceededRemoteData } from '../../../core/shared/operators';
|
|
||||||
import { RelationshipType } from '../../../core/shared/item-relationships/relationship-type.model';
|
|
||||||
import {
|
|
||||||
compareArraysUsingIds,
|
|
||||||
filterRelationsByTypeLabel,
|
|
||||||
relationsToItems
|
|
||||||
} from '../../simple/item-types/shared/item.component';
|
|
||||||
import { combineLatest as observableCombineLatest } from 'rxjs/internal/observable/combineLatest';
|
|
||||||
import { AbstractItemUpdateComponent } from '../abstract-item-update/abstract-item-update.component';
|
import { AbstractItemUpdateComponent } from '../abstract-item-update/abstract-item-update.component';
|
||||||
|
import { ItemDataService } from '../../../core/data/item-data.service';
|
||||||
|
import { ObjectUpdatesService } from '../../../core/data/object-updates/object-updates.service';
|
||||||
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
|
import { NotificationsService } from '../../../shared/notifications/notifications.service';
|
||||||
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
|
import { GLOBAL_CONFIG, GlobalConfig } from '../../../../config';
|
||||||
|
import { RelationshipService } from '../../../core/data/relationship.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'ds-item-relationships',
|
selector: 'ds-item-relationships',
|
||||||
@@ -33,49 +27,32 @@ export class ItemRelationshipsComponent extends AbstractItemUpdateComponent {
|
|||||||
*/
|
*/
|
||||||
relationLabels$: Observable<string[]>;
|
relationLabels$: Observable<string[]>;
|
||||||
|
|
||||||
/**
|
constructor(
|
||||||
* Resolved relationships and types together in one observable
|
protected itemService: ItemDataService,
|
||||||
*/
|
protected objectUpdatesService: ObjectUpdatesService,
|
||||||
resolvedRelsAndTypes$: Observable<[Relationship[], RelationshipType[]]>;
|
protected router: Router,
|
||||||
|
protected notificationsService: NotificationsService,
|
||||||
|
protected translateService: TranslateService,
|
||||||
|
@Inject(GLOBAL_CONFIG) protected EnvConfig: GlobalConfig,
|
||||||
|
protected route: ActivatedRoute,
|
||||||
|
protected relationshipService: RelationshipService
|
||||||
|
) {
|
||||||
|
super(itemService, objectUpdatesService, router, notificationsService, translateService, EnvConfig, route);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set up and initialize all fields
|
* Set up and initialize all fields
|
||||||
*/
|
*/
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
super.ngOnInit();
|
super.ngOnInit();
|
||||||
this.initRelationshipObservables();
|
this.relationLabels$ = this.relationshipService.getItemRelationshipLabels(this.item);
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize the item's relationship observables for easier access across the component
|
|
||||||
*/
|
|
||||||
initRelationshipObservables() {
|
|
||||||
const relationships$ = this.getRelationships();
|
|
||||||
|
|
||||||
const relationshipTypes$ = relationships$.pipe(
|
|
||||||
flatMap((rels: Relationship[]) =>
|
|
||||||
observableZip(...rels.map((rel: Relationship) => rel.relationshipType)).pipe(
|
|
||||||
map(([...arr]: Array<RemoteData<RelationshipType>>) => arr.map((d: RemoteData<RelationshipType>) => d.payload).filter((type) => hasValue(type)))
|
|
||||||
)
|
|
||||||
),
|
|
||||||
distinctUntilChanged(compareArraysUsingIds())
|
|
||||||
);
|
|
||||||
|
|
||||||
this.resolvedRelsAndTypes$ = observableCombineLatest(
|
|
||||||
relationships$,
|
|
||||||
relationshipTypes$
|
|
||||||
);
|
|
||||||
this.relationLabels$ = relationshipTypes$.pipe(
|
|
||||||
map((types: RelationshipType[]) => Array.from(new Set(types.map((type) => type.leftLabel))))
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize the values and updates of the current item's relationship fields
|
* Initialize the values and updates of the current item's relationship fields
|
||||||
*/
|
*/
|
||||||
public initializeUpdates(): void {
|
public initializeUpdates(): void {
|
||||||
this.updates$ = this.getRelationships().pipe(
|
this.updates$ = this.relationshipService.getRelatedItems(this.item).pipe(
|
||||||
relationsToItems(this.item.id, this.itemService),
|
|
||||||
switchMap((items: Item[]) => this.objectUpdatesService.getFieldUpdates(this.url, items))
|
switchMap((items: Item[]) => this.objectUpdatesService.getFieldUpdates(this.url, items))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -88,9 +65,7 @@ export class ItemRelationshipsComponent extends AbstractItemUpdateComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public submit(): void {
|
public submit(): void {
|
||||||
const updatedItems$ = this.getRelationships().pipe(
|
const updatedItems$ = this.relationshipService.getRelatedItems(this.item).pipe(
|
||||||
first(),
|
|
||||||
relationsToItems(this.item.id, this.itemService),
|
|
||||||
switchMap((items: Item[]) => this.objectUpdatesService.getUpdatedFields(this.url, items) as Observable<Item[]>)
|
switchMap((items: Item[]) => this.objectUpdatesService.getUpdatedFields(this.url, items) as Observable<Item[]>)
|
||||||
);
|
);
|
||||||
// TODO: Delete relationships
|
// TODO: Delete relationships
|
||||||
@@ -100,36 +75,17 @@ export class ItemRelationshipsComponent extends AbstractItemUpdateComponent {
|
|||||||
* Sends all initial values of this item to the object updates service
|
* Sends all initial values of this item to the object updates service
|
||||||
*/
|
*/
|
||||||
public initializeOriginalFields() {
|
public initializeOriginalFields() {
|
||||||
this.getRelationships().pipe(
|
this.relationshipService.getRelatedItems(this.item).pipe(take(1)).subscribe((items: Item[]) => {
|
||||||
first(),
|
|
||||||
relationsToItems(this.item.id, this.itemService)
|
|
||||||
).subscribe((items: Item[]) => {
|
|
||||||
this.objectUpdatesService.initialize(this.url, items, this.item.lastModified);
|
this.objectUpdatesService.initialize(this.url, items, this.item.lastModified);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Fetch all the relationships of the item
|
|
||||||
*/
|
|
||||||
public getRelationships(): Observable<Relationship[]> {
|
|
||||||
return this.item.relationships.pipe(
|
|
||||||
getSucceededRemoteData(),
|
|
||||||
getRemoteDataPayload(),
|
|
||||||
map((rels: PaginatedList<Relationship>) => rels.page),
|
|
||||||
hasValueOperator(),
|
|
||||||
distinctUntilChanged(compareArraysUsingIds())
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Transform the item's relationships of a specific type into related items
|
* Transform the item's relationships of a specific type into related items
|
||||||
* @param label The relationship type's label
|
* @param label The relationship type's label
|
||||||
*/
|
*/
|
||||||
public getRelatedItemsByLabel(label: string): Observable<Item[]> {
|
public getRelatedItemsByLabel(label: string): Observable<Item[]> {
|
||||||
return this.resolvedRelsAndTypes$.pipe(
|
return this.relationshipService.getRelatedItemsByLabel(this.item, label);
|
||||||
filterRelationsByTypeLabel(label),
|
|
||||||
relationsToItems(this.item.id, this.itemService)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -81,6 +81,7 @@ import { DSOChangeAnalyzer } from './data/dso-change-analyzer.service';
|
|||||||
import { ObjectUpdatesService } from './data/object-updates/object-updates.service';
|
import { ObjectUpdatesService } from './data/object-updates/object-updates.service';
|
||||||
import { DefaultChangeAnalyzer } from './data/default-change-analyzer.service';
|
import { DefaultChangeAnalyzer } from './data/default-change-analyzer.service';
|
||||||
import { SearchService } from '../+search-page/search-service/search.service';
|
import { SearchService } from '../+search-page/search-service/search.service';
|
||||||
|
import { RelationshipService } from './data/relationship.service';
|
||||||
|
|
||||||
const IMPORTS = [
|
const IMPORTS = [
|
||||||
CommonModule,
|
CommonModule,
|
||||||
@@ -163,6 +164,7 @@ const PROVIDERS = [
|
|||||||
MenuService,
|
MenuService,
|
||||||
ObjectUpdatesService,
|
ObjectUpdatesService,
|
||||||
SearchService,
|
SearchService,
|
||||||
|
RelationshipService,
|
||||||
// register AuthInterceptor as HttpInterceptor
|
// register AuthInterceptor as HttpInterceptor
|
||||||
{
|
{
|
||||||
provide: HTTP_INTERCEPTORS,
|
provide: HTTP_INTERCEPTORS,
|
||||||
|
121
src/app/core/data/relationship.service.ts
Normal file
121
src/app/core/data/relationship.service.ts
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { RequestService } from './request.service';
|
||||||
|
import { HALEndpointService } from '../shared/hal-endpoint.service';
|
||||||
|
import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
|
||||||
|
import { hasValue, hasValueOperator, isNotEmptyOperator } from '../../shared/empty.util';
|
||||||
|
import { distinctUntilChanged, flatMap, map, take } from 'rxjs/operators';
|
||||||
|
import {
|
||||||
|
configureRequest,
|
||||||
|
filterSuccessfulResponses,
|
||||||
|
getRemoteDataPayload,
|
||||||
|
getSucceededRemoteData
|
||||||
|
} from '../shared/operators';
|
||||||
|
import { DeleteRequest, RestRequest } from './request.models';
|
||||||
|
import { Observable } from 'rxjs/internal/Observable';
|
||||||
|
import { RestResponse } from '../cache/response.models';
|
||||||
|
import { Item } from '../shared/item.model';
|
||||||
|
import { Relationship } from '../shared/item-relationships/relationship.model';
|
||||||
|
import { RelationshipType } from '../shared/item-relationships/relationship-type.model';
|
||||||
|
import { RemoteData } from './remote-data';
|
||||||
|
import {
|
||||||
|
compareArraysUsingIds,
|
||||||
|
filterRelationsByTypeLabel, relationsToItems
|
||||||
|
} from '../../+item-page/simple/item-types/shared/item.component';
|
||||||
|
import { combineLatest as observableCombineLatest } from 'rxjs/internal/observable/combineLatest';
|
||||||
|
import { zip as observableZip } from 'rxjs';
|
||||||
|
import { PaginatedList } from './paginated-list';
|
||||||
|
import { ItemDataService } from './item-data.service';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The service handling all relationship requests
|
||||||
|
*/
|
||||||
|
@Injectable()
|
||||||
|
export class RelationshipService {
|
||||||
|
protected linkPath = 'relationships';
|
||||||
|
|
||||||
|
constructor(protected requestService: RequestService,
|
||||||
|
protected halService: HALEndpointService,
|
||||||
|
protected rdbService: RemoteDataBuildService,
|
||||||
|
protected itemService: ItemDataService) {
|
||||||
|
}
|
||||||
|
|
||||||
|
getRelationshipEndpoint(uuid: string) {
|
||||||
|
return this.halService.getEndpoint(this.linkPath).pipe(
|
||||||
|
map((href: string) => `${href}/${uuid}`)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
deleteRelationship(uuid: string): Observable<RestResponse> {
|
||||||
|
const requestUuid = this.requestService.generateRequestId();
|
||||||
|
|
||||||
|
this.getRelationshipEndpoint(uuid).pipe(
|
||||||
|
isNotEmptyOperator(),
|
||||||
|
distinctUntilChanged(),
|
||||||
|
map((endpointURL: string) => new DeleteRequest(requestUuid, endpointURL)),
|
||||||
|
configureRequest(this.requestService),
|
||||||
|
take(1)
|
||||||
|
).subscribe();
|
||||||
|
|
||||||
|
return this.requestService.getByUUID(requestUuid).pipe(
|
||||||
|
filterSuccessfulResponses()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
getItemResolvedRelsAndTypes(item: Item): Observable<[Relationship[], RelationshipType[]]> {
|
||||||
|
const relationships$ = this.getItemRelationshipsArray(item);
|
||||||
|
|
||||||
|
const relationshipTypes$ = relationships$.pipe(
|
||||||
|
flatMap((rels: Relationship[]) =>
|
||||||
|
observableZip(...rels.map((rel: Relationship) => rel.relationshipType)).pipe(
|
||||||
|
map(([...arr]: Array<RemoteData<RelationshipType>>) => arr.map((d: RemoteData<RelationshipType>) => d.payload).filter((type) => hasValue(type)))
|
||||||
|
)
|
||||||
|
),
|
||||||
|
distinctUntilChanged(compareArraysUsingIds())
|
||||||
|
);
|
||||||
|
|
||||||
|
return observableCombineLatest(
|
||||||
|
relationships$,
|
||||||
|
relationshipTypes$
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
getItemRelationshipsArray(item: Item): Observable<Relationship[]> {
|
||||||
|
return item.relationships.pipe(
|
||||||
|
getSucceededRemoteData(),
|
||||||
|
getRemoteDataPayload(),
|
||||||
|
map((rels: PaginatedList<Relationship>) => rels.page),
|
||||||
|
hasValueOperator(),
|
||||||
|
distinctUntilChanged(compareArraysUsingIds())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
getItemRelationshipLabels(item: Item): Observable<string[]> {
|
||||||
|
return this.getItemResolvedRelsAndTypes(item).pipe(
|
||||||
|
map(([relsCurrentPage, relTypesCurrentPage]) => {
|
||||||
|
return relTypesCurrentPage.map((type, index) => {
|
||||||
|
const relationship = relsCurrentPage[index];
|
||||||
|
if (relationship.leftId === item.uuid) {
|
||||||
|
return type.leftLabel;
|
||||||
|
} else {
|
||||||
|
return type.rightLabel;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}),
|
||||||
|
map((labels: string[]) => Array.from(new Set(labels)))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
getRelatedItems(item: Item): Observable<Item[]> {
|
||||||
|
return this.getItemRelationshipsArray(item).pipe(
|
||||||
|
relationsToItems(item.uuid, this.itemService)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
getRelatedItemsByLabel(item: Item, label: string): Observable<Item[]> {
|
||||||
|
return this.getItemResolvedRelsAndTypes(item).pipe(
|
||||||
|
filterRelationsByTypeLabel(label),
|
||||||
|
relationsToItems(item.uuid, this.itemService)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Reference in New Issue
Block a user