forked from MapComplete/MapComplete
		
	Only upload changes after 30s, on focus loss or on closing of the popup - this should improve #162 already a lot
This commit is contained in:
		
							parent
							
								
									3fb2b9adab
								
							
						
					
					
						commit
						df483786b3
					
				
					 4 changed files with 88 additions and 7 deletions
				
			
		
							
								
								
									
										54
									
								
								Logic/Actors/PendingChangesUploader.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								Logic/Actors/PendingChangesUploader.ts
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,54 @@
 | 
				
			||||||
 | 
					import {Changes} from "../Osm/Changes";
 | 
				
			||||||
 | 
					import Constants from "../../Models/Constants";
 | 
				
			||||||
 | 
					import {UIEventSource} from "../UIEventSource";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default class PendingChangesUploader{
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    private lastChange : Date;
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    constructor(changes: Changes, selectedFeature: UIEventSource<any>) {
 | 
				
			||||||
 | 
					        const self = this;
 | 
				
			||||||
 | 
					        this.lastChange = new Date();
 | 
				
			||||||
 | 
					        changes.pending.addCallback(() => {
 | 
				
			||||||
 | 
					            self.lastChange = new Date();
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					            window.setTimeout(() => {
 | 
				
			||||||
 | 
					                const diff = (new Date().getTime() - self.lastChange.getTime()) / 1000;
 | 
				
			||||||
 | 
					                if(Constants.updateTimeoutSec >= diff - 1){
 | 
				
			||||||
 | 
					                    changes.flushChanges("Flushing changes due to timeout");
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }, Constants.updateTimeoutSec * 1000);
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        selectedFeature
 | 
				
			||||||
 | 
					            .stabilized(10000)
 | 
				
			||||||
 | 
					            .addCallback(feature => {
 | 
				
			||||||
 | 
					            if(feature === undefined){
 | 
				
			||||||
 | 
					                // The popup got closed - we flush
 | 
				
			||||||
 | 
					                changes.flushChanges("Flushing changes due to popup closed");
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        document.addEventListener('mouseout', e => {
 | 
				
			||||||
 | 
					            // @ts-ignore
 | 
				
			||||||
 | 
					            if (!e.toElement && !e.relatedTarget) {
 | 
				
			||||||
 | 
					                changes.flushChanges("Flushing changes due to focus lost");
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        window.onbeforeunload = function(e){ 
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					            if(changes.pending.data.length == 0){
 | 
				
			||||||
 | 
					                return;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            changes.flushChanges("onbeforeunload - probably closing or something similar");
 | 
				
			||||||
 | 
					            e.preventDefault();
 | 
				
			||||||
 | 
					            return "Saving your last changes..."
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -12,9 +12,17 @@ import FeatureSource from "../FeatureSource/FeatureSource";
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
export class Changes implements FeatureSource{
 | 
					export class Changes implements FeatureSource{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * The newly created points, as a FeatureSource
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
    public features = new UIEventSource<{feature: any, freshness: Date}[]>([]);
 | 
					    public features = new UIEventSource<{feature: any, freshness: Date}[]>([]);
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    private static _nextId = -1; // Newly assigned ID's are negative
 | 
					    private static _nextId = -1; // Newly assigned ID's are negative
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * All the pending changes
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public readonly pending: UIEventSource<{ elementId: string, key: string, value: string }[]> = 
 | 
				
			||||||
 | 
					        new UIEventSource<{elementId: string; key: string; value: string}[]>([]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Adds a change to the pending changes
 | 
					     * Adds a change to the pending changes
 | 
				
			||||||
| 
						 | 
					@ -39,6 +47,8 @@ export class Changes implements FeatureSource{
 | 
				
			||||||
        return {k: key, v: value};
 | 
					        return {k: key, v: value};
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
    addTag(elementId: string, tagsFilter: TagsFilter,
 | 
					    addTag(elementId: string, tagsFilter: TagsFilter,
 | 
				
			||||||
           tags?: UIEventSource<any>) {
 | 
					           tags?: UIEventSource<any>) {
 | 
				
			||||||
        const changes = this.tagToChange(tagsFilter);
 | 
					        const changes = this.tagToChange(tagsFilter);
 | 
				
			||||||
| 
						 | 
					@ -47,21 +57,30 @@ export class Changes implements FeatureSource{
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        const eventSource = tags ?? State.state?.allElements.getEventSourceById(elementId);
 | 
					        const eventSource = tags ?? State.state?.allElements.getEventSourceById(elementId);
 | 
				
			||||||
        const elementTags = eventSource.data;
 | 
					        const elementTags = eventSource.data;
 | 
				
			||||||
        const pending: { elementId: string, key: string, value: string }[] = [];
 | 
					 | 
				
			||||||
        for (const change of changes) {
 | 
					        for (const change of changes) {
 | 
				
			||||||
            if (elementTags[change.k] !== change.v) {
 | 
					            if (elementTags[change.k] !== change.v) {
 | 
				
			||||||
                elementTags[change.k] = change.v;
 | 
					                elementTags[change.k] = change.v;
 | 
				
			||||||
                pending.push({elementId: elementTags.id, key: change.k, value: change.v});
 | 
					                this.pending.data.push({elementId: elementTags.id, key: change.k, value: change.v});
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        if (pending.length === 0) {
 | 
					        this.pending.ping();
 | 
				
			||||||
            return;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        console.log("Sending ping", eventSource)
 | 
					 | 
				
			||||||
        eventSource.ping();
 | 
					        eventSource.ping();
 | 
				
			||||||
        this.uploadAll([], pending);
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Uploads all the pending changes in one go.
 | 
				
			||||||
 | 
					     * Triggered by the 'PendingChangeUploader'-actor in Actors
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public flushChanges(flushreason: string = undefined){
 | 
				
			||||||
 | 
					        if(this.pending.data.length === 0){
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if(flushreason !== undefined){
 | 
				
			||||||
 | 
					            console.log(flushreason)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        this.uploadAll([], this.pending.data);
 | 
				
			||||||
 | 
					        this.pending.setData([]);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Create a new node element at the given lat/long.
 | 
					     * Create a new node element at the given lat/long.
 | 
				
			||||||
     * An internal OsmObject is created to upload later on, a geojson represention is returned.
 | 
					     * An internal OsmObject is created to upload later on, a geojson represention is returned.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -17,6 +17,11 @@ export default class Constants {
 | 
				
			||||||
        addNewPointWithUnreadMessagesUnlock: 500,
 | 
					        addNewPointWithUnreadMessagesUnlock: 500,
 | 
				
			||||||
        minZoomLevelToAddNewPoints: (Constants.isRetina() ? 18 : 19)
 | 
					        minZoomLevelToAddNewPoints: (Constants.isRetina() ? 18 : 19)
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Used by 'PendingChangesUploader', which waits this amount of seconds to upload changes.
 | 
				
			||||||
 | 
					     * (Note that pendingChanges might upload sooner if the popup is closed or similar)
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    static updateTimeoutSec: number = 30;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private static isRetina(): boolean {
 | 
					    private static isRetina(): boolean {
 | 
				
			||||||
        if (Utils.runningFromConsole) {
 | 
					        if (Utils.runningFromConsole) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										3
									
								
								State.ts
									
										
									
									
									
								
							
							
						
						
									
										3
									
								
								State.ts
									
										
									
									
									
								
							| 
						 | 
					@ -18,6 +18,7 @@ import Constants from "./Models/Constants";
 | 
				
			||||||
import UpdateFromOverpass from "./Logic/Actors/UpdateFromOverpass";
 | 
					import UpdateFromOverpass from "./Logic/Actors/UpdateFromOverpass";
 | 
				
			||||||
import LayerConfig from "./Customizations/JSON/LayerConfig";
 | 
					import LayerConfig from "./Customizations/JSON/LayerConfig";
 | 
				
			||||||
import TitleHandler from "./Logic/Actors/TitleHandler";
 | 
					import TitleHandler from "./Logic/Actors/TitleHandler";
 | 
				
			||||||
 | 
					import PendingChangesUploader from "./Logic/Actors/PendingChangesUploader";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Contains the global state: a bunch of UI-event sources
 | 
					 * Contains the global state: a bunch of UI-event sources
 | 
				
			||||||
| 
						 | 
					@ -208,6 +209,8 @@ export default class State {
 | 
				
			||||||
        this.allElements = new ElementStorage();
 | 
					        this.allElements = new ElementStorage();
 | 
				
			||||||
        this.changes = new Changes();
 | 
					        this.changes = new Changes();
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
 | 
					        new PendingChangesUploader(this.changes, this.selectedElement);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        this.mangroveIdentity = new MangroveIdentity(
 | 
					        this.mangroveIdentity = new MangroveIdentity(
 | 
				
			||||||
            this.osmConnection.GetLongPreference("identity", "mangrove")
 | 
					            this.osmConnection.GetLongPreference("identity", "mangrove")
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue