From e4ffac86e85410d5c9a865484a70fc2470995703 Mon Sep 17 00:00:00 2001 From: Pieter Vander Vennet Date: Sun, 12 Oct 2025 12:56:57 +0200 Subject: [PATCH 1/4] Themes(benches): add changeset tag if data is imported --- assets/themes/benches/benches.json | 2 +- src/UI/SpecialVisualisations/TagApplyViz.ts | 19 +++++++++++-------- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/assets/themes/benches/benches.json b/assets/themes/benches/benches.json index c8f33e81e..e38426099 100644 --- a/assets/themes/benches/benches.json +++ b/assets/themes/benches/benches.json @@ -164,7 +164,7 @@ "special": { "classes": "p-2 m-1 my-4 border-2 border-dashed border-black", "key": "_nearby_osm_poi:props", - "tagrendering": "{id} ({_distance}m, {openbenches:id}) {minimap(17,id;_original:id)} {tag_apply($_original:tags,Link this object.,link,id,_original:id)}", + "tagrendering": "{id} ({_distance}m, {openbenches:id}) {minimap(17,id;_original:id)} {tag_apply($_original:tags,Link this object.,link,id,_original:id,import:attribute)}", "type": "multi" } } diff --git a/src/UI/SpecialVisualisations/TagApplyViz.ts b/src/UI/SpecialVisualisations/TagApplyViz.ts index d07eba57a..b1a406e75 100644 --- a/src/UI/SpecialVisualisations/TagApplyViz.ts +++ b/src/UI/SpecialVisualisations/TagApplyViz.ts @@ -1,9 +1,5 @@ import { AutoAction } from "../Popup/AutoApplyButtonVis" -import { - SpecialVisualisationParams, - SpecialVisualization, - SpecialVisualizationState, -} from "../SpecialVisualization" +import { SpecialVisualisationParams, SpecialVisualization, SpecialVisualizationState } from "../SpecialVisualization" import { Utils } from "../../Utils" import { Store, UIEventSource } from "../../Logic/UIEventSource" import { Tag } from "../../Logic/Tags/Tag" @@ -47,6 +43,11 @@ export default class TagApplyViz extends SpecialVisualization implements AutoAct defaultValue: undefined, doc: "If specified, this maproulette-challenge will be closed when the tags are applied. This should be the `id` of the individual task, _not_ the task_id (which corresponds with the challenge).", }, + { + name: "changeset_type", + defaultValue: "answer", + doc: "If set, this attribute will be set on the changeset. A typical example is `answer` if it answers a question or `import:attribute` if attributes are copied" + } ] public readonly example = "`{tag_apply(survey_date=$_now:date, Surveyed today!)}`, `{tag_apply(addr:street=$addr:street, Apply the address, apply_icon.svg, _closest_osm_id)" @@ -133,7 +134,8 @@ export default class TagApplyViz extends SpecialVisualization implements AutoAct _: Feature, state: SpecialVisualizationState, tags: UIEventSource, - args: string[] + args: string[], + changesetMetaattribute: string = "change" ): Promise { const tagsToApply = TagApplyViz.generateTagsToApply(args[0], tags) const targetIdKey = args[3] @@ -145,7 +147,7 @@ export default class TagApplyViz extends SpecialVisualization implements AutoAct tags.data, // We pass in the tags of the selected element, not the tags of the target element! { theme: state.theme.id, - changeType: "answer", + changeType: changesetMetaattribute } ) await state.changes.applyAction(changeAction) @@ -184,12 +186,13 @@ export default class TagApplyViz extends SpecialVisualization implements AutoAct let image = args[2]?.trim() const targetIdKey = args[3] const maprouletteId = args[4] + const changeType = args[5] if (image === "" || image === "undefined") { image = undefined } const onApply = async () => { - await this.applyActionOn(feature, state, tags, args) + await this.applyActionOn(feature, state, tags, args, changeType) } return new SvelteUIElement(TagApplyButton, { From c152de78d0bc5579ffb7064517eb2dce56c447a7 Mon Sep 17 00:00:00 2001 From: Pieter Vander Vennet Date: Mon, 13 Oct 2025 09:51:19 +0200 Subject: [PATCH 2/4] UI: translate snippet --- langs/en.json | 1 + src/UI/Image/UploadImage.svelte | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/langs/en.json b/langs/en.json index ea1cd894c..714defa74 100644 --- a/langs/en.json +++ b/langs/en.json @@ -608,6 +608,7 @@ "doDelete": "Remove image", "isDeleted": "Deleted", "loadingFailed": "Loading this image failed", + "maintenance": "Due to maintenance, uploading images is currently not possible. Sorry about this!", "mapillaryTrackingProtection": "Strict tracking protection blocks loading images from Mapillary, as Mapillary is owned by Facebook/Meta. Disable strict tracking protection if you want to see this image.", "nearby": { "close": "Collapse panel with nearby images", diff --git a/src/UI/Image/UploadImage.svelte b/src/UI/Image/UploadImage.svelte index f29afad92..563bbdd90 100644 --- a/src/UI/Image/UploadImage.svelte +++ b/src/UI/Image/UploadImage.svelte @@ -72,7 +72,7 @@ {#if maintenanceBusy}
- Due to maintenance, uploading images is currently not possible. Sorry about this! +
{:else}
From 604ea6fb3ebffe6032a97241491a9ef77745d583 Mon Sep 17 00:00:00 2001 From: Pieter Vander Vennet Date: Mon, 13 Oct 2025 09:52:52 +0200 Subject: [PATCH 3/4] Docs: add file to .gitignore --- scripts/generateDocs.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/generateDocs.ts b/scripts/generateDocs.ts index 73b9a8b94..a961f58c8 100644 --- a/scripts/generateDocs.ts +++ b/scripts/generateDocs.ts @@ -221,6 +221,7 @@ export class GenerateDocs extends Script { this.generateSidebar("nl") this.generatedPaths.push(".gitignore") + this.generatedPaths.push("nl/index.html") writeFileSync( "./Docs/.gitignore", this.generatedPaths.map((p) => p.replace("./Docs/", "")).join("\n"), From abe81abb2277f4c842542e64d83db905dca96da6 Mon Sep 17 00:00:00 2001 From: Pieter Vander Vennet Date: Mon, 13 Oct 2025 10:13:12 +0200 Subject: [PATCH 4/4] Fix: fix #2549 --- langs/en.json | 1 + src/UI/Image/UploadImage.svelte | 24 ++++++++++++++++++- .../ImportButtons/PointImportFlowState.ts | 4 ++-- src/UI/Popup/Notes/AddNoteComment.svelte | 8 +++---- src/UI/Popup/Notes/CloseNoteButton.svelte | 3 +-- src/UI/Popup/Notes/NoteCommentElement.ts | 15 ++++++++++-- .../NoteVisualisations.ts | 14 ++++------- 7 files changed, 49 insertions(+), 20 deletions(-) diff --git a/langs/en.json b/langs/en.json index 714defa74..702924ae1 100644 --- a/langs/en.json +++ b/langs/en.json @@ -618,6 +618,7 @@ "seeNearby": "Browse nearby pictures", "title": "Nearby streetview imagery" }, + "noteReopen": "Adding a picture will reopen the note", "openOnWebsite": "Open this image on {name}", "panoramax": { "deletionRequested": "The report has been sent. A moderator will look to it shortly", diff --git a/src/UI/Image/UploadImage.svelte b/src/UI/Image/UploadImage.svelte index 563bbdd90..ad19047e1 100644 --- a/src/UI/Image/UploadImage.svelte +++ b/src/UI/Image/UploadImage.svelte @@ -16,6 +16,8 @@ import type { Feature } from "geojson" import Camera from "@babeard/svelte-heroicons/mini/Camera" import ArrowUpTray from "@babeard/svelte-heroicons/solid/ArrowUpTray" + import LayerConfig from "../../Models/ThemeConfig/LayerConfig" + import NoteCommentElement from "../Popup/Notes/NoteCommentElement" export let state: SpecialVisualizationState @@ -23,6 +25,7 @@ export let targetKey: string = undefined export let noBlur: boolean = false export let feature: Feature + export let layer: LayerConfig /** * Image to show in the button * NOT the image to upload! @@ -33,6 +36,8 @@ } export let labelText: string = undefined const t = Translations.t.image + const isNote = layer.id === "note" + const noteIsOpened = tags.mapD(tags => tags.closed_at === undefined) let errors = new UIEventSource([]) @@ -47,7 +52,15 @@ errs.push(canBeUploaded.error) continue } - await state?.imageUploadManager?.uploadImageAndApply( + + if (isNote) { + if (!noteIsOpened.data) { + await state.osmConnection.reopenNote(tags.data.id) + NoteCommentElement.mimickStatusChange(tags, true) + } + } + + state?.imageUploadManager?.uploadImageAndApply( file, tags, targetKey, @@ -109,6 +122,9 @@ {/if} + {#if isNote && !$noteIsOpened} + + {/if}
@@ -150,14 +166,20 @@ {/if} + {#if isNote && !$noteIsOpened} + + {/if} +
+ + {/if} diff --git a/src/UI/Popup/ImportButtons/PointImportFlowState.ts b/src/UI/Popup/ImportButtons/PointImportFlowState.ts index 5814c76b5..ffb54a7be 100644 --- a/src/UI/Popup/ImportButtons/PointImportFlowState.ts +++ b/src/UI/Popup/ImportButtons/PointImportFlowState.ts @@ -7,6 +7,7 @@ import Maproulette from "../../../Logic/Maproulette" import { GeoOperations } from "../../../Logic/GeoOperations" import { Tag } from "../../../Logic/Tags/Tag" import { SpecialVisualizationState } from "../../SpecialVisualization" +import NoteCommentElement from "../Notes/NoteCommentElement" export interface PointImportFlowArguments extends ImportFlowArguments { max_snap_distance?: string @@ -74,8 +75,7 @@ export class PointImportFlowState extends ImportFlow { if (note_id !== undefined) { await this.state.osmConnection.closeNote(note_id, "imported") - originalFeatureTags.data["closed_at"] = new Date().toISOString() - originalFeatureTags.ping() + NoteCommentElement.mimickStatusChange(originalFeatureTags, false) } const maproulette_id = originalFeatureTags.data[this.args.maproulette_id] diff --git a/src/UI/Popup/Notes/AddNoteComment.svelte b/src/UI/Popup/Notes/AddNoteComment.svelte index c8e152af1..09e0dfb9e 100644 --- a/src/UI/Popup/Notes/AddNoteComment.svelte +++ b/src/UI/Popup/Notes/AddNoteComment.svelte @@ -43,6 +43,7 @@ if (isClosed.data) { await state.osmConnection.reopenNote(id, txt.data) await state.osmConnection.closeNote(id) + NoteCommentElement.mimickStatusChange(tags, false) } else { await state.osmConnection.addCommentToNote(id, txt.data) } @@ -54,16 +55,15 @@ async function closeNote() { isProcessing.set(true) await state.osmConnection.closeNote(id, txt.data) - isProcessing.set(false) - tags.data["closed_at"] = new Date().toISOString() NoteCommentElement.addCommentTo(txt.data, tags, state) - tags.ping() + NoteCommentElement.mimickStatusChange(tags, false) // Will ping + isProcessing.set(false) } async function reopenNote() { isProcessing.set(true) await state.osmConnection.reopenNote(id, txt.data) - tags.data["closed_at"] = undefined + NoteCommentElement.mimickStatusChange(tags, true) NoteCommentElement.addCommentTo(txt.data, tags, state) tags.ping() txt.set(undefined) diff --git a/src/UI/Popup/Notes/CloseNoteButton.svelte b/src/UI/Popup/Notes/CloseNoteButton.svelte index ca972551d..558c53dac 100644 --- a/src/UI/Popup/Notes/CloseNoteButton.svelte +++ b/src/UI/Popup/Notes/CloseNoteButton.svelte @@ -26,8 +26,7 @@ const id = tags.data[idkey] await state.osmConnection.closeNote(id, message) NoteCommentElement.addCommentTo(message, tags, state) - tags.data["closed_at"] = new Date().toISOString() - tags.ping() + NoteCommentElement.mimickStatusChange(tags, false) } diff --git a/src/UI/Popup/Notes/NoteCommentElement.ts b/src/UI/Popup/Notes/NoteCommentElement.ts index d8a69e624..065cc069f 100644 --- a/src/UI/Popup/Notes/NoteCommentElement.ts +++ b/src/UI/Popup/Notes/NoteCommentElement.ts @@ -1,6 +1,17 @@ import { Store, UIEventSource } from "../../../Logic/UIEventSource" export default class NoteCommentElement { + + public static mimickStatusChange(tags: UIEventSource>, opened: boolean) { + if (opened) { + tags.data.status = "open" + tags.data.closed_at = undefined + } else { + tags.data.status = "closed" + tags.data.closed_at = new Date().toISOString() + } + tags.ping() + } /** * Adds the comment to the _visualisation_ of the given note; doesn't _actually_ upload * @param txt @@ -16,9 +27,9 @@ export default class NoteCommentElement { const username = state.osmConnection.userDetails.data.name const urlRegex = /(https?:\/\/[^\s]+)/g - const html = txt.replace(urlRegex, function (url) { + const html = txt?.replace(urlRegex, function(url) { return '' + url + "" - }) + }) ?? "" comments.push({ date: new Date().toISOString(), diff --git a/src/UI/SpecialVisualisations/NoteVisualisations.ts b/src/UI/SpecialVisualisations/NoteVisualisations.ts index 62aecc77f..76de6eae6 100644 --- a/src/UI/SpecialVisualisations/NoteVisualisations.ts +++ b/src/UI/SpecialVisualisations/NoteVisualisations.ts @@ -1,8 +1,4 @@ -import { - SpecialVisualisationParams, - SpecialVisualization, - SpecialVisualizationSvelte, -} from "../SpecialVisualization" +import { SpecialVisualisationParams, SpecialVisualization, SpecialVisualizationSvelte } from "../SpecialVisualization" import Constants from "../../Models/Constants" import { UIEventSource } from "../../Logic/UIEventSource" import { Feature } from "geojson" @@ -126,10 +122,10 @@ class AddImageToNote extends SpecialVisualizationSvelte { group = "notes" needsUrls = [] - constr({ state, tags, args, feature }: SpecialVisualisationParams) { - const id = tags.data[args[0] ?? "id"] - tags = state.featureProperties.getStore(id) - return new SvelteUIElement(UploadImage, { state, tags, feature }) + constr(params: SpecialVisualisationParams) { + const id = params.tags.data[params.args[0] ?? "id"] + const tags = params.state.featureProperties.getStore(id) + return new SvelteUIElement(UploadImage, { ...params, tags }) } }