import {FlowStep} from "./FlowStep"; import Combine from "../Base/Combine"; import {Store} from "../../Logic/UIEventSource"; import LayerConfig from "../../Models/ThemeConfig/LayerConfig"; import {InputElement} from "../Input/InputElement"; import {AllKnownLayouts} from "../../Customizations/AllKnownLayouts"; import {FixedInputElement} from "../Input/FixedInputElement"; import Img from "../Base/Img"; import Title from "../Base/Title"; import {RadioButton} from "../Input/RadioButton"; import {And} from "../../Logic/Tags/And"; import {VariableUiElement} from "../Base/VariableUIElement"; 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[], theme: string, layer: LayerConfig, bbox: BBox, }> { public readonly Value: Store<{ features: any[], theme: string, layer: LayerConfig, bbox: BBox, }>; public readonly IsValid: Store; constructor(params: ({ features: any[], layer: LayerConfig, bbox: BBox, })) { const t = Translations.t.importHelper.selectTheme let options: InputElement[] = AllKnownLayouts.layoutsList .filter(th => th.layers.some(l => l.id === params.layer.id)) .filter(th => th.id !== "personal") .map(th => new FixedInputElement( new Combine([ new Img(th.icon).SetClass("block h-12 w-12 br-4"), new Title(th.title) ]).SetClass("flex items-center"), th.id)) const themeRadios = new RadioButton(options, { selectFirstAsDefault: false }) const applicablePresets = themeRadios.GetValue().map(theme => { if (theme === undefined) { return [] } // we get the layer with the correct ID via the actual theme config, as the actual theme might have different presets due to overrides const themeConfig = AllKnownLayouts.layoutsList.find(th => th.id === theme) const layer = themeConfig.layers.find(l => l.id === params.layer.id) return layer.presets }) const nonMatchedElements = applicablePresets.map(presets => { if (presets === undefined || presets.length === 0) { return undefined } return params.features.filter(feat => !presets.some(preset => new And(preset.tags).matchesProperties(feat.properties))) }) super([ 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 t.noMatchingPresets.SetClass("alert") } }, [themeRadios.GetValue()])), new VariableUiElement(nonMatchedElements.map(unmatched => SelectTheme.nonMatchedElementsPanel(unmatched, applicablePresets.data), [applicablePresets])) ]); this.SetClass("flex flex-col") this.Value = themeRadios.GetValue().map(theme => ({ features: params.features, layer: params.layer, bbox: params.bbox, theme })) this.IsValid = this.Value.map(obj => { if (obj === undefined) { return false; } if ([obj.theme, obj.features].some(v => v === undefined)) { return false; } if (applicablePresets.data === undefined || applicablePresets.data.length === 0) { return false } if ((nonMatchedElements.data?.length ?? 0) > 0) { return false; } return true; }, [applicablePresets]) } private static nonMatchedElementsPanel(unmatched: any[], applicablePresets: PresetConfig[]): BaseUIElement { if (unmatched === undefined || unmatched.length === 0) { return } 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) { const parts: BaseUIElement[] = [] parts.push(new Combine(Object.keys(feat.properties).map(k => k+"="+feat.properties[k] )).SetClass("flex flex-col")) for (const preset of applicablePresets) { const tags = new And(preset.tags).asChange({}) const missing = [] for (const {k, v} of tags) { if (preset[k] === undefined) { missing.push(t.missing.Subs({k,v})) } else if (feat.properties[k] !== v) { missing.push(t.misMatch.Subs({k, v, properties: feat.properties})) } } if (missing.length > 0) { parts.push( new Combine([ t.notApplicable.Subs(preset), new List(missing) ]).SetClass("flex flex-col alert") ) } } unmatchedPanels.push(new Combine(parts).SetClass("flex flex-col")) } return new Combine([ t.displayNonMatchingCount.Subs(unmatched).SetClass("alert"), ...applicablePresetsOverview, new Toggleable(new Title(t.unmatchedTitle), new Combine(unmatchedPanels)) ]).SetClass("flex flex-col") } }