forked from MapComplete/MapComplete
		
	Split up allKnownLayouts, make parsing it lazy for faster loading
This commit is contained in:
		
							parent
							
								
									6dc0fa0851
								
							
						
					
					
						commit
						6ee85b12f8
					
				
					 14 changed files with 311 additions and 323 deletions
				
			
		|  | @ -1,298 +1,52 @@ | |||
| import known_themes from "../assets/generated/known_layers_and_themes.json" | ||||
| import known_themes from "../assets/generated/known_themes.json" | ||||
| import LayoutConfig from "../Models/ThemeConfig/LayoutConfig" | ||||
| import LayerConfig from "../Models/ThemeConfig/LayerConfig" | ||||
| import BaseUIElement from "../UI/BaseUIElement" | ||||
| import Combine from "../UI/Base/Combine" | ||||
| import Title from "../UI/Base/Title" | ||||
| import List from "../UI/Base/List" | ||||
| import DependencyCalculator from "../Models/ThemeConfig/DependencyCalculator" | ||||
| import Constants from "../Models/Constants" | ||||
| import { Utils } from "../Utils" | ||||
| import Link from "../UI/Base/Link" | ||||
| import { LayoutConfigJson } from "../Models/ThemeConfig/Json/LayoutConfigJson" | ||||
| import { LayerConfigJson } from "../Models/ThemeConfig/Json/LayerConfigJson" | ||||
| 
 | ||||
| export class AllKnownLayouts { | ||||
|     public static allKnownLayouts: Map<string, LayoutConfig> = AllKnownLayouts.AllLayouts() | ||||
|     public static layoutsList: LayoutConfig[] = AllKnownLayouts.GenerateOrderedList( | ||||
|         AllKnownLayouts.allKnownLayouts | ||||
|     ) | ||||
|     // Must be below the list...
 | ||||
|     private static sharedLayers: Map<string, LayerConfig> = AllKnownLayouts.getSharedLayers() | ||||
| 
 | ||||
|     public static AllPublicLayers(options?: { | ||||
|         includeInlineLayers: true | boolean | ||||
|     }): LayerConfig[] { | ||||
|         const allLayers: LayerConfig[] = [] | ||||
|         const seendIds = new Set<string>() | ||||
|         AllKnownLayouts.sharedLayers.forEach((layer, key) => { | ||||
|             seendIds.add(key) | ||||
|             allLayers.push(layer) | ||||
|         }) | ||||
|         if (options?.includeInlineLayers ?? true) { | ||||
|             const publicLayouts = AllKnownLayouts.layoutsList.filter((l) => !l.hideFromOverview) | ||||
|             for (const layout of publicLayouts) { | ||||
|                 if (layout.hideFromOverview) { | ||||
|                     continue | ||||
|                 } | ||||
|                 for (const layer of layout.layers) { | ||||
|                     if (seendIds.has(layer.id)) { | ||||
|                         continue | ||||
|                     } | ||||
|                     seendIds.add(layer.id) | ||||
|                     allLayers.push(layer) | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         return allLayers | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Returns all themes which use the given layer, reverse sorted by minzoom. This sort maximizes the chances that the layer is prominently featured on the first theme | ||||
|      */ | ||||
|     public static themesUsingLayer(id: string, publicOnly = true): LayoutConfig[] { | ||||
|         const themes = AllKnownLayouts.layoutsList | ||||
|             .filter((l) => !(publicOnly && l.hideFromOverview) && l.id !== "personal") | ||||
|             .map((theme) => ({ | ||||
|                 theme, | ||||
|                 minzoom: theme.layers.find((layer) => layer.id === id)?.minzoom, | ||||
|             })) | ||||
|             .filter((obj) => obj.minzoom !== undefined) | ||||
|         themes.sort((th0, th1) => th1.minzoom - th0.minzoom) | ||||
|         return themes.map((th) => th.theme) | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Generates documentation for the layers. | ||||
|      * Inline layers are included (if the theme is public) | ||||
|      * @param callback | ||||
|      * @constructor | ||||
|      */ | ||||
|     public static GenOverviewsForSingleLayer( | ||||
|         callback: (layer: LayerConfig, element: BaseUIElement, inlineSource: string) => void | ||||
|     ): void { | ||||
|         const allLayers: LayerConfig[] = Array.from(AllKnownLayouts.sharedLayers.values()).filter( | ||||
|             (layer) => Constants.priviliged_layers.indexOf(layer.id) < 0 | ||||
|         ) | ||||
|         const builtinLayerIds: Set<string> = new Set<string>() | ||||
|         allLayers.forEach((l) => builtinLayerIds.add(l.id)) | ||||
|         const inlineLayers = new Map<string, string>() | ||||
| 
 | ||||
|         for (const layout of Array.from(AllKnownLayouts.allKnownLayouts.values())) { | ||||
|             if (layout.hideFromOverview) { | ||||
|                 continue | ||||
|             } | ||||
| 
 | ||||
|             for (const layer of layout.layers) { | ||||
|                 if (Constants.priviliged_layers.indexOf(layer.id) >= 0) { | ||||
|                     continue | ||||
|                 } | ||||
|                 if (builtinLayerIds.has(layer.id)) { | ||||
|                     continue | ||||
|                 } | ||||
|                 if (layer.source.geojsonSource !== undefined) { | ||||
|                     // Not an OSM-source
 | ||||
|                     continue | ||||
|                 } | ||||
|                 allLayers.push(layer) | ||||
|                 builtinLayerIds.add(layer.id) | ||||
|                 inlineLayers.set(layer.id, layout.id) | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         const themesPerLayer = new Map<string, string[]>() | ||||
| 
 | ||||
|         for (const layout of Array.from(AllKnownLayouts.allKnownLayouts.values())) { | ||||
|             if (layout.hideFromOverview) { | ||||
|                 continue | ||||
|             } | ||||
|             for (const layer of layout.layers) { | ||||
|                 if (!builtinLayerIds.has(layer.id)) { | ||||
|                     // This is an inline layer
 | ||||
|                     continue | ||||
|                 } | ||||
|                 if (!themesPerLayer.has(layer.id)) { | ||||
|                     themesPerLayer.set(layer.id, []) | ||||
|                 } | ||||
|                 themesPerLayer.get(layer.id).push(layout.id) | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         // Determine the cross-dependencies
 | ||||
|         const layerIsNeededBy: Map<string, string[]> = new Map<string, string[]>() | ||||
| 
 | ||||
|         for (const layer of allLayers) { | ||||
|             for (const dep of DependencyCalculator.getLayerDependencies(layer)) { | ||||
|                 const dependency = dep.neededLayer | ||||
|                 if (!layerIsNeededBy.has(dependency)) { | ||||
|                     layerIsNeededBy.set(dependency, []) | ||||
|                 } | ||||
|                 layerIsNeededBy.get(dependency).push(layer.id) | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         allLayers.forEach((layer) => { | ||||
|             const element = layer.GenerateDocumentation( | ||||
|                 themesPerLayer.get(layer.id), | ||||
|                 layerIsNeededBy, | ||||
|                 DependencyCalculator.getLayerDependencies(layer) | ||||
|             ) | ||||
|             callback(layer, element, inlineLayers.get(layer.id)) | ||||
|         }) | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Generates the documentation for the layers overview page | ||||
|      * @constructor | ||||
|      */ | ||||
|     public static GenLayerOverviewText(): BaseUIElement { | ||||
|         for (const id of Constants.priviliged_layers) { | ||||
|             if (!AllKnownLayouts.sharedLayers.has(id)) { | ||||
|                 throw "Priviliged layer definition not found: " + id | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         const allLayers: LayerConfig[] = Array.from(AllKnownLayouts.sharedLayers.values()).filter( | ||||
|             (layer) => Constants.priviliged_layers.indexOf(layer.id) < 0 | ||||
|         ) | ||||
| 
 | ||||
|         const builtinLayerIds: Set<string> = new Set<string>() | ||||
|         allLayers.forEach((l) => builtinLayerIds.add(l.id)) | ||||
| 
 | ||||
|         const themesPerLayer = new Map<string, string[]>() | ||||
| 
 | ||||
|         for (const layout of Array.from(AllKnownLayouts.allKnownLayouts.values())) { | ||||
|             for (const layer of layout.layers) { | ||||
|                 if (!builtinLayerIds.has(layer.id)) { | ||||
|                     continue | ||||
|                 } | ||||
|                 if (!themesPerLayer.has(layer.id)) { | ||||
|                     themesPerLayer.set(layer.id, []) | ||||
|                 } | ||||
|                 themesPerLayer.get(layer.id).push(layout.id) | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         // Determine the cross-dependencies
 | ||||
|         const layerIsNeededBy: Map<string, string[]> = new Map<string, string[]>() | ||||
| 
 | ||||
|         for (const layer of allLayers) { | ||||
|             for (const dep of DependencyCalculator.getLayerDependencies(layer)) { | ||||
|                 const dependency = dep.neededLayer | ||||
|                 if (!layerIsNeededBy.has(dependency)) { | ||||
|                     layerIsNeededBy.set(dependency, []) | ||||
|                 } | ||||
|                 layerIsNeededBy.get(dependency).push(layer.id) | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         return new Combine([ | ||||
|             new Title("Special and other useful layers", 1), | ||||
|             "MapComplete has a few data layers available in the theme which have special properties through builtin-hooks. Furthermore, there are some normal layers (which are built from normal Theme-config files) but are so general that they get a mention here.", | ||||
|             new Title("Priviliged layers", 1), | ||||
|             new List(Constants.priviliged_layers.map((id) => "[" + id + "](#" + id + ")")), | ||||
|             ...Constants.priviliged_layers | ||||
|                 .map((id) => AllKnownLayouts.sharedLayers.get(id)) | ||||
|                 .map((l) => | ||||
|                     l.GenerateDocumentation( | ||||
|                         themesPerLayer.get(l.id), | ||||
|                         layerIsNeededBy, | ||||
|                         DependencyCalculator.getLayerDependencies(l), | ||||
|                         Constants.added_by_default.indexOf(l.id) >= 0, | ||||
|                         Constants.no_include.indexOf(l.id) < 0 | ||||
|                     ) | ||||
|                 ), | ||||
|             new Title("Normal layers", 1), | ||||
|             "The following layers are included in MapComplete:", | ||||
|             new List( | ||||
|                 Array.from(AllKnownLayouts.sharedLayers.keys()).map( | ||||
|                     (id) => new Link(id, "./Layers/" + id + ".md") | ||||
|                 ) | ||||
|             ), | ||||
|         ]) | ||||
|     } | ||||
| 
 | ||||
|     public static GenerateDocumentationForTheme(theme: LayoutConfig): BaseUIElement { | ||||
|         return new Combine([ | ||||
|             new Title( | ||||
|                 new Combine([ | ||||
|                     theme.title, | ||||
|                     "(", | ||||
|                     new Link(theme.id, "https://mapcomplete.osm.be/" + theme.id), | ||||
|                     ")", | ||||
|                 ]), | ||||
|                 2 | ||||
|             ), | ||||
|             theme.description, | ||||
|             "This theme contains the following layers:", | ||||
|             new List( | ||||
|                 theme.layers | ||||
|                     .filter((l) => !l.id.startsWith("note_import_")) | ||||
|                     .map((l) => new Link(l.id, "../Layers/" + l.id + ".md")) | ||||
|             ), | ||||
|             "Available languages:", | ||||
|             new List(theme.language.filter((ln) => ln !== "_context")), | ||||
|         ]).SetClass("flex flex-col") | ||||
|     } | ||||
| 
 | ||||
|     public static getSharedLayers(): Map<string, LayerConfig> { | ||||
|         const sharedLayers = new Map<string, LayerConfig>() | ||||
|         for (const layer of known_themes["layers"]) { | ||||
|             try { | ||||
|                 // @ts-ignore
 | ||||
|                 const parsed = new LayerConfig(layer, "shared_layers") | ||||
|                 sharedLayers.set(layer.id, parsed) | ||||
|             } catch (e) { | ||||
|                 if (!Utils.runningFromConsole) { | ||||
|                     console.error( | ||||
|                         "CRITICAL: Could not parse a layer configuration!", | ||||
|                         layer.id, | ||||
|                         " due to", | ||||
|                         e | ||||
|                     ) | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         return sharedLayers | ||||
|     } | ||||
| 
 | ||||
|     public static getSharedLayersConfigs(): Map<string, LayerConfigJson> { | ||||
|         const sharedLayers = new Map<string, LayerConfigJson>() | ||||
|         for (const layer of known_themes["layers"]) { | ||||
|             // @ts-ignore
 | ||||
|             sharedLayers.set(layer.id, layer) | ||||
|         } | ||||
| 
 | ||||
|         return sharedLayers | ||||
|     } | ||||
| 
 | ||||
|     private static GenerateOrderedList(allKnownLayouts: Map<string, LayoutConfig>): LayoutConfig[] { | ||||
|         const list = [] | ||||
|         allKnownLayouts.forEach((layout) => { | ||||
|             list.push(layout) | ||||
|         }) | ||||
|         return list | ||||
|     } | ||||
| 
 | ||||
|     private static AllLayouts(): Map<string, LayoutConfig> { | ||||
|         const dict: Map<string, LayoutConfig> = new Map() | ||||
| /** | ||||
|  * Somewhat of a dictionary, which lazily parses needed themes | ||||
|  */ | ||||
| export class AllKnownLayoutsLazy { | ||||
|     private readonly dict: Map<string, { data: LayoutConfig } | { func: () => LayoutConfig }> = | ||||
|         new Map() | ||||
|     constructor() { | ||||
|         for (const layoutConfigJson of known_themes["themes"]) { | ||||
|             const layout = new LayoutConfig(<LayoutConfigJson>layoutConfigJson, true) | ||||
|             dict.set(layout.id, layout) | ||||
|             for (let i = 0; i < layout.layers.length; i++) { | ||||
|                 let layer = layout.layers[i] | ||||
|                 if (typeof layer === "string") { | ||||
|                     layer = AllKnownLayouts.sharedLayers.get(layer) | ||||
|                     layout.layers[i] = layer | ||||
|                     if (layer === undefined) { | ||||
|                         console.log("Defined layers are ", AllKnownLayouts.sharedLayers.keys()) | ||||
|                         throw `Layer ${layer} was not found or defined - probably a type was made` | ||||
|             this.dict.set(layoutConfigJson.id, { | ||||
|                 func: () => { | ||||
|                     const layout = new LayoutConfig(<LayoutConfigJson>layoutConfigJson, true) | ||||
|                     for (let i = 0; i < layout.layers.length; i++) { | ||||
|                         let layer = layout.layers[i] | ||||
|                         if (typeof layer === "string") { | ||||
|                             throw "Layer " + layer + " was not expanded in " + layout.id | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|                     return layout | ||||
|                 }, | ||||
|             }) | ||||
|         } | ||||
|         return dict | ||||
|     } | ||||
| 
 | ||||
|     public get(key: string): LayoutConfig { | ||||
|         const thunk = this.dict.get(key) | ||||
|         if (thunk === undefined) { | ||||
|             return undefined | ||||
|         } | ||||
|         if (thunk["data"]) { | ||||
|             return thunk["data"] | ||||
|         } | ||||
|         const layout = thunk["func"]() | ||||
|         this.dict.set(key, { data: layout }) | ||||
|         return layout | ||||
|     } | ||||
| 
 | ||||
|     public keys() { | ||||
|         return this.dict.keys() | ||||
|     } | ||||
| 
 | ||||
|     public values() { | ||||
|         return Array.from(this.keys()).map((k) => this.get(k)) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| export class AllKnownLayouts { | ||||
|     public static allKnownLayouts: AllKnownLayoutsLazy = new AllKnownLayoutsLazy() | ||||
| } | ||||
|  |  | |||
							
								
								
									
										69
									
								
								Customizations/AllSharedLayers.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								Customizations/AllSharedLayers.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,69 @@ | |||
| import LayerConfig from "../Models/ThemeConfig/LayerConfig" | ||||
| import { Utils } from "../Utils" | ||||
| import known_themes from "../assets/generated/known_layers.json" | ||||
| import { LayerConfigJson } from "../Models/ThemeConfig/Json/LayerConfigJson" | ||||
| import { ALL } from "dns" | ||||
| import { AllKnownLayouts } from "./AllKnownLayouts" | ||||
| export class AllSharedLayers { | ||||
|     public static sharedLayers: Map<string, LayerConfig> = AllSharedLayers.getSharedLayers() | ||||
|     public static getSharedLayersConfigs(): Map<string, LayerConfigJson> { | ||||
|         const sharedLayers = new Map<string, LayerConfigJson>() | ||||
|         for (const layer of known_themes.layers) { | ||||
|             // @ts-ignore
 | ||||
|             sharedLayers.set(layer.id, layer) | ||||
|         } | ||||
| 
 | ||||
|         return sharedLayers | ||||
|     } | ||||
|     private static getSharedLayers(): Map<string, LayerConfig> { | ||||
|         const sharedLayers = new Map<string, LayerConfig>() | ||||
|         for (const layer of known_themes.layers) { | ||||
|             try { | ||||
|                 // @ts-ignore
 | ||||
|                 const parsed = new LayerConfig(layer, "shared_layers") | ||||
|                 sharedLayers.set(layer.id, parsed) | ||||
|             } catch (e) { | ||||
|                 if (!Utils.runningFromConsole) { | ||||
|                     console.error( | ||||
|                         "CRITICAL: Could not parse a layer configuration!", | ||||
|                         layer.id, | ||||
|                         " due to", | ||||
|                         e | ||||
|                     ) | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         return sharedLayers | ||||
|     } | ||||
| 
 | ||||
|     public static AllPublicLayers(options?: { | ||||
|         includeInlineLayers: true | boolean | ||||
|     }): LayerConfig[] { | ||||
|         const allLayers: LayerConfig[] = [] | ||||
|         const seendIds = new Set<string>() | ||||
|         AllSharedLayers.sharedLayers.forEach((layer, key) => { | ||||
|             seendIds.add(key) | ||||
|             allLayers.push(layer) | ||||
|         }) | ||||
|         if (options?.includeInlineLayers ?? true) { | ||||
|             const publicLayouts = Array.from(AllKnownLayouts.allKnownLayouts.values()).filter( | ||||
|                 (l) => !l.hideFromOverview | ||||
|             ) | ||||
|             for (const layout of publicLayouts) { | ||||
|                 if (layout.hideFromOverview) { | ||||
|                     continue | ||||
|                 } | ||||
|                 for (const layer of layout.layers) { | ||||
|                     if (seendIds.has(layer.id)) { | ||||
|                         continue | ||||
|                     } | ||||
|                     seendIds.add(layer.id) | ||||
|                     allLayers.push(layer) | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         return allLayers | ||||
|     } | ||||
| } | ||||
|  | @ -30,7 +30,7 @@ export default class DetermineLayout { | |||
|     /** | ||||
|      * Gets the correct layout for this website | ||||
|      */ | ||||
|     public static async GetLayout(): Promise<LayoutConfig> { | ||||
|     public static async GetLayout(): Promise<LayoutConfig | undefined> { | ||||
|         const loadCustomThemeParam = QueryParameters.GetQueryParameter( | ||||
|             "userlayout", | ||||
|             "false", | ||||
|  |  | |||
|  | @ -1,7 +1,7 @@ | |||
| import { Utils } from "../Utils" | ||||
| 
 | ||||
| export default class Constants { | ||||
|     public static vNumber = "0.26.1" | ||||
|     public static vNumber = "0.26.2" | ||||
| 
 | ||||
|     public static ImgurApiKey = "7070e7167f0a25a" | ||||
|     public static readonly mapillary_client_token_v4 = | ||||
|  |  | |||
|  | @ -35,7 +35,7 @@ export default class AllThemesGui { | |||
|             ]) | ||||
|                 .SetClass("block m-5 lg:w-3/4 lg:ml-40") | ||||
|                 .SetStyle("pointer-events: all;") | ||||
|                 .AttachTo("topleft-tools") | ||||
|                 .AttachTo("top-left") | ||||
|         } catch (e) { | ||||
|             console.error(">>>> CRITICAL", e) | ||||
|             new FixedUiElement( | ||||
|  |  | |||
|  | @ -3,7 +3,6 @@ import Svg from "../../Svg" | |||
| import Combine from "../Base/Combine" | ||||
| import { SubtleButton } from "../Base/SubtleButton" | ||||
| import Translations from "../i18n/Translations" | ||||
| import personal from "../../assets/themes/personal/personal.json" | ||||
| import Constants from "../../Models/Constants" | ||||
| import BaseUIElement from "../BaseUIElement" | ||||
| import LayoutConfig from "../../Models/ThemeConfig/LayoutConfig" | ||||
|  | @ -382,7 +381,7 @@ export default class MoreScreen extends Combine { | |||
|                     return undefined | ||||
|                 } | ||||
|                 const button = MoreScreen.createLinkButton(state, layout)?.SetClass(buttonClass) | ||||
|                 if (layout.id === personal.id) { | ||||
|                 if (layout.id === "personal") { | ||||
|                     const element = new VariableUiElement( | ||||
|                         state.osmConnection.userDetails | ||||
|                             .map((userdetails) => userdetails.csCount) | ||||
|  |  | |||
|  | @ -37,7 +37,7 @@ export default class SelectTheme | |||
| 
 | ||||
|     constructor(params: { features: any[]; layer: LayerConfig; bbox: BBox }) { | ||||
|         const t = Translations.t.importHelper.selectTheme | ||||
|         let options: InputElement<string>[] = AllKnownLayouts.layoutsList | ||||
|         let options: InputElement<string>[] = Array.from(AllKnownLayouts.allKnownLayouts.values()) | ||||
|             .filter((th) => th.layers.some((l) => l.id === params.layer.id)) | ||||
|             .filter((th) => th.id !== "personal") | ||||
|             .map( | ||||
|  | @ -60,7 +60,7 @@ export default class SelectTheme | |||
|                 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 themeConfig = AllKnownLayouts.allKnownLayouts.get(theme) | ||||
|             const layer = themeConfig.layers.find((l) => l.id === params.layer.id) | ||||
|             return layer.presets | ||||
|         }) | ||||
|  |  | |||
|  | @ -8,17 +8,17 @@ import { Utils } from "../Utils" | |||
| import Combine from "./Base/Combine" | ||||
| import { StackedRenderingChart } from "./BigComponents/TagRenderingChart" | ||||
| import { LayerFilterPanel } from "./BigComponents/FilterView" | ||||
| import { AllKnownLayouts } from "../Customizations/AllKnownLayouts" | ||||
| import MapState from "../Logic/State/MapState" | ||||
| import BaseUIElement from "./BaseUIElement" | ||||
| import Title from "./Base/Title" | ||||
| import { FixedUiElement } from "./Base/FixedUiElement" | ||||
| import List from "./Base/List" | ||||
| 
 | ||||
| import LayoutConfig from "../Models/ThemeConfig/LayoutConfig" | ||||
| import mcChanges from "../assets/generated/themes/mapcomplete-changes.json" | ||||
| class StatisticsForOverviewFile extends Combine { | ||||
|     constructor(homeUrl: string, paths: string[]) { | ||||
|         paths = paths.filter((p) => !p.endsWith("file-overview.json")) | ||||
|         const layer = AllKnownLayouts.allKnownLayouts.get("mapcomplete-changes").layers[0] | ||||
|         const layer = new LayoutConfig(<any>mcChanges, true).layers[0] | ||||
|         const filteredLayer = MapState.InitializeFilteredLayers( | ||||
|             { id: "statistics-view", layers: [layer] }, | ||||
|             undefined | ||||
|  |  | |||
|  | @ -58,12 +58,7 @@ | |||
|     <!-- DECORATION 0 END --> | ||||
| </div> | ||||
| 
 | ||||
| <div class="z-index-above-map pointer-events-none" id="topleft-tools"> | ||||
|     <div class="p-3 flex flex-col items-end sm:items-start sm:flex-row sm:flex-wrap w-full sm:justify-between"> | ||||
|         <div class="shadow rounded-full h-min w-full overflow-hidden sm:max-w-sm pointer-events-auto" | ||||
|              id="searchbox"></div> | ||||
|         <div class="m-1 pointer-events-auto" id="userbadge"></div> | ||||
|     </div> | ||||
| <div id="top-left"> | ||||
| </div> | ||||
| 
 | ||||
| <div class="clutter absolute h-24 left-24 right-24 top-56 text-xl text-center" | ||||
|  |  | |||
|  | @ -36,7 +36,7 @@ | |||
|     "generate:service-worker": "tsc service-worker.ts --outFile public/service-worker.js && git_hash=$(git rev-parse HEAD) && sed -i \"s/GITHUB-COMMIT/$git_hash/\" public/service-worker.js", | ||||
|     "optimize-images": "cd assets/generated/ &&  find -name '*.png' -exec optipng '{}' \\; && echo 'PNGs are optimized'", | ||||
|     "generate:stats": "ts-node scripts/GenerateSeries.ts", | ||||
|     "reset:layeroverview": "echo {\\\"layers\\\":[], \\\"themes\\\":[]} > ./assets/generated/known_layers_and_themes.json && echo {\\\"layers\\\": []} > ./assets/generated/known_layers.json && rm -f ./assets/generated/layers/*.json && rm -f ./assets/generated/themes/*.json && npm run generate:layeroverview && ts-node scripts/generateLayerOverview.ts --force", | ||||
|     "reset:layeroverview": "echo {\\\"themes\\\":[]} > ./assets/generated/known_themes.json && echo {\\\"layers\\\": []} > ./assets/generated/known_layers.json && rm -f ./assets/generated/layers/*.json && rm -f ./assets/generated/themes/*.json && npm run generate:layeroverview && ts-node scripts/generateLayerOverview.ts --force", | ||||
|     "generate": "mkdir -p ./assets/generated; npm run generate:licenses; npm run generate:images; npm run generate:charging-stations; npm run generate:translations; npm run reset:layeroverview; npm run generate:service-worker", | ||||
|     "generate:charging-stations": "cd ./assets/layers/charging_station && ts-node csvToJson.ts && cd -", | ||||
|     "prepare-deploy": "npm run generate:service-worker && ./scripts/build.sh", | ||||
|  |  | |||
|  | @ -539,10 +539,7 @@ export async function main(args: string[]) { | |||
| 
 | ||||
|     const theme = AllKnownLayouts.allKnownLayouts.get(themeName) | ||||
|     if (theme === undefined) { | ||||
|         const keys = [] | ||||
|         AllKnownLayouts.allKnownLayouts.forEach((_, key) => { | ||||
|             keys.push(key) | ||||
|         }) | ||||
|         const keys = Array.from(AllKnownLayouts.allKnownLayouts.keys()) | ||||
|         console.error("The theme " + theme + " was not found; try one of ", keys) | ||||
|         return | ||||
|     } | ||||
|  |  | |||
|  | @ -24,6 +24,11 @@ import { DefaultGuiState } from "../UI/DefaultGuiState" | |||
| import fakedom from "fake-dom" | ||||
| import Hotkeys from "../UI/Base/Hotkeys" | ||||
| import { QueryParameters } from "../Logic/Web/QueryParameters" | ||||
| import Link from "../UI/Base/Link" | ||||
| import Constants from "../Models/Constants" | ||||
| import LayerConfig from "../Models/ThemeConfig/LayerConfig" | ||||
| import DependencyCalculator from "../Models/ThemeConfig/DependencyCalculator" | ||||
| import { AllSharedLayers } from "../Customizations/AllSharedLayers" | ||||
| function WriteFile( | ||||
|     filename, | ||||
|     html: BaseUIElement, | ||||
|  | @ -74,6 +79,179 @@ function WriteFile( | |||
|     writeFileSync(filename, warnAutomated + md) | ||||
| } | ||||
| 
 | ||||
| function GenerateDocumentationForTheme(theme: LayoutConfig): BaseUIElement { | ||||
|     return new Combine([ | ||||
|         new Title( | ||||
|             new Combine([ | ||||
|                 theme.title, | ||||
|                 "(", | ||||
|                 new Link(theme.id, "https://mapcomplete.osm.be/" + theme.id), | ||||
|                 ")", | ||||
|             ]), | ||||
|             2 | ||||
|         ), | ||||
|         theme.description, | ||||
|         "This theme contains the following layers:", | ||||
|         new List( | ||||
|             theme.layers | ||||
|                 .filter((l) => !l.id.startsWith("note_import_")) | ||||
|                 .map((l) => new Link(l.id, "../Layers/" + l.id + ".md")) | ||||
|         ), | ||||
|         "Available languages:", | ||||
|         new List(theme.language.filter((ln) => ln !== "_context")), | ||||
|     ]).SetClass("flex flex-col") | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * Generates the documentation for the layers overview page | ||||
|  * @constructor | ||||
|  */ | ||||
| function GenLayerOverviewText(): BaseUIElement { | ||||
|     for (const id of Constants.priviliged_layers) { | ||||
|         if (!AllSharedLayers.sharedLayers.has(id)) { | ||||
|             throw "Priviliged layer definition not found: " + id | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     const allLayers: LayerConfig[] = Array.from(AllSharedLayers.sharedLayers.values()).filter( | ||||
|         (layer) => Constants.priviliged_layers.indexOf(layer.id) < 0 | ||||
|     ) | ||||
| 
 | ||||
|     const builtinLayerIds: Set<string> = new Set<string>() | ||||
|     allLayers.forEach((l) => builtinLayerIds.add(l.id)) | ||||
| 
 | ||||
|     const themesPerLayer = new Map<string, string[]>() | ||||
| 
 | ||||
|     for (const layout of Array.from(AllKnownLayouts.allKnownLayouts.values())) { | ||||
|         for (const layer of layout.layers) { | ||||
|             if (!builtinLayerIds.has(layer.id)) { | ||||
|                 continue | ||||
|             } | ||||
|             if (!themesPerLayer.has(layer.id)) { | ||||
|                 themesPerLayer.set(layer.id, []) | ||||
|             } | ||||
|             themesPerLayer.get(layer.id).push(layout.id) | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     // Determine the cross-dependencies
 | ||||
|     const layerIsNeededBy: Map<string, string[]> = new Map<string, string[]>() | ||||
| 
 | ||||
|     for (const layer of allLayers) { | ||||
|         for (const dep of DependencyCalculator.getLayerDependencies(layer)) { | ||||
|             const dependency = dep.neededLayer | ||||
|             if (!layerIsNeededBy.has(dependency)) { | ||||
|                 layerIsNeededBy.set(dependency, []) | ||||
|             } | ||||
|             layerIsNeededBy.get(dependency).push(layer.id) | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     return new Combine([ | ||||
|         new Title("Special and other useful layers", 1), | ||||
|         "MapComplete has a few data layers available in the theme which have special properties through builtin-hooks. Furthermore, there are some normal layers (which are built from normal Theme-config files) but are so general that they get a mention here.", | ||||
|         new Title("Priviliged layers", 1), | ||||
|         new List(Constants.priviliged_layers.map((id) => "[" + id + "](#" + id + ")")), | ||||
|         ...Constants.priviliged_layers | ||||
|             .map((id) => AllSharedLayers.sharedLayers.get(id)) | ||||
|             .map((l) => | ||||
|                 l.GenerateDocumentation( | ||||
|                     themesPerLayer.get(l.id), | ||||
|                     layerIsNeededBy, | ||||
|                     DependencyCalculator.getLayerDependencies(l), | ||||
|                     Constants.added_by_default.indexOf(l.id) >= 0, | ||||
|                     Constants.no_include.indexOf(l.id) < 0 | ||||
|                 ) | ||||
|             ), | ||||
|         new Title("Normal layers", 1), | ||||
|         "The following layers are included in MapComplete:", | ||||
|         new List( | ||||
|             Array.from(AllSharedLayers.sharedLayers.keys()).map( | ||||
|                 (id) => new Link(id, "./Layers/" + id + ".md") | ||||
|             ) | ||||
|         ), | ||||
|     ]) | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * Generates documentation for the layers. | ||||
|  * Inline layers are included (if the theme is public) | ||||
|  * @param callback | ||||
|  * @constructor | ||||
|  */ | ||||
| function GenOverviewsForSingleLayer( | ||||
|     callback: (layer: LayerConfig, element: BaseUIElement, inlineSource: string) => void | ||||
| ): void { | ||||
|     const allLayers: LayerConfig[] = Array.from(AllSharedLayers.sharedLayers.values()).filter( | ||||
|         (layer) => Constants.priviliged_layers.indexOf(layer.id) < 0 | ||||
|     ) | ||||
|     const builtinLayerIds: Set<string> = new Set<string>() | ||||
|     allLayers.forEach((l) => builtinLayerIds.add(l.id)) | ||||
|     const inlineLayers = new Map<string, string>() | ||||
| 
 | ||||
|     for (const layout of Array.from(AllKnownLayouts.allKnownLayouts.values())) { | ||||
|         if (layout.hideFromOverview) { | ||||
|             continue | ||||
|         } | ||||
| 
 | ||||
|         for (const layer of layout.layers) { | ||||
|             if (Constants.priviliged_layers.indexOf(layer.id) >= 0) { | ||||
|                 continue | ||||
|             } | ||||
|             if (builtinLayerIds.has(layer.id)) { | ||||
|                 continue | ||||
|             } | ||||
|             if (layer.source.geojsonSource !== undefined) { | ||||
|                 // Not an OSM-source
 | ||||
|                 continue | ||||
|             } | ||||
|             allLayers.push(layer) | ||||
|             builtinLayerIds.add(layer.id) | ||||
|             inlineLayers.set(layer.id, layout.id) | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     const themesPerLayer = new Map<string, string[]>() | ||||
| 
 | ||||
|     for (const layout of Array.from(AllKnownLayouts.allKnownLayouts.values())) { | ||||
|         if (layout.hideFromOverview) { | ||||
|             continue | ||||
|         } | ||||
|         for (const layer of layout.layers) { | ||||
|             if (!builtinLayerIds.has(layer.id)) { | ||||
|                 // This is an inline layer
 | ||||
|                 continue | ||||
|             } | ||||
|             if (!themesPerLayer.has(layer.id)) { | ||||
|                 themesPerLayer.set(layer.id, []) | ||||
|             } | ||||
|             themesPerLayer.get(layer.id).push(layout.id) | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     // Determine the cross-dependencies
 | ||||
|     const layerIsNeededBy: Map<string, string[]> = new Map<string, string[]>() | ||||
| 
 | ||||
|     for (const layer of allLayers) { | ||||
|         for (const dep of DependencyCalculator.getLayerDependencies(layer)) { | ||||
|             const dependency = dep.neededLayer | ||||
|             if (!layerIsNeededBy.has(dependency)) { | ||||
|                 layerIsNeededBy.set(dependency, []) | ||||
|             } | ||||
|             layerIsNeededBy.get(dependency).push(layer.id) | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     allLayers.forEach((layer) => { | ||||
|         const element = layer.GenerateDocumentation( | ||||
|             themesPerLayer.get(layer.id), | ||||
|             layerIsNeededBy, | ||||
|             DependencyCalculator.getLayerDependencies(layer) | ||||
|         ) | ||||
|         callback(layer, element, inlineLayers.get(layer.id)) | ||||
|     }) | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * The wikitable is updated as some tools show an overview of apps based on the wiki. | ||||
|  */ | ||||
|  | @ -131,7 +309,7 @@ console.log("Starting documentation generation...") | |||
| ScriptUtils.fixUtils() | ||||
| generateWikipage() | ||||
| 
 | ||||
| AllKnownLayouts.GenOverviewsForSingleLayer((layer, element, inlineSource) => { | ||||
| GenOverviewsForSingleLayer((layer, element, inlineSource) => { | ||||
|     console.log("Exporting ", layer.id) | ||||
|     if (!existsSync("./Docs/Layers")) { | ||||
|         mkdirSync("./Docs/Layers") | ||||
|  | @ -144,7 +322,7 @@ AllKnownLayouts.GenOverviewsForSingleLayer((layer, element, inlineSource) => { | |||
| }) | ||||
| 
 | ||||
| Array.from(AllKnownLayouts.allKnownLayouts.values()).map((theme) => { | ||||
|     const docs = AllKnownLayouts.GenerateDocumentationForTheme(theme) | ||||
|     const docs = GenerateDocumentationForTheme(theme) | ||||
|     WriteFile( | ||||
|         "./Docs/Themes/" + theme.id + ".md", | ||||
|         docs, | ||||
|  | @ -167,9 +345,7 @@ WriteFile( | |||
| WriteFile("./Docs/SpecialInputElements.md", ValidatedTextField.HelpText(), [ | ||||
|     "UI/Input/ValidatedTextField.ts", | ||||
| ]) | ||||
| WriteFile("./Docs/BuiltinLayers.md", AllKnownLayouts.GenLayerOverviewText(), [ | ||||
|     "Customizations/AllKnownLayouts.ts", | ||||
| ]) | ||||
| WriteFile("./Docs/BuiltinLayers.md", GenLayerOverviewText(), ["Customizations/AllKnownLayouts.ts"]) | ||||
| WriteFile("./Docs/BuiltinQuestions.md", SharedTagRenderings.HelpText(), [ | ||||
|     "Customizations/SharedTagRenderings.ts", | ||||
|     "assets/tagRenderings/questions.json", | ||||
|  |  | |||
|  | @ -21,8 +21,7 @@ import { PrepareLayer } from "../Models/ThemeConfig/Conversion/PrepareLayer" | |||
| import { PrepareTheme } from "../Models/ThemeConfig/Conversion/PrepareTheme" | ||||
| import { DesugaringContext } from "../Models/ThemeConfig/Conversion/Conversion" | ||||
| import { Utils } from "../Utils" | ||||
| import { AllKnownLayouts } from "../Customizations/AllKnownLayouts" | ||||
| import { Script } from "vm" | ||||
| import { AllSharedLayers } from "../Customizations/AllSharedLayers" | ||||
| 
 | ||||
| // This scripts scans 'assets/layers/*.json' for layer definition files and 'assets/themes/*.json' for theme definition files.
 | ||||
| // It spits out an overview of those to be used to load them
 | ||||
|  | @ -259,9 +258,8 @@ class LayerOverviewUtils { | |||
|         ) | ||||
| 
 | ||||
|         writeFileSync( | ||||
|             "./assets/generated/known_layers_and_themes.json", | ||||
|             "./assets/generated/known_themes.json", | ||||
|             JSON.stringify({ | ||||
|                 layers: Array.from(sharedLayers.values()), | ||||
|                 themes: Array.from(sharedThemes.values()), | ||||
|             }) | ||||
|         ) | ||||
|  | @ -306,7 +304,7 @@ class LayerOverviewUtils { | |||
|             "GenerateLayerOverview:" | ||||
|         ) | ||||
| 
 | ||||
|         if (AllKnownLayouts.getSharedLayersConfigs().size == 0) { | ||||
|         if (AllSharedLayers.getSharedLayersConfigs().size == 0) { | ||||
|             console.error("This was a bootstrapping-run. Run generate layeroverview again!") | ||||
|         } else { | ||||
|             const green = (s) => "\x1b[92m" + s + "\x1b[0m" | ||||
|  | @ -325,7 +323,7 @@ class LayerOverviewUtils { | |||
|         const sharedTagRenderings = this.getSharedTagRenderings(doesImageExist) | ||||
|         const state: DesugaringContext = { | ||||
|             tagRenderings: sharedTagRenderings, | ||||
|             sharedLayers: AllKnownLayouts.getSharedLayersConfigs(), | ||||
|             sharedLayers: AllSharedLayers.getSharedLayersConfigs(), | ||||
|         } | ||||
|         const sharedLayers = new Map<string, LayerConfigJson>() | ||||
|         const prepLayer = new PrepareLayer(state) | ||||
|  |  | |||
|  | @ -205,7 +205,7 @@ function main() { | |||
| 
 | ||||
|     const files = [] | ||||
| 
 | ||||
|     for (const layout of AllKnownLayouts.layoutsList) { | ||||
|     for (const layout of AllKnownLayouts.allKnownLayouts.values()) { | ||||
|         if (layout.hideFromOverview) { | ||||
|             continue | ||||
|         } | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue