forked from MapComplete/MapComplete
Merge branch 'develop' into feature/360-view
This commit is contained in:
commit
fa9e61c2b5
230 changed files with 45510 additions and 33214 deletions
|
|
@ -6,18 +6,26 @@
|
|||
|
||||
export let osmConnection: OsmConnection
|
||||
export let clss: string | undefined = undefined
|
||||
|
||||
/**
|
||||
* Show the button, even though we are logged in
|
||||
*/
|
||||
export let forceShow: boolean = false
|
||||
export let msg: String = undefined
|
||||
if (osmConnection === undefined) {
|
||||
console.error("No osmConnection passed into loginButton")
|
||||
}
|
||||
let isLoggedIn = osmConnection.isLoggedIn
|
||||
</script>
|
||||
|
||||
{#if !$isLoggedIn}
|
||||
{#if !$isLoggedIn || forceShow}
|
||||
<button class={clss} on:click={() => osmConnection.AttemptLogin()} style="margin-left: 0">
|
||||
<ArrowLeftOnRectangle class="m-1 w-12" />
|
||||
<slot>
|
||||
<Tr t={Translations.t.general.loginWithOpenStreetMap} />
|
||||
{#if msg}
|
||||
{msg}
|
||||
{:else}
|
||||
<Tr t={Translations.t.general.loginWithOpenStreetMap} />
|
||||
{/if}
|
||||
</slot>
|
||||
</button>
|
||||
{/if}
|
||||
|
|
|
|||
|
|
@ -24,11 +24,13 @@
|
|||
let dialogClass =
|
||||
"fixed top-0 start-0 end-0 h-modal inset-0 w-full p-4 flex border-none " + zIndex
|
||||
|
||||
export let backdropClass = "fixed inset-0 z-40 bg-gray-900 bg-opacity-50 dark:bg-opacity-80 frozen-glass"
|
||||
export let backdropClass =
|
||||
"fixed inset-0 z-40 bg-gray-900 bg-opacity-50 dark:bg-opacity-80 frozen-glass"
|
||||
if (fullscreen) {
|
||||
dialogClass += " h-full-child"
|
||||
}
|
||||
let bodyClass = bodyPadding + " h-full space-y-4 flex-1 overflow-y-auto overscroll-contain background-normal"
|
||||
let bodyClass =
|
||||
bodyPadding + " h-full space-y-4 flex-1 overflow-y-auto overscroll-contain background-normal"
|
||||
|
||||
let headerClass = "flex justify-between items-center p-2 px-4 md:px-5 rounded-t-lg"
|
||||
if (!$$slots.header) {
|
||||
|
|
@ -43,7 +45,7 @@
|
|||
<Modal
|
||||
open={_shown}
|
||||
on:close={() => shown.set(false)}
|
||||
outsideclose
|
||||
outsideclose={dismissable}
|
||||
size="xl"
|
||||
{dismissable}
|
||||
{defaultClass}
|
||||
|
|
|
|||
|
|
@ -88,8 +88,7 @@
|
|||
image={providedImage}
|
||||
imgClass="max-h-64 w-auto sm:h-32 md:h-64"
|
||||
attributionFormat="minimal"
|
||||
>
|
||||
</AttributedImage>
|
||||
/>
|
||||
<LoginToggle {state} silentFail={true}>
|
||||
{#if linkable}
|
||||
<label>
|
||||
|
|
|
|||
|
|
@ -24,16 +24,20 @@
|
|||
|
||||
let enableLogin = state.featureSwitches.featureSwitchEnableLogin
|
||||
export let shown = new UIEventSource(false)
|
||||
onDestroy(MenuState.nearbyImagesFeature.addCallback(something => {
|
||||
if (something !== feature) {
|
||||
shown.set(false)
|
||||
}
|
||||
}))
|
||||
onDestroy(shown.addCallbackAndRun(isShown => {
|
||||
if (isShown) {
|
||||
MenuState.nearbyImagesFeature.set(feature)
|
||||
}
|
||||
}))
|
||||
onDestroy(
|
||||
MenuState.nearbyImagesFeature.addCallback((something) => {
|
||||
if (something !== feature) {
|
||||
shown.set(false)
|
||||
}
|
||||
})
|
||||
)
|
||||
onDestroy(
|
||||
shown.addCallbackAndRun((isShown) => {
|
||||
if (isShown) {
|
||||
MenuState.nearbyImagesFeature.set(feature)
|
||||
}
|
||||
})
|
||||
)
|
||||
</script>
|
||||
|
||||
{#if enableLogin.data}
|
||||
|
|
|
|||
|
|
@ -56,13 +56,13 @@
|
|||
let searchIsRunning = new UIEventSource(false)
|
||||
let maplibremap: MapLibreAdaptor = new MapLibreAdaptor(map, {
|
||||
zoom,
|
||||
location: new UIEventSource<{ lon: number; lat: number }>({ lat: lat.data, lon: lon.data })
|
||||
location: new UIEventSource<{ lon: number; lat: number }>({ lat: lat.data, lon: lon.data }),
|
||||
})
|
||||
maplibremap.location.stabilized(500).addCallbackAndRunD((l) => {
|
||||
lat.set(l.lat)
|
||||
lon.set(l.lon)
|
||||
})
|
||||
let searchSuggestions = searchvalue.bindD(search => {
|
||||
let searchSuggestions = searchvalue.bindD((search) => {
|
||||
searchIsRunning.set(true)
|
||||
try {
|
||||
return UIEventSource.FromPromise(geocoder.search(search))
|
||||
|
|
@ -79,8 +79,8 @@
|
|||
showSearchDrawer,
|
||||
applyGeocodeResult(geocodeResult: GeocodeResult) {
|
||||
maplibremap.location.set({ lon: geocodeResult.lon, lat: geocodeResult.lat })
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
let allLayers = HistoryUtils.personalTheme.layers
|
||||
let layersNoFixme = allLayers.filter((l) => l.id !== "fixme")
|
||||
|
|
@ -94,7 +94,7 @@
|
|||
Utils.waitFor(200).then(() => {
|
||||
selectedElement.set(f)
|
||||
})
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
let osmConnection = new OsmConnection()
|
||||
|
|
@ -126,7 +126,7 @@
|
|||
inspectedData.push({
|
||||
label: undefined,
|
||||
visitedTime: new Date().toISOString(),
|
||||
name: user
|
||||
name: user,
|
||||
})
|
||||
}
|
||||
inspectedContributors.ping()
|
||||
|
|
@ -136,7 +136,7 @@
|
|||
featuresStore.set([])
|
||||
const overpass = new Overpass(
|
||||
undefined,
|
||||
user.split(";").map((user) => "nw(user_touched:\"" + user + "\");"),
|
||||
user.split(";").map((user) => 'nw(user_touched:"' + user + '");'),
|
||||
Constants.defaultOverpassUrls[0]
|
||||
)
|
||||
if (!maplibremap.bounds.data) {
|
||||
|
|
@ -172,7 +172,12 @@
|
|||
<h1 class="m-0 mx-2 flex-shrink-0">
|
||||
<Tr t={t.title} />
|
||||
</h1>
|
||||
<ValidatedInput placeholder={t.previouslySpied.username} type="string" value={username} on:submit={() => load()} />
|
||||
<ValidatedInput
|
||||
placeholder={t.previouslySpied.username}
|
||||
type="string"
|
||||
value={username}
|
||||
on:submit={() => load()}
|
||||
/>
|
||||
{#if loadingData}
|
||||
<Loading />
|
||||
{:else}
|
||||
|
|
@ -242,12 +247,14 @@
|
|||
</Drawer>
|
||||
{/if}
|
||||
|
||||
|
||||
<div class="relative m-1 flex-grow overflow-hidden rounded-xl">
|
||||
<MaplibreMap {map} mapProperties={maplibremap} autorecovery={true} />
|
||||
<div class="absolute right-0 top-0 w-1/4 p-4">
|
||||
<Searchbar isFocused={searchIsFocussed} value={searchvalue}
|
||||
on:focus={() => state.searchState.showSearchDrawer.set(true)} />
|
||||
<Searchbar
|
||||
isFocused={searchIsFocussed}
|
||||
value={searchvalue}
|
||||
on:focus={() => state.searchState.showSearchDrawer.set(true)}
|
||||
/>
|
||||
{#if $searchSuggestions?.length > 0 || $searchIsFocussed}
|
||||
<GeocodeResults {state} />
|
||||
{/if}
|
||||
|
|
|
|||
|
|
@ -24,13 +24,13 @@ export class MapLibreAdaptor implements MapProperties, ExportableMap {
|
|||
"dragRotate",
|
||||
"dragPan",
|
||||
"keyboard",
|
||||
"touchZoomRotate"
|
||||
"touchZoomRotate",
|
||||
]
|
||||
private static maplibre_zoom_handlers = [
|
||||
"scrollZoom",
|
||||
"boxZoom",
|
||||
"doubleClickZoom",
|
||||
"touchZoomRotate"
|
||||
"touchZoomRotate",
|
||||
]
|
||||
readonly location: UIEventSource<{ lon: number; lat: number }>
|
||||
private readonly isFlying = new UIEventSource(false)
|
||||
|
|
@ -44,14 +44,14 @@ export class MapLibreAdaptor implements MapProperties, ExportableMap {
|
|||
readonly lastClickLocation: Store<
|
||||
| undefined
|
||||
| {
|
||||
lon: number
|
||||
lat: number
|
||||
mode: "left" | "right" | "middle"
|
||||
/**
|
||||
* The nearest feature from a MapComplete layer
|
||||
*/
|
||||
nearestFeature?: Feature
|
||||
}
|
||||
lon: number
|
||||
lat: number
|
||||
mode: "left" | "right" | "middle"
|
||||
/**
|
||||
* The nearest feature from a MapComplete layer
|
||||
*/
|
||||
nearestFeature?: Feature
|
||||
}
|
||||
>
|
||||
readonly minzoom: UIEventSource<number>
|
||||
readonly maxzoom: UIEventSource<number>
|
||||
|
|
@ -141,7 +141,7 @@ export class MapLibreAdaptor implements MapProperties, ExportableMap {
|
|||
const features = map
|
||||
.queryRenderedFeatures([
|
||||
[point.x - buffer, point.y - buffer],
|
||||
[point.x + buffer, point.y + buffer]
|
||||
[point.x + buffer, point.y + buffer],
|
||||
])
|
||||
.filter((f) => f.source.startsWith("mapcomplete_"))
|
||||
if (features.length === 1) {
|
||||
|
|
@ -281,9 +281,9 @@ export class MapLibreAdaptor implements MapProperties, ExportableMap {
|
|||
return {
|
||||
map: mlmap,
|
||||
ui: new SvelteUIElement(MaplibreMap, {
|
||||
map: mlmap
|
||||
map: mlmap,
|
||||
}),
|
||||
mapproperties: new MapLibreAdaptor(mlmap)
|
||||
mapproperties: new MapLibreAdaptor(mlmap),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -347,7 +347,7 @@ export class MapLibreAdaptor implements MapProperties, ExportableMap {
|
|||
) {
|
||||
const event = {
|
||||
date: new Date(),
|
||||
key: key
|
||||
key: key,
|
||||
}
|
||||
|
||||
for (let i = 0; i < this._onKeyNavigation.length; i++) {
|
||||
|
|
@ -536,7 +536,7 @@ export class MapLibreAdaptor implements MapProperties, ExportableMap {
|
|||
const bounds = map.getBounds()
|
||||
const bbox = new BBox([
|
||||
[bounds.getEast(), bounds.getNorth()],
|
||||
[bounds.getWest(), bounds.getSouth()]
|
||||
[bounds.getWest(), bounds.getSouth()],
|
||||
])
|
||||
if (this.bounds.data === undefined || !isSetup) {
|
||||
this.bounds.setData(bbox)
|
||||
|
|
@ -732,14 +732,14 @@ export class MapLibreAdaptor implements MapProperties, ExportableMap {
|
|||
type: "raster-dem",
|
||||
url:
|
||||
"https://api.maptiler.com/tiles/terrain-rgb/tiles.json?key=" +
|
||||
Constants.maptilerApiKey
|
||||
Constants.maptilerApiKey,
|
||||
})
|
||||
try {
|
||||
while (!map?.isStyleLoaded()) {
|
||||
await Utils.waitFor(250)
|
||||
}
|
||||
map.setTerrain({
|
||||
source: id
|
||||
source: id,
|
||||
})
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
|
|
@ -764,7 +764,7 @@ export class MapLibreAdaptor implements MapProperties, ExportableMap {
|
|||
if (this.scaleControl === undefined) {
|
||||
this.scaleControl = new ScaleControl({
|
||||
maxWidth: 100,
|
||||
unit: "metric"
|
||||
unit: "metric",
|
||||
})
|
||||
}
|
||||
if (!map.hasControl(this.scaleControl)) {
|
||||
|
|
@ -777,7 +777,7 @@ export class MapLibreAdaptor implements MapProperties, ExportableMap {
|
|||
window.requestAnimationFrame(() => {
|
||||
this._maplibreMap.data?.flyTo({
|
||||
zoom,
|
||||
center: [lon, lat]
|
||||
center: [lon, lat],
|
||||
})
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -593,7 +593,10 @@ export default class ShowDataLayer {
|
|||
try {
|
||||
map.resize()
|
||||
} catch (e) {
|
||||
console.error("Could not resize the map in preparation of zoomToCurrentFeatures; the error is:", e)
|
||||
console.error(
|
||||
"Could not resize the map in preparation of zoomToCurrentFeatures; the error is:",
|
||||
e
|
||||
)
|
||||
}
|
||||
map.fitBounds(bbox.toLngLat(), {
|
||||
padding: { top: 10, bottom: 10, left: 10, right: 10 },
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@
|
|||
import { UIEventSource } from "../../../Logic/UIEventSource"
|
||||
import LayerConfig from "../../../Models/ThemeConfig/LayerConfig"
|
||||
import { TagUtils } from "../../../Logic/Tags/TagUtils"
|
||||
import type { UploadableTag } from "../../../Logic/Tags/TagUtils"
|
||||
import OsmChangeAction from "../../../Logic/Osm/Actions/OsmChangeAction"
|
||||
import DeleteAction from "../../../Logic/Osm/Actions/DeleteAction"
|
||||
import ChangeTagAction from "../../../Logic/Osm/Actions/ChangeTagAction"
|
||||
|
|
@ -22,6 +21,7 @@
|
|||
import Trash from "@babeard/svelte-heroicons/mini/Trash"
|
||||
import Invalid from "../../../assets/svg/Invalid.svelte"
|
||||
import { And } from "../../../Logic/Tags/And"
|
||||
import type { UploadableTag } from "../../../Logic/Tags/TagTypes"
|
||||
|
||||
export let state: SpecialVisualizationState
|
||||
export let deleteConfig: DeleteConfig
|
||||
|
|
@ -46,9 +46,9 @@
|
|||
|
||||
const t = Translations.t.delete
|
||||
|
||||
let selectedTags: UploadableTag
|
||||
let selectedTags: UploadableTag[]
|
||||
let changedProperties = undefined
|
||||
$: changedProperties = TagUtils.changeAsProperties(selectedTags?.asChange(tags?.data ?? {}) ?? [])
|
||||
$: changedProperties = TagUtils.changeAsProperties(And.construct(selectedTags)?.asChange(tags?.data ?? {}) ?? [])
|
||||
let isHardDelete = undefined
|
||||
$: isHardDelete = changedProperties[DeleteConfig.deleteReasonKey] !== undefined
|
||||
|
||||
|
|
@ -58,7 +58,7 @@
|
|||
}
|
||||
currentState = "applying"
|
||||
let actionToTake: OsmChangeAction
|
||||
const changedProperties = TagUtils.changeAsProperties(selectedTags.asChange(tags?.data ?? {}))
|
||||
const changedProperties = TagUtils.changeAsProperties(And.construct(selectedTags)?.asChange(tags?.data ?? {}))
|
||||
const deleteReason = changedProperties[DeleteConfig.deleteReasonKey]
|
||||
if (deleteReason) {
|
||||
let softDeletionTags: UploadableTag
|
||||
|
|
@ -81,7 +81,7 @@
|
|||
)
|
||||
} else {
|
||||
// no _delete_reason is given, which implies that this is _not_ a deletion but merely a retagging via a nonDeleteMapping
|
||||
actionToTake = new ChangeTagAction(featureId, selectedTags, tags.data, {
|
||||
actionToTake = new ChangeTagAction(featureId, new And(selectedTags), tags.data, {
|
||||
theme: state?.theme?.id ?? "unkown",
|
||||
changeType: "special-delete",
|
||||
})
|
||||
|
|
|
|||
|
|
@ -69,7 +69,9 @@
|
|||
/**
|
||||
* The tags to apply to mark this answer as "unknown"
|
||||
*/
|
||||
let onMarkUnknown: Store<UploadableTag[] | undefined> = tags.mapD((tags) => config.markUnknown(layer, tags))
|
||||
let onMarkUnknown: Store<UploadableTag[] | undefined> = tags.mapD((tags) =>
|
||||
config.markUnknown(layer, tags)
|
||||
)
|
||||
let unknownModal = new UIEventSource(false)
|
||||
|
||||
let searchTerm: UIEventSource<string> = new UIEventSource("")
|
||||
|
|
@ -120,7 +122,7 @@
|
|||
seenFreeforms.push(newProps[confg.freeform.key])
|
||||
}
|
||||
return matches
|
||||
})
|
||||
}),
|
||||
]
|
||||
|
||||
if (tgs !== undefined && confg.freeform) {
|
||||
|
|
@ -229,7 +231,7 @@
|
|||
freeform: $freeformInput,
|
||||
selectedMapping,
|
||||
checkedMappings,
|
||||
currentTags: tags.data
|
||||
currentTags: tags.data,
|
||||
},
|
||||
" --> ",
|
||||
selectedTags
|
||||
|
|
@ -290,7 +292,7 @@
|
|||
dispatch("saved", { config, applied: selectedTagsJoined })
|
||||
const change = new ChangeTagAction(tags.data.id, selectedTagsJoined, tags.data, {
|
||||
theme: tags.data["_orig_theme"] ?? state.theme?.id,
|
||||
changeType: "answer"
|
||||
changeType: "answer",
|
||||
})
|
||||
freeformInput.set(undefined)
|
||||
selectedMapping = undefined
|
||||
|
|
@ -334,7 +336,7 @@
|
|||
const tagsToSet: UploadableTag[] = onMarkUnknown.data
|
||||
const change = new ChangeTagAction(tags.data.id, new And(tagsToSet), tags.data, {
|
||||
theme: tags.data["_orig_theme"] ?? state.theme.id,
|
||||
changeType: "answer"
|
||||
changeType: "answer",
|
||||
})
|
||||
freeformInput.set(undefined)
|
||||
selectedMapping = undefined
|
||||
|
|
@ -581,7 +583,7 @@
|
|||
>
|
||||
<div class="subtle">
|
||||
<Tr t={Translations.t.unknown.removedKeys} />
|
||||
<TagHint tags={$onMarkUnknown}></TagHint>
|
||||
<TagHint tags={$onMarkUnknown} />
|
||||
</div>
|
||||
</If>
|
||||
<div class="flex w-full justify-end" slot="footer">
|
||||
|
|
@ -613,13 +615,8 @@
|
|||
<!-- TagRenderingQuestion-buttons -->
|
||||
<slot name="cancel" />
|
||||
<slot name="save-button" {selectedTags}>
|
||||
|
||||
<!-- Save-button / delete button -->
|
||||
{#if config.freeform?.key &&
|
||||
!checkedMappings?.some((m) => m) &&
|
||||
!$freeformInput && !$freeformInputUnvalidated
|
||||
&& $tags[config.freeform.key]
|
||||
&& $isKnown}
|
||||
{#if config.freeform?.key && !checkedMappings?.some((m) => m) && !$freeformInput && !$freeformInputUnvalidated && $tags[config.freeform.key] && $isKnown}
|
||||
<button
|
||||
class="primary flex"
|
||||
on:click|stopPropagation|preventDefault={() => onSave()}
|
||||
|
|
@ -652,7 +649,10 @@
|
|||
</div>
|
||||
{/if}
|
||||
{#if $featureSwitchIsTesting || $featureSwitchIsDebugging}
|
||||
<button class="small as-link" on:click={() => console.log("Configuration is ", config)}>
|
||||
<button
|
||||
class="small as-link"
|
||||
on:click={() => console.log("Configuration is ", config)}
|
||||
>
|
||||
{config.id}
|
||||
</button>
|
||||
{/if}
|
||||
|
|
|
|||
|
|
@ -16,9 +16,9 @@
|
|||
|
||||
export let entry: GeocodeResult
|
||||
export let state: {
|
||||
mapProperties: MapProperties,
|
||||
theme?: ThemeConfig,
|
||||
featureProperties?: FeaturePropertiesStore,
|
||||
mapProperties: MapProperties
|
||||
theme?: ThemeConfig
|
||||
featureProperties?: FeaturePropertiesStore
|
||||
searchState: Partial<SearchState>
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -16,7 +16,8 @@
|
|||
searchTerm: UIEventSource<string>
|
||||
suggestions: Store<GeocodeResult[]>
|
||||
suggestionsSearchRunning: Store<boolean>
|
||||
}, mapProperties: MapProperties
|
||||
}
|
||||
mapProperties: MapProperties
|
||||
}
|
||||
|
||||
let searchTerm = state.searchState.searchTerm
|
||||
|
|
|
|||
|
|
@ -57,7 +57,6 @@
|
|||
{/if}
|
||||
<GeocodeResults {state}>
|
||||
<svelte:fragment slot="if-no-results">
|
||||
|
||||
{#if $recentlySeen?.length > 0}
|
||||
<SidebarUnit>
|
||||
<div class="flex justify-between">
|
||||
|
|
@ -67,8 +66,8 @@
|
|||
<DotMenu>
|
||||
<button
|
||||
on:click={() => {
|
||||
state.userRelatedState.recentlyVisitedSearch.clear()
|
||||
}}
|
||||
state.userRelatedState.recentlyVisitedSearch.clear()
|
||||
}}
|
||||
>
|
||||
<TrashIcon />
|
||||
<Tr t={Translations.t.general.search.deleteSearchHistory} />
|
||||
|
|
@ -85,7 +84,6 @@
|
|||
</SidebarUnit>
|
||||
{/if}
|
||||
</svelte:fragment>
|
||||
|
||||
</GeocodeResults>
|
||||
|
||||
{#if $allowOtherThemes}
|
||||
|
|
|
|||
|
|
@ -111,12 +111,30 @@ export class SettingsVisualisations {
|
|||
},
|
||||
{
|
||||
funcName: "login_button",
|
||||
args: [],
|
||||
args: [
|
||||
{
|
||||
name: "force",
|
||||
doc: "Always show this button, even if logged in",
|
||||
},
|
||||
{
|
||||
name: "message",
|
||||
doc: "Message to display on the button",
|
||||
},
|
||||
],
|
||||
docs: "Show a login button",
|
||||
needsUrls: [],
|
||||
group: "settings",
|
||||
constr(state: SpecialVisualizationState): SvelteUIElement {
|
||||
return new SvelteUIElement(LoginButton, { osmConnection: state.osmConnection })
|
||||
constr(state: SpecialVisualizationState, _, args): SvelteUIElement {
|
||||
const force = args[0].toLowerCase()
|
||||
let msg = args[1]
|
||||
if (msg === "") {
|
||||
msg = undefined
|
||||
}
|
||||
return new SvelteUIElement(LoginButton, {
|
||||
osmConnection: state.osmConnection,
|
||||
msg,
|
||||
forceShow: force === "yes" || force === "true",
|
||||
})
|
||||
},
|
||||
},
|
||||
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
import { Utils } from "../../Utils"
|
||||
import Loading from "../Base/Loading.svelte"
|
||||
import Checkbox from "../Base/Checkbox.svelte"
|
||||
import PlantNet from "../../Logic/Web/PlantNet"
|
||||
|
||||
let services: MCService[] = []
|
||||
|
||||
|
|
@ -62,7 +63,7 @@
|
|||
return "offline"
|
||||
}
|
||||
}),
|
||||
message: osmApi,
|
||||
message: osmApi
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -90,7 +91,7 @@
|
|||
}
|
||||
const files: string[] = s["success"]["allFiles"]
|
||||
return "Contains " + (files.length ?? "no") + " files"
|
||||
}),
|
||||
})
|
||||
})
|
||||
}
|
||||
{
|
||||
|
|
@ -106,7 +107,7 @@
|
|||
return "degraded"
|
||||
}
|
||||
}),
|
||||
message: simpleMessage(testDownload(Constants.panoramax.url + "/api")),
|
||||
message: simpleMessage(testDownload(Constants.panoramax.url + "/api"))
|
||||
})
|
||||
}
|
||||
{
|
||||
|
|
@ -122,7 +123,7 @@
|
|||
return "degraded"
|
||||
}
|
||||
}),
|
||||
message: simpleMessage(testDownload(Constants.GeoIpServer + "/ip")),
|
||||
message: simpleMessage(testDownload(Constants.GeoIpServer + "/ip"))
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -141,7 +142,7 @@
|
|||
}
|
||||
return "degraded"
|
||||
}),
|
||||
message: simpleMessage(status),
|
||||
message: simpleMessage(status)
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -160,7 +161,7 @@
|
|||
}
|
||||
return "online"
|
||||
}),
|
||||
message: simpleMessage(status),
|
||||
message: simpleMessage(status)
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -199,7 +200,7 @@
|
|||
|
||||
const json = JSON.stringify(s["success"], null, " ")
|
||||
return "Database is " + Math.floor(timediffDays) + " days out of sync\n\n" + json
|
||||
}),
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -212,7 +213,7 @@
|
|||
layer: "food",
|
||||
z: 14,
|
||||
x: 8848,
|
||||
y: 5828,
|
||||
y: 5828
|
||||
})
|
||||
)
|
||||
services.push({
|
||||
|
|
@ -223,7 +224,7 @@
|
|||
}
|
||||
return "online"
|
||||
}),
|
||||
message: new ImmutableStore("See SettingUpPSQL.md to fix"),
|
||||
message: new ImmutableStore("See SettingUpPSQL.md to fix")
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -242,7 +243,7 @@
|
|||
}
|
||||
return "degraded"
|
||||
}),
|
||||
message: status.map((s) => JSON.stringify(s)),
|
||||
message: status.map((s) => JSON.stringify(s))
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -261,7 +262,7 @@
|
|||
return "online"
|
||||
}
|
||||
return "degraded"
|
||||
}),
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -280,7 +281,7 @@
|
|||
}
|
||||
return "degraded"
|
||||
}),
|
||||
message: simpleMessage(status),
|
||||
message: simpleMessage(status)
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -306,7 +307,7 @@
|
|||
|
||||
return "online"
|
||||
}),
|
||||
message: simpleMessage(status),
|
||||
message: simpleMessage(status)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -319,7 +320,36 @@
|
|||
return "online"
|
||||
}
|
||||
return "offline"
|
||||
}),
|
||||
})
|
||||
})
|
||||
|
||||
services.push({
|
||||
name: "Plantnet",
|
||||
status: testDownload(PlantNet.baseUrl, true).mapD((r) => {
|
||||
if (r["success"]) {
|
||||
return "online"
|
||||
}
|
||||
// This code will break in the future. Time to blame past me!
|
||||
const response = JSON.parse(r["error"].substring("other error: , ".length))
|
||||
if (response.message === "\"images\" is required") {
|
||||
// Actual expected behaviour
|
||||
return "online"
|
||||
}
|
||||
console.log("R", response)
|
||||
return "offline"
|
||||
})
|
||||
})
|
||||
}
|
||||
{
|
||||
services.push({
|
||||
name: "Version Control Server (Forgéjo)",
|
||||
status: testDownload("https://source.mapcomplete.org", true).mapD(r => {
|
||||
if (r["success"]) {
|
||||
return "online"
|
||||
}
|
||||
return "offline"
|
||||
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@
|
|||
import RawEditor from "./RawEditor.svelte"
|
||||
import { OsmConnection } from "../../Logic/Osm/OsmConnection"
|
||||
import DeleteButton from "./DeleteButton.svelte"
|
||||
import { UIEventSource } from "../../Logic/UIEventSource"
|
||||
import StudioHashSetter from "./StudioHashSetter"
|
||||
|
||||
export let state: EditThemeState
|
||||
|
|
@ -57,7 +56,7 @@
|
|||
let hasErrors = messages.map(
|
||||
(m: ConversionMessage[]) => m.filter((m) => m.level === "error").length
|
||||
)
|
||||
let title = state.getStoreFor(["id"])
|
||||
let title = state.getStoreFor<string>(["id"])
|
||||
const wl = window.location
|
||||
const baseUrl = wl.protocol + "//" + wl.host + "/theme.html?userlayout="
|
||||
|
||||
|
|
|
|||
|
|
@ -363,7 +363,7 @@
|
|||
id="theme-search"
|
||||
type="search"
|
||||
placeholder="Filter themes by name"
|
||||
bind:value={themeFilterTerm}
|
||||
bind:value={$themeFilterTerm}
|
||||
/>
|
||||
</label>
|
||||
</form>
|
||||
|
|
|
|||
|
|
@ -49,6 +49,8 @@
|
|||
import Loading from "./Base/Loading.svelte"
|
||||
import { WithSearchState } from "../Models/ThemeViewState/WithSearchState"
|
||||
import TitleHandler from "../Logic/Actors/TitleHandler"
|
||||
import Popup from "./Base/Popup.svelte"
|
||||
import TagRenderingAnswer from "./Popup/TagRendering/TagRenderingAnswer.svelte"
|
||||
|
||||
export let state: WithSearchState
|
||||
new TitleHandler(state.selectedElement, state)
|
||||
|
|
@ -76,6 +78,7 @@
|
|||
let mapproperties: MapProperties = state.mapProperties
|
||||
let searchOpened = state.searchState.showSearchDrawer
|
||||
|
||||
let metatags = state.userRelatedState.preferencesAsTags
|
||||
Orientation.singleton.startMeasurements()
|
||||
|
||||
let slideDuration = 150 // ms
|
||||
|
|
@ -500,5 +503,39 @@
|
|||
{/if}
|
||||
{/if}
|
||||
|
||||
{#each theme.popups as popup}
|
||||
{#if popup.condition.matchesProperties($metatags)}
|
||||
<Popup shown={new UIEventSource(true)} dismissable={popup.dismissible}>
|
||||
<TagRenderingAnswer
|
||||
slot="header"
|
||||
config={popup.title}
|
||||
{state}
|
||||
tags={metatags}
|
||||
layer={undefined}
|
||||
selectedElement={{
|
||||
type: "Feature",
|
||||
properties: $metatags,
|
||||
geometry: { type: "Point", coordinates: [0, 0] },
|
||||
}}
|
||||
/>
|
||||
<div class="flex flex-col">
|
||||
{#each popup.body as body}
|
||||
<TagRenderingAnswer
|
||||
config={body}
|
||||
{state}
|
||||
tags={metatags}
|
||||
layer={undefined}
|
||||
selectedElement={{
|
||||
type: "Feature",
|
||||
properties: $metatags,
|
||||
geometry: { type: "Point", coordinates: [0, 0] },
|
||||
}}
|
||||
/>
|
||||
{/each}
|
||||
<span class="subtle">{popup.id}</span>
|
||||
</div>
|
||||
</Popup>
|
||||
{/if}
|
||||
{/each}
|
||||
<MenuDrawer onlyLink={false} {state} />
|
||||
</main>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue