forked from MapComplete/MapComplete
		
	When a logged-in user opens a popup, the latest data will be downloaded and tags are updated to prevent duplicate work, fix #505
This commit is contained in:
		
							parent
							
								
									adf02af5fe
								
							
						
					
					
						commit
						d4e63d90e4
					
				
					 4 changed files with 106 additions and 0 deletions
				
			
		
							
								
								
									
										1
									
								
								.gitignore
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
										
									
									
										vendored
									
									
								
							|  | @ -17,3 +17,4 @@ missing_translations.txt | ||||||
| .DS_Store | .DS_Store | ||||||
| Svg.ts | Svg.ts | ||||||
| data/ | data/ | ||||||
|  | Folder.DotSettings.user | ||||||
|  |  | ||||||
							
								
								
									
										100
									
								
								Logic/Actors/SelectedElementTagsUpdater.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										100
									
								
								Logic/Actors/SelectedElementTagsUpdater.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,100 @@ | ||||||
|  | /** | ||||||
|  |  * This actor will download the latest version of the selected element from OSM and update the tags if necessary. | ||||||
|  |  */ | ||||||
|  | import {UIEventSource} from "../UIEventSource"; | ||||||
|  | import {ElementStorage} from "../ElementStorage"; | ||||||
|  | import {Changes} from "../Osm/Changes"; | ||||||
|  | import {OsmObject} from "../Osm/OsmObject"; | ||||||
|  | import {OsmConnection} from "../Osm/OsmConnection"; | ||||||
|  | 
 | ||||||
|  | export default class SelectedElementTagsUpdater { | ||||||
|  | 
 | ||||||
|  |     constructor(state: { | ||||||
|  |         selectedElement: UIEventSource<any>, | ||||||
|  |         allElements: ElementStorage, | ||||||
|  |         changes: Changes, | ||||||
|  |         osmConnection: OsmConnection | ||||||
|  |     }) { | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |         state.osmConnection.isLoggedIn.addCallbackAndRun(isLoggedIn => { | ||||||
|  |             if(isLoggedIn){ | ||||||
|  |                 SelectedElementTagsUpdater.installCallback(state) | ||||||
|  |                 return true; | ||||||
|  |             } | ||||||
|  |         }) | ||||||
|  | 
 | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     private static installCallback(state: { | ||||||
|  |         selectedElement: UIEventSource<any>, | ||||||
|  |         allElements: ElementStorage, | ||||||
|  |         changes: Changes, | ||||||
|  |         osmConnection: OsmConnection | ||||||
|  |     }) { | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |         state.selectedElement.addCallbackAndRunD(s => { | ||||||
|  |             const id = s.properties?.id | ||||||
|  |             OsmObject.DownloadObjectAsync(id).then(obj => { | ||||||
|  |                 SelectedElementTagsUpdater.applyUpdate(state, obj, id) | ||||||
|  |             }).catch(e => { | ||||||
|  |                 console.error("Could not update tags of ", id, "due to", e) | ||||||
|  |             }) | ||||||
|  |         }); | ||||||
|  | 
 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private static applyUpdate(state: { | ||||||
|  |                                    selectedElement: UIEventSource<any>, | ||||||
|  |                                    allElements: ElementStorage, | ||||||
|  |                                    changes: Changes, | ||||||
|  |                                    osmConnection: OsmConnection | ||||||
|  |                                }, obj: OsmObject, id: string | ||||||
|  |     ) { | ||||||
|  |         const pendingChanges = state.changes.pendingChanges.data | ||||||
|  |             .filter(change => change.type === obj.type && change.id === obj.id) | ||||||
|  |             .filter(change => change.tags !== undefined); | ||||||
|  |         const latestTags = obj.tags | ||||||
|  |         console.log("Applying updates of ", id, " got tags", latestTags, "and still have to apply changes: ", pendingChanges) | ||||||
|  | 
 | ||||||
|  |         for (const pendingChange of pendingChanges) { | ||||||
|  |             const tagChanges = pendingChange.tags; | ||||||
|  |             for (const tagChange of tagChanges) { | ||||||
|  |                 const key = tagChange.k | ||||||
|  |                 const v = tagChange.v | ||||||
|  |                 if (v === undefined || v === "") { | ||||||
|  |                     delete latestTags[key] | ||||||
|  |                 } else { | ||||||
|  |                     latestTags[key] = v | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         // With the changes applied, we merge them onto the upstream object
 | ||||||
|  |         let somethingChanged = false; | ||||||
|  |         const currentTagsSource = state.allElements.getEventSourceById(id); | ||||||
|  |         const currentTags = currentTagsSource.data | ||||||
|  |         for (const key in latestTags) { | ||||||
|  |             let osmValue = latestTags[key] | ||||||
|  |              | ||||||
|  |             if(typeof osmValue === "number"){ | ||||||
|  |                 osmValue = ""+osmValue | ||||||
|  |             } | ||||||
|  |              | ||||||
|  |             const localValue = currentTags[key] | ||||||
|  |             if (localValue !== osmValue) { | ||||||
|  |                 console.log("Local value:", localValue, "upstream", osmValue) | ||||||
|  |                 somethingChanged = true; | ||||||
|  |                 currentTags[key] = osmValue | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         if (somethingChanged) { | ||||||
|  |             console.log("Detected upstream changes to the object when opening it, updating...") | ||||||
|  |             currentTagsSource.ping() | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | @ -18,6 +18,8 @@ export interface ChangeDescription { | ||||||
|     /** |     /** | ||||||
|      * All changes to tags |      * All changes to tags | ||||||
|      * v = "" or v = undefined to erase this tag |      * v = "" or v = undefined to erase this tag | ||||||
|  |      *  | ||||||
|  |      * Note that this list will only contain the _changes_ to the tags, not the full set of tags | ||||||
|      */ |      */ | ||||||
|     tags?: { k: string, v: string }[], |     tags?: { k: string, v: string }[], | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
							
								
								
									
										3
									
								
								State.ts
									
										
									
									
									
								
							
							
						
						
									
										3
									
								
								State.ts
									
										
									
									
									
								
							|  | @ -18,6 +18,7 @@ import FilteredLayer from "./Models/FilteredLayer"; | ||||||
| import ChangeToElementsActor from "./Logic/Actors/ChangeToElementsActor"; | import ChangeToElementsActor from "./Logic/Actors/ChangeToElementsActor"; | ||||||
| import LayoutConfig from "./Models/ThemeConfig/LayoutConfig"; | import LayoutConfig from "./Models/ThemeConfig/LayoutConfig"; | ||||||
| import {BBox} from "./Logic/BBox"; | import {BBox} from "./Logic/BBox"; | ||||||
|  | import SelectedElementTagsUpdater from "./Logic/Actors/SelectedElementTagsUpdater"; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * Contains the global state: a bunch of UI-event sources |  * Contains the global state: a bunch of UI-event sources | ||||||
|  | @ -377,6 +378,8 @@ export default class State { | ||||||
| 
 | 
 | ||||||
|         new PendingChangesUploader(this.changes, this.selectedElement); |         new PendingChangesUploader(this.changes, this.selectedElement); | ||||||
|          |          | ||||||
|  |         new SelectedElementTagsUpdater(this) | ||||||
|  | 
 | ||||||
|         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