fix issue where the first relationship of a type wouldn't be added

This commit is contained in:
Art Lowel
2020-04-02 10:22:08 +02:00
parent 6dbc2ef880
commit 29e6f6f72f
10 changed files with 82 additions and 7 deletions

View File

@@ -105,6 +105,7 @@ export class ServerSyncBufferEffects {
if (isNotEmpty(entry.patches)) { if (isNotEmpty(entry.patches)) {
const flatPatch: Operation[] = [].concat(...entry.patches.map((patch) => patch.operations)); const flatPatch: Operation[] = [].concat(...entry.patches.map((patch) => patch.operations));
if (isNotEmpty(flatPatch)) { if (isNotEmpty(flatPatch)) {
// if (href.match(/https://dspace7-ben.atmire.com/server/api/core/relationships/\d+/))
this.requestService.configure(new PatchRequest(this.requestService.generateRequestId(), href, flatPatch)); this.requestService.configure(new PatchRequest(this.requestService.generateRequestId(), href, flatPatch));
} }
} }

View File

@@ -509,7 +509,15 @@ export abstract class DataService<T extends CacheableObject> {
this.requestService.commit(method); this.requestService.commit(method);
} }
getLinkPath() { /**
* Return the links to traverse from the root of the api to the
* endpoint this DataService represents
*
* e.g. if the api root links to 'foo', and the endpoint at 'foo'
* links to 'bar' the linkPath for the BarDataService would be
* 'foo/bar'
*/
getLinkPath(): string {
return this.linkPath; return this.linkPath;
} }
} }

View File

@@ -3,9 +3,9 @@ import { Injectable } from '@angular/core';
import { Store } from '@ngrx/store'; import { Store } from '@ngrx/store';
import { combineLatest as observableCombineLatest } from 'rxjs'; import { combineLatest as observableCombineLatest } from 'rxjs';
import { Observable } from 'rxjs/internal/Observable'; import { Observable } from 'rxjs/internal/Observable';
import { filter, find, map, switchMap } from 'rxjs/operators'; import { filter, find, map, switchMap, tap, mergeMap } from 'rxjs/operators';
import { AppState } from '../../app.reducer'; import { AppState } from '../../app.reducer';
import { isNotUndefined } from '../../shared/empty.util'; import { isNotUndefined, hasValue, isNotEmpty } from '../../shared/empty.util';
import { NotificationsService } from '../../shared/notifications/notifications.service'; import { NotificationsService } from '../../shared/notifications/notifications.service';
import { followLink } from '../../shared/utils/follow-link-config.model'; import { followLink } from '../../shared/utils/follow-link-config.model';
import { dataService } from '../cache/builders/build-decorators'; import { dataService } from '../cache/builders/build-decorators';
@@ -76,7 +76,7 @@ export class RelationshipTypeService extends DataService<RelationshipType> {
getSucceededRemoteData(), getSucceededRemoteData(),
/* Flatten the page so we can treat it like an observable */ /* Flatten the page so we can treat it like an observable */
switchMap((typeListRD: RemoteData<PaginatedList<RelationshipType>>) => typeListRD.payload.page), switchMap((typeListRD: RemoteData<PaginatedList<RelationshipType>>) => typeListRD.payload.page),
switchMap((type: RelationshipType) => { mergeMap((type: RelationshipType) => {
if (type.leftwardType === label) { if (type.leftwardType === label) {
return this.checkType(type, firstType, secondType); return this.checkType(type, firstType, secondType);
} else if (type.rightwardType === label) { } else if (type.rightwardType === label) {
@@ -92,7 +92,7 @@ export class RelationshipTypeService extends DataService<RelationshipType> {
// returns a void observable if there's not match // returns a void observable if there's not match
// returns an observable that emits the relationship type when there is a match // returns an observable that emits the relationship type when there is a match
private checkType(type: RelationshipType, firstType: string, secondType: string): Observable<RelationshipType> { private checkType(type: RelationshipType, firstType: string, secondType: string): Observable<RelationshipType> {
const entityTypes = observableCombineLatest(type.leftType.pipe(getSucceededRemoteData()), type.rightType.pipe(getSucceededRemoteData())); const entityTypes = observableCombineLatest([type.leftType.pipe(getSucceededRemoteData()), type.rightType.pipe(getSucceededRemoteData())]);
return entityTypes.pipe( return entityTypes.pipe(
find(([leftTypeRD, rightTypeRD]: [RemoteData<ItemType>, RemoteData<ItemType>]) => leftTypeRD.payload.label === firstType && rightTypeRD.payload.label === secondType), find(([leftTypeRD, rightTypeRD]: [RemoteData<ItemType>, RemoteData<ItemType>]) => leftTypeRD.payload.label === firstType && rightTypeRD.payload.label === secondType),
filter((types) => isNotUndefined(types)), filter((types) => isNotUndefined(types)),

View File

@@ -114,6 +114,7 @@ export class RelationshipService extends DataService<Relationship> {
* @param rightwardValue The rightward value of the relationship * @param rightwardValue The rightward value of the relationship
*/ */
addRelationship(typeId: string, item1: Item, item2: Item, leftwardValue?: string, rightwardValue?: string): Observable<RestResponse> { addRelationship(typeId: string, item1: Item, item2: Item, leftwardValue?: string, rightwardValue?: string): Observable<RestResponse> {
console.log('addRelationship', typeId, item1, item2, leftwardValue, rightwardValue);
const options: HttpOptions = Object.create({}); const options: HttpOptions = Object.create({});
let headers = new HttpHeaders(); let headers = new HttpHeaders();
headers = headers.append('Content-Type', 'text/uri-list'); headers = headers.append('Content-Type', 'text/uri-list');

View File

@@ -65,6 +65,14 @@ export class JsonPatchOperationsBuilder {
} }
} }
/**
* Dispatch a new NewPatchMoveOperationAction
*
* @param path
* the new path tho move to
* @param prevPath
* the original path to move from
*/
move(path: JsonPatchOperationPathObject, prevPath: string) { move(path: JsonPatchOperationPathObject, prevPath: string) {
this.store.dispatch( this.store.dispatch(
new NewPatchMoveOperationAction( new NewPatchMoveOperationAction(

View File

@@ -294,6 +294,20 @@ function flushOperation(state: JsonPatchOperationsState, action: FlushPatchOpera
} }
} }
/**
* Add a new operation to a patch
*
* @param body
* The current patch
* @param actionType
* The type of operation to add
* @param targetPath
* The path for the operation
* @param value
* The new value
* @param fromPath
* The previous path (in case of a move operation)
*/
function addOperationToList(body: JsonPatchOperationObject[], actionType, targetPath, value?, fromPath?) { function addOperationToList(body: JsonPatchOperationObject[], actionType, targetPath, value?, fromPath?) {
const newBody = Array.from(body); const newBody = Array.from(body);
switch (actionType) { switch (actionType) {

View File

@@ -358,6 +358,9 @@ export class DsDynamicFormControlContainerComponent extends DynamicFormControlCo
.forEach((sub) => sub.unsubscribe()); .forEach((sub) => sub.unsubscribe());
} }
/**
* Initialize this.item$ based on this.model.submissionId
*/
private setItem() { private setItem() {
const submissionObject$ = this.submissionObjectService const submissionObject$ = this.submissionObjectService
.findById(this.model.submissionId, followLink('item'), followLink('collection')).pipe( .findById(this.model.submissionId, followLink('item'), followLink('collection')).pipe(

View File

@@ -35,17 +35,33 @@ export abstract class Reorderable {
constructor(public oldIndex?: number, public newIndex?: number) { constructor(public oldIndex?: number, public newIndex?: number) {
} }
/**
* Return the id for this Reorderable
*/
abstract getId(): string; abstract getId(): string;
/**
* Return the place metadata for this Reorderable
*/
abstract getPlace(): number; abstract getPlace(): number;
/**
* Update the Reorderable
*/
abstract update(): Observable<any>; abstract update(): Observable<any>;
/**
* Returns true if the oldIndex of this Reorderable
* differs from the newIndex
*/
get hasMoved(): boolean { get hasMoved(): boolean {
return this.oldIndex !== this.newIndex return this.oldIndex !== this.newIndex
} }
} }
/**
* A Reorderable representation of a FormFieldMetadataValue
*/
export class ReorderableFormFieldMetadataValue extends Reorderable { export class ReorderableFormFieldMetadataValue extends Reorderable {
constructor( constructor(
@@ -60,6 +76,9 @@ export class ReorderableFormFieldMetadataValue extends Reorderable {
this.metadataValue = metadataValue; this.metadataValue = metadataValue;
} }
/**
* Return the id for this Reorderable
*/
getId(): string { getId(): string {
if (hasValue(this.metadataValue.authority)) { if (hasValue(this.metadataValue.authority)) {
return this.metadataValue.authority; return this.metadataValue.authority;
@@ -69,10 +88,16 @@ export class ReorderableFormFieldMetadataValue extends Reorderable {
} }
} }
/**
* Return the place metadata for this Reorderable
*/
getPlace(): number { getPlace(): number {
return this.metadataValue.place; return this.metadataValue.place;
} }
/**
* Update the Reorderable
*/
update(): Observable<FormFieldMetadataValueObject> { update(): Observable<FormFieldMetadataValueObject> {
this.oldIndex = this.newIndex; this.oldIndex = this.newIndex;
return observableOf(this.metadataValue); return observableOf(this.metadataValue);
@@ -98,10 +123,16 @@ export class ReorderableRelationship extends Reorderable {
this.useLeftItem = useLeftItem; this.useLeftItem = useLeftItem;
} }
/**
* Return the id for this Reorderable
*/
getId(): string { getId(): string {
return this.relationship.id; return this.relationship.id;
} }
/**
* Return the place metadata for this Reorderable
*/
getPlace(): number { getPlace(): number {
if (this.useLeftItem) { if (this.useLeftItem) {
return this.relationship.rightPlace return this.relationship.rightPlace
@@ -110,6 +141,9 @@ export class ReorderableRelationship extends Reorderable {
} }
} }
/**
* Update the Reorderable
*/
update(): Observable<RemoteData<Relationship>> { update(): Observable<RemoteData<Relationship>> {
this.store.dispatch(new UpdateRelationshipAction(this.relationship, this.submissionID)) this.store.dispatch(new UpdateRelationshipAction(this.relationship, this.submissionID))
const updatedRelationship$ = this.relationshipService.updatePlace(this).pipe( const updatedRelationship$ = this.relationshipService.updatePlace(this).pipe(
@@ -154,6 +188,9 @@ export class ExistingMetadataListElementComponent implements OnChanges, OnDestro
) { ) {
} }
/**
* Change callback for the component
*/
ngOnChanges() { ngOnChanges() {
if (hasValue(this.reoRel)) { if (hasValue(this.reoRel)) {
const item$ = this.reoRel.useLeftItem ? const item$ = this.reoRel.useLeftItem ?

View File

@@ -144,6 +144,7 @@ export class DsDynamicLookupRelationModalComponent implements OnInit, OnDestroy
* @param selectableObjects * @param selectableObjects
*/ */
select(...selectableObjects: Array<SearchResult<Item>>) { select(...selectableObjects: Array<SearchResult<Item>>) {
console.log('selectableObjects', selectableObjects);
this.zone.runOutsideAngular( this.zone.runOutsideAngular(
() => { () => {
const obs: Observable<any[]> = combineLatest(...selectableObjects.map((sri: SearchResult<Item>) => { const obs: Observable<any[]> = combineLatest(...selectableObjects.map((sri: SearchResult<Item>) => {
@@ -163,7 +164,9 @@ export class DsDynamicLookupRelationModalComponent implements OnInit, OnDestroy
obs obs
.subscribe((arr: any[]) => { .subscribe((arr: any[]) => {
return arr.forEach((object: any) => { return arr.forEach((object: any) => {
this.store.dispatch(new AddRelationshipAction(this.item, object.item, this.relationshipOptions.relationshipType, this.submissionId, object.nameVariant)); const addRelationshipAction = new AddRelationshipAction(this.item, object.item, this.relationshipOptions.relationshipType, this.submissionId, object.nameVariant);
console.log('addRelationshipAction', addRelationshipAction);
this.store.dispatch(addRelationshipAction);
} }
); );
}) })

View File

@@ -21,7 +21,7 @@ import { ServerSyncBufferActionTypes } from '../../../../../core/cache/server-sy
import { CommitPatchOperationsAction, JsonPatchOperationsActionTypes, PatchOperationsActions } from '../../../../../core/json-patch/json-patch-operations.actions'; import { CommitPatchOperationsAction, JsonPatchOperationsActionTypes, PatchOperationsActions } from '../../../../../core/json-patch/json-patch-operations.actions';
import { followLink } from '../../../../utils/follow-link-config.model'; import { followLink } from '../../../../utils/follow-link-config.model';
const DEBOUNCE_TIME = 5000; const DEBOUNCE_TIME = 500;
/** /**
* NGRX effects for RelationshipEffects * NGRX effects for RelationshipEffects