Feature(offline): better support for making changes while offline

This commit is contained in:
Pieter Vander Vennet 2025-08-05 23:49:15 +02:00
parent f671cd342f
commit 7155cd7f61
8 changed files with 89 additions and 10 deletions

View file

@ -430,10 +430,10 @@
}
},
{
"id": "favourite_icon",
"condition": "_favourite=yes",
"description": "Only for rendering",
"icon": "circle:white;heart:red",
"condition": "_favourite=yes",
"id": "favourite_icon",
"metacondition": "__showTimeSensitiveIcons!=no"
},
{

View file

@ -18,7 +18,7 @@
"allFilteredAway": "No feature in view meets all filters",
"loadingData": "Loading data…",
"noData": "There are no relevant features in the current view",
"noDataOffline": "No data is loaded and you are offline",
"noDataOffline": "No data is loaded and you are offline",
"ready": "Done!",
"retrying": "Loading data failed. Trying again in {count} seconds…",
"zoomIn": "Zoom in to view or edit the data"
@ -639,6 +639,7 @@
"uploading": "{count} images are being uploaded…"
},
"noBlur": "Images will not be blurred. Do not photograph people",
"offline": "You are currently offline. Uploading images be attempted when your internet is back",
"one": {
"done": "Your image was successfully uploaded. Thank you!",
"failed": "Sorry, we could not upload your image",
@ -653,7 +654,7 @@
"confirmDeleteTitle": "Delete this image?",
"delete": "Delete this image",
"intro": "The following images are queued for upload",
"menu": "Image upload queue ({count})",
"menu": "Pending changes and image uploads ({count})",
"noFailedImages": "There are currently no images in the upload queue",
"retryAll": "Retry uploading all images"
},

View file

@ -19,6 +19,7 @@ import MarkdownUtils from "../../Utils/MarkdownUtils"
import FeaturePropertiesStore from "../FeatureSource/Actors/FeaturePropertiesStore"
import { Feature, Point } from "geojson"
import { Lists } from "../../Utils/Lists"
import { IsOnline } from "../Web/IsOnline"
/**
* Handles all changes made to OSM.
@ -287,6 +288,10 @@ export class Changes {
if (this.pendingChanges.data.length === 0) {
return
}
if(!IsOnline.isOnline.data){
// No use to upload, we aren't connected anyway
return
}
if (this.isUploading.data) {
console.log("Is already uploading... Abort")
return

View file

@ -64,6 +64,10 @@
import { GlobeEuropeAfrica } from "@babeard/svelte-heroicons/solid/GlobeEuropeAfrica"
import { onDestroy } from "svelte"
import Avatar from "../Base/Avatar.svelte"
import { SpecialVisualizationSvelte } from "../SpecialVisualization"
import ThemeViewState from "../../Models/ThemeViewState"
import { Changes } from "../../Logic/Osm/Changes"
import PendingChangesView from "./PendingChangesView.svelte"
export let state: {
favourites: FavouritesFeatureSource
@ -73,6 +77,7 @@
featureSwitches: Partial<FeatureSwitchState>
mapProperties?: MapProperties
userRelatedState?: UserRelatedState
changes?: Changes
}
let userdetails = state.osmConnection.userDetails
@ -81,6 +86,7 @@
let featureSwitches = state.featureSwitches
let showHome = featureSwitches?.featureSwitchBackToThemeOverview
let pg = state.guistate.pageStates
let pendingChanges = state?.changes?.pendingChanges
export let onlyLink: boolean
const t = Translations.t.general.menu
let shown = new UIEventSource(state.guistate.pageStates.menu.data || !onlyLink)
@ -164,12 +170,14 @@
/>
</Page>
{#if $nrOfFailedImages.length > 0 || $failedImagesOpen}
{#if $nrOfFailedImages.length > 0 || $failedImagesOpen || $pendingChanges?.length > 0 }
<Page {onlyLink} shown={pg.failedImages} bodyPadding="p-0 pb-4">
<svelte:fragment slot="header">
<PhotoIcon />
<Tr t={Translations.t.imageQueue.menu.Subs({ count: $nrOfFailedImages.length })} />
<Tr
t={Translations.t.imageQueue.menu.Subs({ count: ($nrOfFailedImages?.length ?? 0) + ($pendingChanges?.length ?? 0) })} />
</svelte:fragment>
<PendingChangesView {state} />
<QueuedImagesView {state} />
</Page>
{/if}

View file

@ -0,0 +1,58 @@
<script lang="ts">
import { Changes } from "../../Logic/Osm/Changes"
import type { SpecialVisualizationState } from "../SpecialVisualization"
export let state: { changes: Changes } & SpecialVisualizationState
let pending = state.changes.pendingChanges
let backend = state.osmConnection.Backend()
let debug = state.featureSwitches.featureSwitchIsDebugging
</script>
{#if $pending?.length > 0}
<div class="p-4">
<h3>Pending changes</h3>
There are currently {$pending.length} pending changes:
<table class="gap-x-2">
<tr>
<th>
Theme
</th>
<th>
Type
</th>
<th>
Object
</th>
</tr>
{#each $pending as change}
<tr>
<td>{change.meta.theme}</td>
<td>{change.meta.changeType}</td>
<td>
<a href={`${backend}/${change.type}/${change.id}`} target="_blank">
{change.type}/{change.id}
</a>
</td>
</tr>
{/each}
</table>
{#if $debug}
{#each $pending as change}
{JSON.stringify(change)}
{/each}
{/if}
</div>
{/if}
<style>
td {
padding-left: 2rem;
padding-right: 2rem;
}
</style>

View file

@ -8,9 +8,11 @@
import type { ImageUploadArguments } from "../../Logic/ImageProviders/ImageUploadQueue"
import { Store } from "../../Logic/UIEventSource"
import UploadingImageCounter from "./UploadingImageCounter.svelte"
import { IsOnline } from "../../Logic/Web/IsOnline"
export let state: WithImageState
let queued: Store<ImageUploadArguments[]> = state.imageUploadManager.queuedArgs
let isUploading = state.imageUploadManager.isUploading
let online = IsOnline.isOnline
const t = Translations.t
const q = t.imageQueue
</script>
@ -27,7 +29,7 @@
{#if $isUploading}
<Loading />
{:else}
{:else if $online}
<button class="primary" on:click={() => state.imageUploadManager.uploadQueue()}>
<ArrowPathIcon class="m-1 h-8 w-8" />
<Tr t={q.retryAll} />

View file

@ -66,7 +66,7 @@
let maintenanceBusy = false
</script>
<LoginToggle {state}>
<LoginToggle {state} offline>
<LoginButton clss="small w-full" osmConnection={state.osmConnection} slot="not-logged-in">
<Tr t={Translations.t.image.pleaseLogin} />
</LoginButton>

View file

@ -12,6 +12,7 @@
import Tr from "../Base/Tr.svelte"
import Loading from "../Base/Loading.svelte"
import UploadFailedMessage from "./UploadFailedMessage.svelte"
import { IsOnline } from "../../Logic/Web/IsOnline"
export let state: SpecialVisualizationState
export let tags: Store<OsmTags> = undefined
@ -59,6 +60,7 @@
failed.addCallbackAndRun((failed) => {
dismissed = Math.min(failed, dismissed)
})
let online = IsOnline.isOnline
let progress = state.imageUploadManager.progressCurrentImage
</script>
@ -91,8 +93,11 @@
</Loading>
</div>
{/if}
{#if $failed > dismissed}
{#if !$online}
<div class="alert">
<Tr t={t.upload.offline} />
</div>
{:else if $failed > dismissed}
<UploadFailedMessage failed={$failed} on:click={() => (dismissed = $failed)} {state} />
{/if}