1+
12import {
23 Inject ,
34 Injectable ,
@@ -12,13 +13,16 @@ import { TranslateService } from '@ngx-translate/core';
1213import {
1314 BehaviorSubject ,
1415 Observable ,
16+ Subject ,
1517} from 'rxjs' ;
1618import {
19+ concatMap ,
1720 filter ,
1821 map ,
1922 mergeMap ,
2023 switchMap ,
2124 take ,
25+ tap ,
2226} from 'rxjs/operators' ;
2327
2428import { ObjectCacheService } from '../../../../../core/cache/object-cache.service' ;
@@ -58,11 +62,31 @@ import {
5862
5963const DEBOUNCE_TIME = 500 ;
6064
65+ enum RelationOperationType {
66+ Add ,
67+ Remove ,
68+ }
69+
70+ interface RelationOperation {
71+ type : RelationOperationType
72+ item1 : Item
73+ item2 : Item
74+ relationshipType : string
75+ submissionId : string
76+ nameVariant ?: string
77+ }
78+
6179/**
6280 * NGRX effects for RelationshipEffects
6381 */
6482@Injectable ( )
6583export class RelationshipEffects {
84+
85+ /**
86+ * Queue to hold all requests, so we can ensure they get sent one at a time
87+ */
88+ private requestQueue : Subject < RelationOperation > = new Subject ( ) ;
89+
6690 /**
6791 * Map that keeps track of the latest RelationshipEffects for each relationship's composed identifier
6892 */
@@ -104,9 +128,22 @@ export class RelationshipEffects {
104128 nameVariant = this . nameVariantUpdates [ identifier ] ;
105129 delete this . nameVariantUpdates [ identifier ] ;
106130 }
107- this . addRelationship ( item1 , item2 , relationshipType , submissionId , nameVariant ) ;
131+ this . requestQueue . next ( {
132+ type : RelationOperationType . Add ,
133+ item1,
134+ item2,
135+ relationshipType,
136+ submissionId,
137+ nameVariant,
138+ } ) ;
108139 } else {
109- this . removeRelationship ( item1 , item2 , relationshipType , submissionId ) ;
140+ this . requestQueue . next ( {
141+ type : RelationOperationType . Remove ,
142+ item1,
143+ item2,
144+ relationshipType,
145+ submissionId,
146+ } ) ;
110147 }
111148 }
112149 delete this . debounceMap [ identifier ] ;
@@ -183,8 +220,41 @@ export class RelationshipEffects {
183220 private selectableListService : SelectableListService ,
184221 @Inject ( DEBOUNCE_TIME_OPERATOR ) private debounceTime : < T > ( dueTime : number ) => ( source : Observable < T > ) => Observable < T > ,
185222 ) {
223+ this . executeRequestsInQueue ( ) ;
186224 }
187225
226+ /**
227+ * Subscribe to the request queue, execute the requests inside. Wait for each request to complete
228+ * before sending the next one
229+ * @private
230+ */
231+ private executeRequestsInQueue ( ) {
232+ this . requestQueue . pipe (
233+ // concatMap ensures the next request in the queue will only start after the previous one has emitted
234+ concatMap ( ( next : RelationOperation ) => {
235+ switch ( next . type ) {
236+ case RelationOperationType . Add :
237+ return this . addRelationship ( next . item1 , next . item2 , next . relationshipType , next . submissionId , next . nameVariant ) . pipe (
238+ map ( ( ) => next ) ,
239+ ) ;
240+ case RelationOperationType . Remove :
241+ return this . removeRelationship ( next . item1 , next . item2 , next . relationshipType ) . pipe (
242+ map ( ( ) => next ) ,
243+ ) ;
244+ default :
245+ return [ next ] ;
246+ }
247+ } ) ,
248+ // refresh the workspaceitem after each request. It would be great if we could find a way to
249+ // optimize this so it only happens when the queue is empty.
250+ switchMap ( ( next : RelationOperation ) => this . refreshWorkspaceItemInCache ( next . submissionId ) ) ,
251+ // update the form after the workspaceitem is refreshed
252+ ) . subscribe ( ( next : SubmissionObject ) => {
253+ this . store . dispatch ( new SaveSubmissionSectionFormSuccessAction ( next . id , [ next ] , false ) ) ;
254+ } ) ;
255+ }
256+
257+
188258 private createIdentifier ( item1 : Item , item2 : Item , relationshipType : string ) : string {
189259 return `${ item1 . uuid } -${ item2 . uuid } -${ relationshipType } ` ;
190260 }
@@ -207,7 +277,7 @@ export class RelationshipEffects {
207277 }
208278 } ) ,
209279 take ( 1 ) ,
210- switchMap ( ( rd : RemoteData < Relationship > ) => {
280+ tap ( ( rd : RemoteData < Relationship > ) => {
211281 if ( hasNoValue ( rd ) || rd . hasFailed ) {
212282 // An error occurred, deselect the object from the selectable list and display an error notification
213283 const listId = `list-${ submissionId } -${ relationshipType } ` ;
@@ -225,19 +295,15 @@ export class RelationshipEffects {
225295 }
226296 this . notificationsService . error ( this . translateService . instant ( 'relationships.add.error.title' ) , errorContent ) ;
227297 }
228- return this . refreshWorkspaceItemInCache ( submissionId ) ;
229298 } ) ,
230- ) . subscribe ( ( submissionObject : SubmissionObject ) => this . store . dispatch ( new SaveSubmissionSectionFormSuccessAction ( submissionId , [ submissionObject ] , false ) ) ) ;
299+ ) ;
231300 }
232301
233- private removeRelationship ( item1 : Item , item2 : Item , relationshipType : string , submissionId : string ) {
234- this . relationshipService . getRelationshipByItemsAndLabel ( item1 , item2 , relationshipType ) . pipe (
302+ private removeRelationship ( item1 : Item , item2 : Item , relationshipType : string ) {
303+ return this . relationshipService . getRelationshipByItemsAndLabel ( item1 , item2 , relationshipType ) . pipe (
235304 mergeMap ( ( relationship : Relationship ) => this . relationshipService . deleteRelationship ( relationship . id , 'none' ) ) ,
236305 take ( 1 ) ,
237- switchMap ( ( ) => this . refreshWorkspaceItemInCache ( submissionId ) ) ,
238- ) . subscribe ( ( submissionObject : SubmissionObject ) => {
239- this . store . dispatch ( new SaveSubmissionSectionFormSuccessAction ( submissionId , [ submissionObject ] , false ) ) ;
240- } ) ;
306+ ) ;
241307 }
242308
243309 /**
0 commit comments