forked from MapComplete/MapComplete
Add translations to more parts of the import helper GUI
This commit is contained in:
parent
8db80d879a
commit
f7844d8b2b
8 changed files with 115 additions and 82 deletions
|
@ -21,6 +21,7 @@ import {FixedUiElement} from "../Base/FixedUiElement";
|
|||
import {VariableUiElement} from "../Base/VariableUIElement";
|
||||
import * as known_layers from "../../assets/generated/known_layers.json"
|
||||
import {LayerConfigJson} from "../../Models/ThemeConfig/Json/LayerConfigJson";
|
||||
import Translations from "../i18n/Translations";
|
||||
|
||||
/**
|
||||
* Filters out points for which the import-note already exists, to prevent duplicates
|
||||
|
@ -28,11 +29,11 @@ import {LayerConfigJson} from "../../Models/ThemeConfig/Json/LayerConfigJson";
|
|||
export class CompareToAlreadyExistingNotes extends Combine implements FlowStep<{ bbox: BBox, layer: LayerConfig, features: any[], theme: string }> {
|
||||
|
||||
public IsValid: UIEventSource<boolean>
|
||||
public Value: UIEventSource<{ bbox: BBox, layer: LayerConfig, features: any[] , theme: string}>
|
||||
public Value: UIEventSource<{ bbox: BBox, layer: LayerConfig, features: any[], theme: string }>
|
||||
|
||||
|
||||
constructor(state, params: { bbox: BBox, layer: LayerConfig, features: any[], theme: string }) {
|
||||
|
||||
constructor(state, params: { bbox: BBox, layer: LayerConfig, features: any[], theme: string }) {
|
||||
const t = Translations.t.importHelper.compareToAlreadyExistingNotes
|
||||
const layerConfig = known_layers.layers.filter(l => l.id === params.layer.id)[0]
|
||||
if (layerConfig === undefined) {
|
||||
console.error("WEIRD: layer not found in the builtin layer overview")
|
||||
|
@ -45,7 +46,7 @@ export class CompareToAlreadyExistingNotes extends Combine implements FlowStep<{
|
|||
layerDef: importLayer
|
||||
}
|
||||
const allNotesWithinBbox = new GeoJsonSource(flayer, params.bbox.padAbsolute(0.0001))
|
||||
|
||||
|
||||
allNotesWithinBbox.features.map(f => MetaTagging.addMetatags(
|
||||
f,
|
||||
{
|
||||
|
@ -63,7 +64,6 @@ export class CompareToAlreadyExistingNotes extends Combine implements FlowStep<{
|
|||
)
|
||||
)
|
||||
const alreadyOpenImportNotes = new FilteringFeatureSource(state, undefined, allNotesWithinBbox)
|
||||
alreadyOpenImportNotes.features.addCallbackD(features => console.log("Loaded and filtered features are", features))
|
||||
const map = Minimap.createMiniMap()
|
||||
map.SetClass("w-full").SetStyle("height: 500px")
|
||||
|
||||
|
@ -99,43 +99,46 @@ export class CompareToAlreadyExistingNotes extends Combine implements FlowStep<{
|
|||
})
|
||||
|
||||
super([
|
||||
new Title("Compare with already existing 'to-import'-notes"),
|
||||
new Title(t.titleLong),
|
||||
new VariableUiElement(
|
||||
alreadyOpenImportNotes.features.map(notesWithImport => {
|
||||
if(allNotesWithinBbox.state.data !== undefined && allNotesWithinBbox.state.data["error"] !== undefined){
|
||||
return new FixedUiElement("Loading notes failed: "+allNotesWithinBbox.state.data["error"] )
|
||||
if (allNotesWithinBbox.state.data !== undefined && allNotesWithinBbox.state.data["error"] !== undefined) {
|
||||
t.loadingFailed.Subs(allNotesWithinBbox.state.data)
|
||||
}
|
||||
if (allNotesWithinBbox.features.data === undefined || allNotesWithinBbox.features.data.length === 0) {
|
||||
return new Loading("Fetching notes from OSM")
|
||||
return new Loading(t.loading)
|
||||
}
|
||||
if (notesWithImport.length === 0) {
|
||||
return new FixedUiElement("No previous import notes found").SetClass("thanks")
|
||||
return t.noPreviousNotesFound.SetClass("thanks")
|
||||
}
|
||||
return new Combine([
|
||||
"The red elements on the next map are all the data points from your dataset. There are <b>"+params.features.length+"</b> elements in your dataset.",
|
||||
t.mapExplanation.Subs(params.features),
|
||||
map,
|
||||
|
||||
new VariableUiElement( partitionedImportPoints.map(({noNearby, hasNearby}) => {
|
||||
|
||||
if(noNearby.length === 0){
|
||||
// Nothing can be imported
|
||||
return new FixedUiElement("All of the proposed points have (or had) an import note already").SetClass("alert w-full block").SetStyle("padding: 0.5rem")
|
||||
}
|
||||
|
||||
if(hasNearby.length === 0){
|
||||
// All points can be imported
|
||||
return new FixedUiElement("All of the proposed points have don't have a previous import note nearby").SetClass("thanks w-full block").SetStyle("padding: 0.5rem")
|
||||
|
||||
}
|
||||
|
||||
return new Combine([
|
||||
new FixedUiElement(hasNearby.length+" points do have an already existing import note within "+maxDistance.data+" meter.").SetClass("alert"),
|
||||
"These data points will <i>not</i> be imported and are shown as red dots on the map below",
|
||||
comparisonMap.SetClass("w-full")
|
||||
]).SetClass("w-full")
|
||||
new VariableUiElement(partitionedImportPoints.map(({noNearby, hasNearby}) => {
|
||||
|
||||
if (noNearby.length === 0) {
|
||||
// Nothing can be imported
|
||||
return t.completelyImported.SetClass("alert w-full block").SetStyle("padding: 0.5rem")
|
||||
}
|
||||
|
||||
if (hasNearby.length === 0) {
|
||||
// All points can be imported
|
||||
return t.nothingNearby.SetClass("thanks w-full block").SetStyle("padding: 0.5rem")
|
||||
|
||||
}
|
||||
|
||||
return new Combine([
|
||||
t.someNearby.Subs({
|
||||
hasNearby: hasNearby.length,
|
||||
distance: maxDistance.data
|
||||
}).SetClass("alert"),
|
||||
t.wontBeImported,
|
||||
comparisonMap.SetClass("w-full")
|
||||
]).SetClass("w-full")
|
||||
}))
|
||||
|
||||
|
||||
|
||||
|
||||
]).SetClass("flex flex-col")
|
||||
|
||||
}, [allNotesWithinBbox.features, allNotesWithinBbox.state])
|
||||
|
|
|
@ -25,15 +25,15 @@ export class FlowPanelFactory<T> {
|
|||
this._stepNames = stepNames;
|
||||
}
|
||||
|
||||
public static start<TOut>(name: string | BaseUIElement, step: FlowStep<TOut>): FlowPanelFactory<TOut> {
|
||||
return new FlowPanelFactory(step, [], [name])
|
||||
public static start<TOut>(name:{title: BaseUIElement}, step: FlowStep<TOut>): FlowPanelFactory<TOut> {
|
||||
return new FlowPanelFactory(step, [], [name.title])
|
||||
}
|
||||
|
||||
public then<TOut>(name: string | BaseUIElement, construct: ((t: T) => FlowStep<TOut>)): FlowPanelFactory<TOut> {
|
||||
public then<TOut>(name: string | {title: BaseUIElement}, construct: ((t: T) => FlowStep<TOut>)): FlowPanelFactory<TOut> {
|
||||
return new FlowPanelFactory<TOut>(
|
||||
this._initial,
|
||||
this._steps.concat([construct]),
|
||||
this._stepNames.concat([name])
|
||||
this._stepNames.concat([name["title"] ?? name])
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ import MinimapImplementation from "../Base/MinimapImplementation";
|
|||
import Translations from "../i18n/Translations";
|
||||
import {FlowPanelFactory} from "./FlowStep";
|
||||
import {RequestFile} from "./RequestFile";
|
||||
import {PreviewPanel} from "./PreviewPanel";
|
||||
import {PreviewAttributesPanel} from "./PreviewPanel";
|
||||
import ConflationChecker from "./ConflationChecker";
|
||||
import {AskMetadata} from "./AskMetadata";
|
||||
import {ConfirmProcess} from "./ConfirmProcess";
|
||||
|
@ -26,16 +26,16 @@ import SelectTheme from "./SelectTheme";
|
|||
export default class ImportHelperGui extends LeftIndex {
|
||||
constructor() {
|
||||
const state = new UserRelatedState(undefined)
|
||||
|
||||
const t = Translations.t.importHelper;
|
||||
const {flow, furthestStep, titles} =
|
||||
FlowPanelFactory
|
||||
.start("Introduction", new Introdution())
|
||||
.then("Login", _ => new LoginToImport(state))
|
||||
.then("Select file", _ => new RequestFile())
|
||||
.then("Inspect attributes", geojson => new PreviewPanel(state, geojson))
|
||||
.then("Inspect data", geojson => new MapPreview(state, geojson))
|
||||
.then("Select theme", v => new SelectTheme(v))
|
||||
.then("Compare with open notes", v => new CompareToAlreadyExistingNotes(state, v))
|
||||
.start(t.introduction, new Introdution())
|
||||
.then(t.login, _ => new LoginToImport(state))
|
||||
.then(t.selectFile, _ => new RequestFile())
|
||||
.then(t.previewAttributes, geojson => new PreviewAttributesPanel(state, geojson))
|
||||
.then(t.mapPreview, geojson => new MapPreview(state, geojson))
|
||||
.then(t.selectTheme, v => new SelectTheme(v))
|
||||
.then(t.compareToAlreadyExistingNotes, v => new CompareToAlreadyExistingNotes(state, v))
|
||||
.then("Compare with existing data", v => new ConflationChecker(state, v))
|
||||
.then("License and community check", v => new ConfirmProcess(v))
|
||||
.then("Metadata", (v) => new AskMetadata(v))
|
||||
|
|
|
@ -10,9 +10,9 @@ export default class Introdution extends Combine implements FlowStep<void> {
|
|||
|
||||
constructor() {
|
||||
super([
|
||||
new Title(Translations.t.importHelper.title),
|
||||
Translations.t.importHelper.description,
|
||||
Translations.t.importHelper.importFormat,
|
||||
new Title(Translations.t.importHelper.introduction.title),
|
||||
Translations.t.importHelper.introduction.description,
|
||||
Translations.t.importHelper.introduction.importFormat,
|
||||
]);
|
||||
this.SetClass("flex flex-col")
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ export default class LoginToImport extends Combine implements FlowStep<UserRelat
|
|||
private static readonly whitelist = [15015689];
|
||||
|
||||
constructor(state: UserRelatedState) {
|
||||
const t = Translations.t.importHelper
|
||||
const t = Translations.t.importHelper.login
|
||||
const check = new CheckBoxes([new VariableUiElement(state.osmConnection.userDetails.map(ud => t.loginIsCorrect.Subs(ud)))])
|
||||
const isValid = state.osmConnection.userDetails.map(ud =>
|
||||
LoginToImport.whitelist.indexOf(ud.uid) >= 0 || ud.csCount >= Constants.userJourney.importHelperUnlock)
|
||||
|
|
|
@ -12,16 +12,16 @@ import List from "../Base/List";
|
|||
import CheckBoxes from "../Input/Checkboxes";
|
||||
|
||||
/**
|
||||
* Shows the data to import on a map, asks for the correct layer to be selected
|
||||
* Shows the attributes by value, requests to check them of
|
||||
*/
|
||||
export class PreviewPanel extends Combine implements FlowStep<{ features: { properties: any, geometry: { coordinates: [number, number] } }[] }> {
|
||||
export class PreviewAttributesPanel extends Combine implements FlowStep<{ features: { properties: any, geometry: { coordinates: [number, number] } }[] }> {
|
||||
public readonly IsValid: UIEventSource<boolean>;
|
||||
public readonly Value: UIEventSource<{ features: { properties: any, geometry: { coordinates: [number, number] } }[] }>
|
||||
|
||||
constructor(
|
||||
state: UserRelatedState,
|
||||
geojson: { features: { properties: any, geometry: { coordinates: [number, number] } }[] }) {
|
||||
const t = Translations.t.importHelper;
|
||||
const t = Translations.t.importHelper.previewAttributes;
|
||||
|
||||
const propertyKeys = new Set<string>()
|
||||
for (const f of geojson.features) {
|
||||
|
|
|
@ -10,12 +10,12 @@ import Title from "../Base/Title";
|
|||
import {RadioButton} from "../Input/RadioButton";
|
||||
import {And} from "../../Logic/Tags/And";
|
||||
import {VariableUiElement} from "../Base/VariableUIElement";
|
||||
import {FixedUiElement} from "../Base/FixedUiElement";
|
||||
import Toggleable from "../Base/Toggleable";
|
||||
import {BBox} from "../../Logic/BBox";
|
||||
import BaseUIElement from "../BaseUIElement";
|
||||
import PresetConfig from "../../Models/ThemeConfig/PresetConfig";
|
||||
import List from "../Base/List";
|
||||
import Translations from "../i18n/Translations";
|
||||
|
||||
export default class SelectTheme extends Combine implements FlowStep<{
|
||||
features: any[],
|
||||
|
@ -33,7 +33,7 @@ export default class SelectTheme extends Combine implements FlowStep<{
|
|||
public readonly IsValid: UIEventSource<boolean>;
|
||||
|
||||
constructor(params: ({ features: any[], layer: LayerConfig, bbox: BBox, })) {
|
||||
|
||||
const t = Translations.t.importHelper.selectTheme
|
||||
let options: InputElement<string>[] = AllKnownLayouts.layoutsList
|
||||
.filter(th => th.layers.some(l => l.id === params.layer.id))
|
||||
.filter(th => th.id !== "personal")
|
||||
|
@ -69,15 +69,15 @@ export default class SelectTheme extends Combine implements FlowStep<{
|
|||
})
|
||||
|
||||
super([
|
||||
new Title("Select a theme"),
|
||||
"All of the following themes will show the import notes. However, the note on OpenStreetMap can link to only one single theme. Choose which theme that the created notes will link to",
|
||||
new Title(t.title),
|
||||
t.intro,
|
||||
themeRadios,
|
||||
new VariableUiElement(applicablePresets.map(applicablePresets => {
|
||||
if (themeRadios.GetValue().data === undefined) {
|
||||
return undefined
|
||||
}
|
||||
if (applicablePresets === undefined || applicablePresets.length === 0) {
|
||||
return new FixedUiElement("This theme has no presets loaded. As a result, imports won't work here").SetClass("alert")
|
||||
return t.noMatchingPresets.SetClass("alert")
|
||||
}
|
||||
}, [themeRadios.GetValue()])),
|
||||
|
||||
|
@ -115,11 +115,14 @@ export default class SelectTheme extends Combine implements FlowStep<{
|
|||
if (unmatched === undefined || unmatched.length === 0) {
|
||||
return
|
||||
}
|
||||
|
||||
const applicablePresetsOverview = applicablePresets.map(preset => new Combine([
|
||||
preset.title.txt, "needs tags",
|
||||
new FixedUiElement(preset.tags.map(t => t.asHumanString()).join(" & ")).SetClass("thanks")
|
||||
]))
|
||||
const t = Translations.t.importHelper.selectTheme
|
||||
|
||||
const applicablePresetsOverview = applicablePresets.map(preset =>
|
||||
t.needsTags.Subs(
|
||||
{title: preset.title,
|
||||
tags:preset.tags.map(t => t.asHumanString()).join(" & ") })
|
||||
.SetClass("thanks")
|
||||
);
|
||||
|
||||
const unmatchedPanels: BaseUIElement[] = []
|
||||
for (const feat of unmatched) {
|
||||
|
@ -133,20 +136,16 @@ export default class SelectTheme extends Combine implements FlowStep<{
|
|||
const missing = []
|
||||
for (const {k, v} of tags) {
|
||||
if (preset[k] === undefined) {
|
||||
missing.push(
|
||||
`Expected ${k}=${v}, but it is completely missing`
|
||||
)
|
||||
missing.push(t.missing.Subs({k,v}))
|
||||
} else if (feat.properties[k] !== v) {
|
||||
missing.push(
|
||||
`Property with key ${k} does not have expected value ${v}; instead it is ${feat.properties}`
|
||||
)
|
||||
missing.push(t.misMatch.Subs({k, v, properties: feat.properties}))
|
||||
}
|
||||
}
|
||||
|
||||
if (missing.length > 0) {
|
||||
parts.push(
|
||||
new Combine([
|
||||
new FixedUiElement(`Preset ${preset.title.txt} is not applicable:`),
|
||||
t.notApplicable.Subs(preset),
|
||||
new List(missing)
|
||||
]).SetClass("flex flex-col alert")
|
||||
)
|
||||
|
@ -158,9 +157,9 @@ export default class SelectTheme extends Combine implements FlowStep<{
|
|||
}
|
||||
|
||||
return new Combine([
|
||||
new FixedUiElement(unmatched.length + " objects dont match any presets").SetClass("alert"),
|
||||
t.displayNonMatchingCount.Subs(unmatched).SetClass("alert"),
|
||||
...applicablePresetsOverview,
|
||||
new Toggleable(new Title("The following elements don't match any of the presets"),
|
||||
new Toggleable(new Title(t.unmatchedTitle),
|
||||
new Combine(unmatchedPanels))
|
||||
]).SetClass("flex flex-col")
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue