also add relationships one by one on the edit item relationships tab

(cherry picked from commit 8e59b7d0b0)
This commit is contained in:
Art Lowel
2024-04-11 17:51:59 +02:00
committed by Alexandre Vryghem
parent d8a24686ec
commit 17d1f2e6ac
2 changed files with 120 additions and 77 deletions

View File

@@ -155,8 +155,11 @@ export class RelationshipDataService extends IdentifiableDataService<Relationshi
* @param id the ID of the relationship to delete
* @param copyVirtualMetadata whether to copy this relationship's virtual metadata to the related Items
* accepted values: none, all, left, right, configured
* @param shouldRefresh refresh the cache for the items in the relationship after creating
* it. Disable this if you want to add relationships in bulk, and
* want to refresh the cachemanually at the end
*/
deleteRelationship(id: string, copyVirtualMetadata: string): Observable<RemoteData<NoContent>> {
deleteRelationship(id: string, copyVirtualMetadata: string, shouldRefresh = true): Observable<RemoteData<NoContent>> {
return this.getRelationshipEndpoint(id).pipe(
isNotEmptyOperator(),
take(1),
@@ -167,7 +170,11 @@ export class RelationshipDataService extends IdentifiableDataService<Relationshi
sendRequest(this.requestService),
switchMap((restRequest: RestRequest) => this.rdbService.buildFromRequestUUID(restRequest.uuid)),
getFirstCompletedRemoteData(),
tap(() => this.refreshRelationshipItemsInCacheByRelationship(id)),
tap(() => {
if (shouldRefresh) {
this.refreshRelationshipItemsInCacheByRelationship(id);
}
}),
);
}
@@ -178,8 +185,11 @@ export class RelationshipDataService extends IdentifiableDataService<Relationshi
* @param item2 The second item of the relationship
* @param leftwardValue The leftward value of the relationship
* @param rightwardValue The rightward value of the relationship
* @param shouldRefresh refresh the cache for the items in the relationship after creating it.
* Disable this if you want to add relationships in bulk, and want to refresh
* the cache manually at the end
*/
addRelationship(typeId: string, item1: Item, item2: Item, leftwardValue?: string, rightwardValue?: string): Observable<RemoteData<Relationship>> {
addRelationship(typeId: string, item1: Item, item2: Item, leftwardValue?: string, rightwardValue?: string, shouldRefresh = true): Observable<RemoteData<Relationship>> {
const options: HttpOptions = Object.create({});
let headers = new HttpHeaders();
headers = headers.append('Content-Type', 'text/uri-list');
@@ -194,8 +204,12 @@ export class RelationshipDataService extends IdentifiableDataService<Relationshi
sendRequest(this.requestService),
switchMap((restRequest: RestRequest) => this.rdbService.buildFromRequestUUID(restRequest.uuid)),
getFirstCompletedRemoteData(),
tap(() => this.refreshRelationshipItemsInCache(item1)),
tap(() => this.refreshRelationshipItemsInCache(item2)),
tap(() => {
if (shouldRefresh) {
this.refreshRelationshipItemsInCache(item1);
this.refreshRelationshipItemsInCache(item2);
}
}),
) as Observable<RemoteData<Relationship>>;
}

View File

@@ -17,16 +17,17 @@ import {
TranslateService,
} from '@ngx-translate/core';
import {
BehaviorSubject,
combineLatest as observableCombineLatest,
EMPTY,
Observable,
of as observableOf,
zip as observableZip,
} from 'rxjs';
import {
concatMap,
map,
startWith,
switchMap,
take,
toArray,
} from 'rxjs/operators';
import { ObjectCacheService } from '../../../core/cache/object-cache.service';
@@ -91,7 +92,7 @@ export class ItemRelationshipsComponent extends AbstractItemUpdateComponent {
/**
* The item's entity type as an observable
*/
entityType$: Observable<ItemType>;
entityType$: BehaviorSubject<ItemType> = new BehaviorSubject(undefined);
constructor(
public itemService: ItemDataService,
@@ -123,13 +124,13 @@ export class ItemRelationshipsComponent extends AbstractItemUpdateComponent {
map((relationshipTypes: PaginatedList<RelationshipType>) => relationshipTypes.page),
);
this.entityType$ = this.entityTypeService.getEntityTypeByLabel(label).pipe(
this.entityTypeService.getEntityTypeByLabel(label).pipe(
getFirstSucceededRemoteData(),
getRemoteDataPayload(),
);
).subscribe((type) => this.entityType$.next(type));
} else {
this.entityType$ = observableOf(undefined);
this.entityType$.next(undefined);
}
}
@@ -147,8 +148,7 @@ export class ItemRelationshipsComponent extends AbstractItemUpdateComponent {
public submit(): void {
// Get all the relationships that should be removed
const removedRelationshipIDs$: Observable<DeleteRelationship[]> = this.relationshipService.getItemRelationshipsArray(this.item).pipe(
startWith([]),
const removeUpdates$: Observable<FieldUpdate[]> = this.relationshipService.getItemRelationshipsArray(this.item).pipe(
map((relationships: Relationship[]) => relationships.map((relationship) =>
Object.assign(new Relationship(), relationship, { uuid: relationship.id }),
)),
@@ -157,84 +157,113 @@ export class ItemRelationshipsComponent extends AbstractItemUpdateComponent {
}),
map((fieldUpdates: FieldUpdates) =>
Object.values(fieldUpdates)
.filter((fieldUpdate: FieldUpdate) => fieldUpdate.changeType === FieldChangeType.REMOVE)
.map((fieldUpdate: FieldUpdate) => fieldUpdate.field as DeleteRelationship),
.filter((fieldUpdate: FieldUpdate) => fieldUpdate.changeType === FieldChangeType.REMOVE),
),
take(1),
);
const addRelatedItems$: Observable<RelationshipIdentifiable[]> = this.objectUpdatesService.getFieldUpdates(this.url, []).pipe(
const addUpdates$: Observable<FieldUpdate[]> = this.objectUpdatesService.getFieldUpdates(this.url, []).pipe(
map((fieldUpdates: FieldUpdates) =>
Object.values(fieldUpdates)
.filter((fieldUpdate: FieldUpdate) => hasValue(fieldUpdate))
.filter((fieldUpdate: FieldUpdate) => fieldUpdate.changeType === FieldChangeType.ADD)
.map((fieldUpdate: FieldUpdate) => fieldUpdate.field as RelationshipIdentifiable),
.filter((fieldUpdate: FieldUpdate) => fieldUpdate.changeType === FieldChangeType.ADD),
),
take(1),
);
observableCombineLatest(
removedRelationshipIDs$,
addRelatedItems$,
).pipe(
observableCombineLatest([
removeUpdates$,
addUpdates$,
]).pipe(
take(1),
).subscribe(([removeRelationshipIDs, addRelatedItems]) => {
const actions = [
this.deleteRelationships(removeRelationshipIDs),
this.addRelationships(addRelatedItems),
];
actions.forEach((action) =>
action.subscribe((response) => {
if (response.length > 0) {
this.initializeOriginalFields();
this.cdr.detectChanges();
this.displayNotifications(response);
this.modalService.dismissAll();
}
}),
);
switchMap(([removeUpdates, addUpdates]) => [...removeUpdates, ...addUpdates]),
concatMap((update: FieldUpdate) => {
if (update.changeType === FieldChangeType.REMOVE) {
return this.deleteRelationship(update.field as DeleteRelationship).pipe(take(1));
} else if (update.changeType === FieldChangeType.ADD) {
return this.addRelationship(update.field as RelationshipIdentifiable).pipe(
take(1),
switchMap((relationshipRD: RemoteData<Relationship>) => {
if (relationshipRD.hasSucceeded) {
// Set the newly related item to stale, so its relationships will update to include
// the new one. Only set the current item to stale at the very end so we only do it
// once
const { leftItem, rightItem } = relationshipRD.payload._links;
if (leftItem.href === this.item.self) {
return this.itemService.invalidateByHref(rightItem.href).pipe(
// when it's invalidated, emit the original relationshipRD for use in the pipe below
map(() => relationshipRD),
);
} else {
return this.itemService.invalidateByHref(leftItem.href).pipe(
// when it's invalidated, emit the original relationshipRD for use in the pipe below
map(() => relationshipRD),
);
}
} else {
return [relationshipRD];
}
}),
);
} else {
return EMPTY;
}
}),
toArray(),
switchMap((responses) => {
// once all relationships are made and all related items have been invalidated, invalidate
// the current item
return this.itemService.invalidateByHref(this.item.self).pipe(
map(() => responses),
);
}),
).subscribe((responses) => {
if (responses.length > 0) {
this.initializeOriginalFields();
this.displayNotifications(responses);
this.modalService.dismissAll();
}
});
}
deleteRelationships(deleteRelationshipIDs: DeleteRelationship[]): Observable<RemoteData<NoContent>[]> {
return observableZip(...deleteRelationshipIDs.map((deleteRelationship) => {
let copyVirtualMetadata: string;
if (deleteRelationship.keepLeftVirtualMetadata && deleteRelationship.keepRightVirtualMetadata) {
copyVirtualMetadata = 'all';
} else if (deleteRelationship.keepLeftVirtualMetadata) {
copyVirtualMetadata = 'left';
} else if (deleteRelationship.keepRightVirtualMetadata) {
copyVirtualMetadata = 'right';
} else {
copyVirtualMetadata = 'none';
}
return this.relationshipService.deleteRelationship(deleteRelationship.uuid, copyVirtualMetadata);
},
));
deleteRelationship(deleteRelationship: DeleteRelationship): Observable<RemoteData<NoContent>> {
let copyVirtualMetadata: string;
if (deleteRelationship.keepLeftVirtualMetadata && deleteRelationship.keepRightVirtualMetadata) {
copyVirtualMetadata = 'all';
} else if (deleteRelationship.keepLeftVirtualMetadata) {
copyVirtualMetadata = 'left';
} else if (deleteRelationship.keepRightVirtualMetadata) {
copyVirtualMetadata = 'right';
} else {
copyVirtualMetadata = 'none';
}
return this.relationshipService.deleteRelationship(deleteRelationship.uuid, copyVirtualMetadata, false);
}
addRelationships(addRelatedItems: RelationshipIdentifiable[]): Observable<RemoteData<Relationship>[]> {
return observableZip(...addRelatedItems.map((addRelationship) =>
this.entityType$.pipe(
switchMap((entityType) => this.entityTypeService.isLeftType(addRelationship.type, entityType)),
switchMap((isLeftType) => {
let leftItem: Item;
let rightItem: Item;
let leftwardValue: string;
let rightwardValue: string;
if (isLeftType) {
leftItem = this.item;
rightItem = addRelationship.relatedItem;
leftwardValue = null;
rightwardValue = addRelationship.nameVariant;
} else {
leftItem = addRelationship.relatedItem;
rightItem = this.item;
leftwardValue = addRelationship.nameVariant;
rightwardValue = null;
}
return this.relationshipService.addRelationship(addRelationship.type.id, leftItem, rightItem, leftwardValue, rightwardValue);
}),
),
));
addRelationship(addRelationship: RelationshipIdentifiable): Observable<RemoteData<Relationship>> {
return this.entityType$.pipe(
switchMap((entityType) => this.entityTypeService.isLeftType(addRelationship.type, entityType)),
switchMap((isLeftType) => {
let leftItem: Item;
let rightItem: Item;
let leftwardValue: string;
let rightwardValue: string;
if (isLeftType) {
leftItem = this.item;
rightItem = addRelationship.relatedItem;
leftwardValue = null;
rightwardValue = addRelationship.nameVariant;
} else {
leftItem = addRelationship.relatedItem;
rightItem = this.item;
leftwardValue = addRelationship.nameVariant;
rightwardValue = null;
}
return this.relationshipService.addRelationship(addRelationship.type.id, leftItem, rightItem, leftwardValue, rightwardValue, false);
}),
);
}
/**