@@ -977,6 +977,27 @@ qx.Class.define("osparc.desktop.StudyEditor", {
977977 }
978978 } ,
979979
980+ __isEchoLoop : function ( patchData ) {
981+ // check if the patchData is an echo loop, i.e. it is the same as the last synced project document
982+ // if it is, return true
983+ const pathParts = patchData [ "path" ] . split ( "/" ) . slice ( 1 ) ; // remove the first empty part
984+ let currentValue = this . __lastSyncedProjectDocument ;
985+ for ( const part of pathParts ) {
986+ if ( currentValue && part in currentValue ) {
987+ currentValue = currentValue [ part ] ;
988+ } else {
989+ // if the path doesn't exist in the last synced project document, return false
990+ return false ;
991+ }
992+ }
993+ // values can be any type, so we need to check if they are equal
994+ if ( JSON . stringify ( currentValue ) === JSON . stringify ( patchData [ "value" ] ) ) {
995+ // if both values are null, return true
996+ return true ;
997+ }
998+ return false ;
999+ } ,
1000+
9801001 /**
9811002 * @param {JSON Patch } data It will soon be used to patch the project document https://datatracker.ietf.org/doc/html/rfc6902
9821003 */
@@ -985,6 +1006,11 @@ qx.Class.define("osparc.desktop.StudyEditor", {
9851006 if ( osparc . utils . Utils . isDevelopmentPlatform ( ) ) {
9861007 console . log ( "projectDocumentChanged" , patchData ) ;
9871008 }
1009+ // avoid echo loop
1010+ if ( this . __isEchoLoop ( patchData ) ) {
1011+ console . warn ( "Echo loop detected, ignoring patchData" , patchData ) ;
1012+ return ;
1013+ }
9881014
9891015 this . getStudy ( ) . setSavePending ( true ) ;
9901016 // throttling: do not update study document right after a change, wait for THROTTLE_PATCH_TIME
0 commit comments