forked from MapComplete/MapComplete
Refactoring: port AutoApplyButton to svelte
This commit is contained in:
parent
ab88afc397
commit
56020adc2f
8 changed files with 318 additions and 353 deletions
179
src/UI/Popup/AutoApplyButton.svelte
Normal file
179
src/UI/Popup/AutoApplyButton.svelte
Normal file
|
|
@ -0,0 +1,179 @@
|
|||
<script lang="ts">
|
||||
import Loading from "../Base/Loading.svelte"
|
||||
import MaplibreMap from "../Map/MaplibreMap.svelte"
|
||||
import { Utils } from "../../Utils"
|
||||
import { Store, UIEventSource } from "../../Logic/UIEventSource"
|
||||
import FilteredLayer from "../../Models/FilteredLayer"
|
||||
import TagRenderingConfig from "../../Models/ThemeConfig/TagRenderingConfig"
|
||||
import type { SpecialVisualizationState } from "../SpecialVisualization"
|
||||
import { MapLibreAdaptor } from "../Map/MapLibreAdaptor"
|
||||
import ShowDataLayer from "../Map/ShowDataLayer"
|
||||
import StaticFeatureSource from "../../Logic/FeatureSource/Sources/StaticFeatureSource"
|
||||
import SpecialVisualizations from "../SpecialVisualizations"
|
||||
import type { AutoAction } from "./AutoApplyButtonVis"
|
||||
import Tr from "../Base/Tr.svelte"
|
||||
import Translations from "../i18n/Translations"
|
||||
|
||||
/**
|
||||
* The ids to handle. Might be data from an external dataset, we cannot assume an OSM-id
|
||||
*/
|
||||
export let ids: Store<string[] | undefined>
|
||||
export let state: SpecialVisualizationState
|
||||
export let options: {
|
||||
target_layer_id: string,
|
||||
targetTagRendering: string,
|
||||
text: string,
|
||||
icon: string,
|
||||
}
|
||||
let buttonState: UIEventSource<
|
||||
"idle" | "running" | "done" | { error: string }
|
||||
> = new UIEventSource<
|
||||
"idle" | "running" | "done" | { error: string }
|
||||
>("idle")
|
||||
let tagRenderingConfig: TagRenderingConfig
|
||||
let appliedNumberOfFeatures = new UIEventSource<number>(0)
|
||||
|
||||
let layer: FilteredLayer = state.layerState.filteredLayers.get(options.target_layer_id)
|
||||
tagRenderingConfig = layer.layerDef.tagRenderings.find(
|
||||
(tr) => tr.id === options.targetTagRendering
|
||||
)
|
||||
|
||||
const mlmap = new UIEventSource(undefined)
|
||||
const mla = new MapLibreAdaptor(mlmap, {
|
||||
rasterLayer: state.mapProperties.rasterLayer
|
||||
})
|
||||
mla.allowZooming.setData(false)
|
||||
mla.allowMoving.setData(false)
|
||||
|
||||
const features = ids.mapD(ids => ids.map((id) =>
|
||||
state.indexedFeatures.featuresById.data.get(id)
|
||||
))
|
||||
|
||||
|
||||
new ShowDataLayer(mlmap, {
|
||||
features: StaticFeatureSource.fromGeojson(features),
|
||||
zoomToFeatures: true,
|
||||
layer: layer.layerDef
|
||||
})
|
||||
|
||||
features.addCallbackAndRunD(f => console.log("Features are now", f))
|
||||
|
||||
async function applyAllChanges() {
|
||||
buttonState.set("running")
|
||||
try {
|
||||
const target_feature_ids = ids.data
|
||||
console.log("Applying auto-action on " + target_feature_ids.length + " features")
|
||||
const appliedOn: string[] = []
|
||||
for (let i = 0; i < target_feature_ids.length; i++) {
|
||||
const targetFeatureId = target_feature_ids[i]
|
||||
console.log("Handling", targetFeatureId)
|
||||
const feature = state.indexedFeatures.featuresById.data.get(targetFeatureId)
|
||||
const featureTags = state.featureProperties.getStore(targetFeatureId)
|
||||
const rendering = tagRenderingConfig.GetRenderValue(featureTags.data).txt
|
||||
const specialRenderings = Utils.NoNull(
|
||||
SpecialVisualizations.constructSpecification(rendering)
|
||||
).filter((v) => typeof v !== "string" && v.func["supportsAutoAction"] === true)
|
||||
|
||||
if (specialRenderings.length == 0) {
|
||||
console.warn(
|
||||
"AutoApply: feature " +
|
||||
targetFeatureId +
|
||||
" got a rendering without supported auto actions:",
|
||||
rendering
|
||||
)
|
||||
}
|
||||
|
||||
for (const specialRendering of specialRenderings) {
|
||||
if (typeof specialRendering === "string") {
|
||||
continue
|
||||
}
|
||||
const action = <AutoAction>specialRendering.func
|
||||
await action.applyActionOn(
|
||||
feature,
|
||||
state,
|
||||
featureTags,
|
||||
specialRendering.args
|
||||
)
|
||||
}
|
||||
appliedOn.push(targetFeatureId)
|
||||
if (i % 50 === 0) {
|
||||
await state.changes.flushChanges("Auto button: intermediate save")
|
||||
}
|
||||
appliedNumberOfFeatures.setData(i + 1)
|
||||
}
|
||||
console.log("Flushing changes...")
|
||||
await state.changes.flushChanges("Auto button: done")
|
||||
buttonState.setData("done")
|
||||
console.log(
|
||||
"Applied changes onto",
|
||||
appliedOn.length,
|
||||
"items, unique IDs:",
|
||||
new Set(appliedOn).size
|
||||
)
|
||||
} catch (e) {
|
||||
console.error("Error while running autoApply: ", e)
|
||||
buttonState.setData({ error: e })
|
||||
}
|
||||
}
|
||||
|
||||
const t = Translations.t.general.add.import
|
||||
|
||||
</script>
|
||||
|
||||
{#if !state.theme.official && !state.featureSwitchIsTesting.data}
|
||||
<div class="alert">The auto-apply button is only available in official themes (or in testing mode)</div>
|
||||
<Tr t={t.howToTest} />
|
||||
|
||||
{:else if ids === undefined}
|
||||
<Loading>Gathering which elements support auto-apply...</Loading>
|
||||
{:else if tagRenderingConfig === undefined}
|
||||
<div class="alert">Target tagrendering {options.targetTagRendering} not found"</div>
|
||||
{:else if $ids.length === 0}
|
||||
<div>No elements found to perform action</div>
|
||||
{:else if $buttonState.error !== undefined}
|
||||
<div class="flex flex-col">
|
||||
|
||||
<div class="alert">Something went wrong</div>
|
||||
<div>{$buttonState.error}</div>
|
||||
</div>
|
||||
{:else if $buttonState === "done"}
|
||||
<div class="thanks">All done!</div>
|
||||
{:else if $buttonState === "running"}
|
||||
<Loading>
|
||||
Applying changes, currently at {$appliedNumberOfFeatures} / {$ids.length}
|
||||
</Loading>
|
||||
{:else if $buttonState === "idle"}
|
||||
<div class="flex flex-col">
|
||||
<button on:click={() => {applyAllChanges()}}>
|
||||
<img class="h-8 w-8" alt="" src={options.icon} />
|
||||
{options.text}
|
||||
</button>
|
||||
|
||||
<div class="h-48 w-full">
|
||||
<MaplibreMap mapProperties={mla} map={mlmap} />
|
||||
</div>
|
||||
|
||||
<div class="subtle link-underline">
|
||||
The following objects will be updated:
|
||||
<div class="flex flex-wrap gap-x-2">
|
||||
|
||||
{#each $ids as featId}
|
||||
{#if layer.layerDef.source.geojsonSource === undefined}
|
||||
<a href={"https://openstreetmap.org/" + featId} target="_blank">{featId}</a>
|
||||
{:else}
|
||||
<div>
|
||||
{featId}
|
||||
</div>
|
||||
{/if}
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{:else}
|
||||
<div>Not supposed to show this... AutoApplyButton has invalid buttonstate: {$buttonState}</div>
|
||||
{/if}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue