Fix: cleanup various typing mistakes, remove unused variables, add error handling in opening hours related special visualisations

This commit is contained in:
Pieter Vander Vennet 2025-07-06 02:29:48 +02:00
parent 35cd979b5e
commit 091b7fbba5
16 changed files with 103 additions and 58 deletions

View file

@ -34,9 +34,13 @@
}, },
"minzoom": 12, "minzoom": 12,
"title": { "title": {
"render": { "render": "{name}",
"*": "{name}" "mappings": [{
} "if": "name=",
"then": {
"en": "Information office"
}
}]
}, },
"pointRendering": [ "pointRendering": [
{ {

View file

@ -204,7 +204,7 @@ export class WikimediaImageProvider extends ImageProvider {
return undefined return undefined
} }
visitUrl(img: ProvidedImage): string | undefined { visitUrl(img: {id: string}): string | undefined {
return "https://commons.wikimedia.org/wiki/"+img.id return "https://commons.wikimedia.org/wiki/"+img.id
} }
} }

View file

@ -12,8 +12,6 @@ import { VariableUiElement } from "../../UI/Base/VariableUIElement"
import { TagRenderingConfigJson } from "./Json/TagRenderingConfigJson" import { TagRenderingConfigJson } from "./Json/TagRenderingConfigJson"
import SvelteUIElement from "../../UI/Base/SvelteUIElement" import SvelteUIElement from "../../UI/Base/SvelteUIElement"
import DynamicMarker from "../../UI/Map/DynamicMarker.svelte" import DynamicMarker from "../../UI/Map/DynamicMarker.svelte"
import { UIElement } from "../../UI/UIElement"
import Img from "../../UI/Base/Img"
export class IconConfig extends WithContextLoader { export class IconConfig extends WithContextLoader {
public static readonly defaultIcon = new IconConfig({ icon: "pin", color: "#ff9939" }) public static readonly defaultIcon = new IconConfig({ icon: "pin", color: "#ff9939" })
@ -98,6 +96,9 @@ export default class PointRenderingConfig extends WithContextLoader {
this.labelCss = this.tr("labelCss", undefined) this.labelCss = this.tr("labelCss", undefined)
this.labelCssClasses = this.tr("labelCssClasses", undefined) this.labelCssClasses = this.tr("labelCssClasses", undefined)
this.iconBadges = (json.iconBadges ?? []).map((overlay, i) => { this.iconBadges = (json.iconBadges ?? []).map((overlay, i) => {
if(typeof overlay === "string"){
throw "Found an invalid,unexpanded overlay"
}
return { return {
if: TagUtils.Tag(overlay.if), if: TagUtils.Tag(overlay.if),
then: new TagRenderingConfig(overlay.then, `iconBadges.${i}`), then: new TagRenderingConfig(overlay.then, `iconBadges.${i}`),

View file

@ -38,7 +38,6 @@ export default class SvelteUIElement<
this._props = props ?? <Props>{} this._props = props ?? <Props>{}
this._events = events this._events = events
this._slots = slots this._slots = slots
console.trace("Constructing a special stack element")
} }
public setSpan() { public setSpan() {

View file

@ -9,19 +9,27 @@
let isSvelte = false let isSvelte = false
let uiElement: BaseUIElement | SvelteUIElement | undefined let uiElement: BaseUIElement | SvelteUIElement | undefined
let svelteElem: SvelteUIElement let svelteElem: SvelteUIElement
let err = false
onMount(() => { onMount(() => {
uiElement = typeof construct === "function" ? construct() : construct try {
if (uiElement?.["isSvelte"]) { uiElement = typeof construct === "function" ? construct() : construct
isSvelte = true
svelteElem = <SvelteUIElement>uiElement
return
}
html = uiElement?.ConstructElement() if (uiElement?.["isSvelte"]) {
isSvelte = true
svelteElem = <SvelteUIElement>uiElement
return
}
if (html !== undefined) { html = uiElement?.ConstructElement()
elem?.replaceWith(html)
if (html !== undefined) {
elem?.replaceWith(html)
}
} catch (e) {
console.error("Could not construct a ToSvelte:", e)
err = true
} }
}) })
@ -30,17 +38,20 @@
uiElement?.Destroy() uiElement?.Destroy()
}) })
</script> </script>
{#if err}
{#if svelteElem?._svelteComponent} <div class="alert">Something went wrong</div>
{#if svelteElem.getClass() || svelteElem.getStyle()} {:else if isSvelte}
<svelte:component {#if svelteElem?._svelteComponent}
this={svelteElem?._svelteComponent} {#if svelteElem.getClass() || svelteElem.getStyle()}
{...svelteElem._props} <svelte:component
class={svelteElem.getClass()} this={svelteElem?._svelteComponent}
style={svelteElem.getStyle()} {...svelteElem._props}
/> class={svelteElem.getClass()}
{:else} style={svelteElem.getStyle()}
<svelte:component this={svelteElem?._svelteComponent} {...svelteElem._props} /> />
{:else}
<svelte:component this={svelteElem?._svelteComponent} {...svelteElem._props} />
{/if}
{/if} {/if}
{:else} {:else}
<span bind:this={elem} /> <span bind:this={elem} />

View file

@ -16,19 +16,34 @@
export let keyToUse: string = "opening_hours" export let keyToUse: string = "opening_hours"
export let prefix: string = undefined export let prefix: string = undefined
export let postfix: string = undefined export let postfix: string = undefined
let oh: Store<opening_hours | "error" | undefined> = OH.CreateOhObjectStore( let oh: Store<opening_hours | undefined> = OH.CreateOhObjectStore(
tags, tags,
keyToUse, keyToUse,
prefix, prefix,
postfix postfix
) ).map(oh => (typeof oh === "string") ? undefined : oh)
let currentState = oh.mapD((oh) => (typeof oh === "string" ? undefined : oh.getState())) let currentState = oh.mapD((oh) => {
try {
return oh.getState()
} catch (e) {
console.error("Could not getState for current OpeningHOurs:", e)
return undefined
}
})
let tomorrow = new Date() let tomorrow = new Date()
tomorrow.setTime(tomorrow.getTime() + 24 * 60 * 60 * 1000) tomorrow.setTime(tomorrow.getTime() + 24 * 60 * 60 * 1000)
let nextChange = oh let nextChange = oh
.mapD( .mapD(
(oh) => (typeof oh === "string" ? undefined : oh.getNextChange(new Date(), tomorrow)), (oh) => {
try {
return (oh.getNextChange(new Date(), tomorrow))
} catch (e) {
console.error("Could not getNextChange", e)
return undefined
}
},
[Stores.Chronic(5 * 60 * 1000)] [Stores.Chronic(5 * 60 * 1000)]
) )
.mapD((date) => Utils.TwoDigits(date.getHours()) + ":" + Utils.TwoDigits(date.getMinutes())) .mapD((date) => Utils.TwoDigits(date.getHours()) + ":" + Utils.TwoDigits(date.getMinutes()))

View file

@ -3,27 +3,26 @@
* Full opening hours visualisations table, dispatches to special cases * Full opening hours visualisations table, dispatches to special cases
*/ */
import type { OpeningRange } from "../OpeningHours"
import { OH, ToTextualDescription } from "../OpeningHours" import { OH, ToTextualDescription } from "../OpeningHours"
import opening_hours from "opening_hours" import opening_hours from "opening_hours"
import { ariaLabel } from "../../../Utils/ariaLabel" import { ariaLabel } from "../../../Utils/ariaLabel"
import RegularOpeningHoursTable from "./RegularOpeningHoursTable.svelte" import RegularOpeningHoursTable from "./RegularOpeningHoursTable.svelte"
import SpecialCase from "./SpecialCase.svelte" import SpecialCase from "./SpecialCase.svelte"
import { Translation } from "../../i18n/Translation" import { Translation } from "../../i18n/Translation"
import type { OpeningRange } from "../OpeningHours"
export let opening_hours_obj: opening_hours export let opening_hours_obj: opening_hours
let applicableWeek = OH.createRangesForApplicableWeek(opening_hours_obj)
let oh = opening_hours_obj let oh = opening_hours_obj
export let applicableWeek: { ranges: OpeningRange[][]; startingMonday: Date }
let ranges = applicableWeek.ranges
let lastMonday = applicableWeek.startingMonday
let textual: Translation = ToTextualDescription.createTextualDescriptionFor( let textual: Translation = ToTextualDescription.createTextualDescriptionFor(
oh, oh,
applicableWeek.ranges applicableWeek.ranges
) )
let applicableWeekRanges: { ranges: OpeningRange[][]; startingMonday: Date } =
OH.createRangesForApplicableWeek(oh)
let ranges = applicableWeekRanges.ranges
let lastMonday = applicableWeekRanges.startingMonday
</script> </script>
<div use:ariaLabel={textual} class="no-weblate"> <div use:ariaLabel={textual} class="no-weblate">

View file

@ -6,7 +6,6 @@
*/ */
export let availableArea: number export let availableArea: number
export let earliestOpen: number export let earliestOpen: number
export let latestclose: number
export let range: OpeningRange export let range: OpeningRange
export let isWeekstable: boolean export let isWeekstable: boolean

View file

@ -8,10 +8,24 @@
import Loading from "../../Base/Loading.svelte" import Loading from "../../Base/Loading.svelte"
import Tr from "../../Base/Tr.svelte" import Tr from "../../Base/Tr.svelte"
import OpeningHours from "./OpeningHours.svelte" import OpeningHours from "./OpeningHours.svelte"
import { OH } from "../OpeningHours"
import AccordionSingle from "../../Flowbite/AccordionSingle.svelte"
export let tags: UIEventSource<Record<string, string>> export let tags: UIEventSource<Record<string, string>>
export let opening_hours_obj: Store<opening_hours | "error"> export let opening_hours_obj: Store<opening_hours | "error">
export let key: string export let key: string
let applicableWeek = opening_hours_obj.map(oh => {
if (oh === "error") {
return "error"
}
try {
return OH.createRangesForApplicableWeek(oh)
} catch (e) {
return e.toString()
}
})
</script> </script>
{#if $tags._country === undefined} {#if $tags._country === undefined}
@ -20,8 +34,18 @@
</Loading> </Loading>
{:else if $opening_hours_obj === undefined} {:else if $opening_hours_obj === undefined}
<div class="alert">No opening hours defined with key {key}</div> <div class="alert">No opening hours defined with key {key}</div>
{:else if $opening_hours_obj === "error"} {:else if typeof $applicableWeek === "string"}
<Tr cls="alert" t={Translations.t.general.opening_hours.error_loading} /> <div class="alert" style="margin-top: 1rem">
<Tr t={Translations.t.general.opening_hours.error_loading} />
</div>
{#if $applicableWeek !== "error"}
<AccordionSingle noBorder>
<div slot="header" class="subtle text-sm">Technical details</div>
<div class="subtle">
{$applicableWeek}
</div>
</AccordionSingle>
{/if}
{:else} {:else}
<OpeningHours opening_hours_obj={$opening_hours_obj} /> <OpeningHours opening_hours_obj={$opening_hours_obj} applicableWeek={$applicableWeek} />
{/if} {/if}

View file

@ -115,7 +115,6 @@
<OpeningHoursRangeElement <OpeningHoursRangeElement
{availableArea} {availableArea}
{earliestOpen} {earliestOpen}
{latestclose}
{range} {range}
{isWeekstable} {isWeekstable}
/> />

View file

@ -108,7 +108,7 @@ class OpeningHoursTableVis extends SpecialVisualizationSvelte {
}, },
] ]
group = "data" group = "data"
needsUrls = [Constants.countryCoderEndpoint] needsUrls = [Constants.countryCoderInfo]
example = example =
"A normal opening hours table can be invoked with `{opening_hours_table()}`. A table for e.g. conditional access with opening hours can be `{opening_hours_table(access:conditional, no @ &LPARENS, &RPARENS)}`" "A normal opening hours table can be invoked with `{opening_hours_table()}`. A table for e.g. conditional access with opening hours can be `{opening_hours_table(access:conditional, no @ &LPARENS, &RPARENS)}`"

View file

@ -21,7 +21,6 @@ export class ShareLinkViz extends SpecialVisualizationSvelte {
}, },
] ]
needsUrls = [] needsUrls = []
svelteBased = true
public constr( public constr(
state: SpecialVisualizationState, state: SpecialVisualizationState,

View file

@ -16,8 +16,9 @@ import ComparisonTool from "../Comparison/ComparisonTool.svelte"
import { Utils } from "../../Utils" import { Utils } from "../../Utils"
import TagApplyViz from "./TagApplyViz" import TagApplyViz from "./TagApplyViz"
import { ServerSourceInfo } from "../../Models/SourceOverview" import { ServerSourceInfo } from "../../Models/SourceOverview"
import MaprouletteSetStatus from "../MapRoulette/MaprouletteSetStatus.svelte"
class MaprouletteSetStatus extends SpecialVisualizationSvelte { class MaprouletteSetStatusVis extends SpecialVisualizationSvelte {
funcName = "maproulette_set_status" funcName = "maproulette_set_status"
group = "data_import" group = "data_import"
docs = "Change the status of the given MapRoulette task" docs = "Change the status of the given MapRoulette task"
@ -305,7 +306,7 @@ export class DataImportSpecialVisualisations {
new WayImportButtonViz(), new WayImportButtonViz(),
new ConflateImportButtonViz(), new ConflateImportButtonViz(),
new PlantNetDetectionViz(), new PlantNetDetectionViz(),
new MaprouletteSetStatus(), new MaprouletteSetStatusVis(),
new LinkedDataFromWebsite(), new LinkedDataFromWebsite(),
new CompareData(), new CompareData(),
] ]

View file

@ -1,8 +1,4 @@
import { import { SpecialVisualization, SpecialVisualizationState, SpecialVisualizationSvelte } from "../SpecialVisualization"
SpecialVisualization,
SpecialVisualizationState,
SpecialVisualizationSvelte,
} from "../SpecialVisualization"
import Constants from "../../Models/Constants" import Constants from "../../Models/Constants"
import { UIEventSource } from "../../Logic/UIEventSource" import { UIEventSource } from "../../Logic/UIEventSource"
import { Feature } from "geojson" import { Feature } from "geojson"
@ -13,7 +9,6 @@ import { Utils } from "../../Utils"
import CloseNoteButton from "../Popup/Notes/CloseNoteButton.svelte" import CloseNoteButton from "../Popup/Notes/CloseNoteButton.svelte"
import Translations from "../i18n/Translations" import Translations from "../i18n/Translations"
import AddNoteComment from "../Popup/Notes/AddNoteComment.svelte" import AddNoteComment from "../Popup/Notes/AddNoteComment.svelte"
import { Imgur } from "../../Logic/ImageProviders/Imgur"
import UploadImage from "../Image/UploadImage.svelte" import UploadImage from "../Image/UploadImage.svelte"
import { VariableUiElement } from "../Base/VariableUIElement" import { VariableUiElement } from "../Base/VariableUIElement"
import Combine from "../Base/Combine" import Combine from "../Base/Combine"
@ -81,7 +76,7 @@ class CloseNoteViz extends SpecialVisualizationSvelte {
class AddNoteCommentViz extends SpecialVisualizationSvelte { class AddNoteCommentViz extends SpecialVisualizationSvelte {
funcName = "add_note_comment" funcName = "add_note_comment"
needsUrls = [Constants.osmAuthConfig.url] needsUrls = [Constants.osmAuthConfig]
docs = "A textfield to add a comment to a node (with the option to close the note)." docs = "A textfield to add a comment to a node (with the option to close the note)."
args = [ args = [
{ {
@ -104,7 +99,7 @@ class OpenNote extends SpecialVisualizationSvelte {
funcName = "open_note" funcName = "open_note"
args = [] args = []
group = "notes" group = "notes"
needsUrls = [Constants.osmAuthConfig.url] needsUrls = [Constants.osmAuthConfig]
docs = "Creates a new map note on the given location. This options is placed in the 'last_click'-popup automatically if the 'notes'-layer is enabled" docs = "Creates a new map note on the given location. This options is placed in the 'last_click'-popup automatically if the 'notes'-layer is enabled"
constr( constr(
@ -157,7 +152,7 @@ class VisualiseNoteComment extends SpecialVisualization {
defaultValue: "0", defaultValue: "0",
}, },
] ]
needsUrls = [Constants.osmAuthConfig.url] needsUrls = [Constants.osmAuthConfig]
constr(state, tags, args) { constr(state, tags, args) {
return new VariableUiElement( return new VariableUiElement(

View file

@ -33,7 +33,6 @@ class StealViz extends SpecialVisualization {
}, },
] ]
needsUrls = [] needsUrls = []
svelteBased = true
constr(state: SpecialVisualizationState, featureTags, args) { constr(state: SpecialVisualizationState, featureTags, args) {
const [featureIdKey, layerAndtagRenderingIds] = args const [featureIdKey, layerAndtagRenderingIds] = args

View file

@ -189,7 +189,7 @@ class LinkVis extends SpecialVisualizationSvelte {
ariaLabel: tagSource.map((tags) => Utils.SubstituteKeys(ariaLabel, tags)), ariaLabel: tagSource.map((tags) => Utils.SubstituteKeys(ariaLabel, tags)),
newTab: new ImmutableStore(newTab), newTab: new ImmutableStore(newTab),
icon: tagSource.map((tags) => Utils.SubstituteKeys(icon, tags)), icon: tagSource.map((tags) => Utils.SubstituteKeys(icon, tags)),
}).setSpan() })
} }
} }
export class WebAndCommunicationSpecialVisualisations { export class WebAndCommunicationSpecialVisualisations {