forked from MapComplete/MapComplete
		
	🚧 Allow editing of layer file in Studio
This commit is contained in:
		
							parent
							
								
									2b12715f5c
								
							
						
					
					
						commit
						a093d52647
					
				
					 4 changed files with 125 additions and 17 deletions
				
			
		
							
								
								
									
										49
									
								
								package-lock.json
									
										
									
										generated
									
									
									
								
							
							
						
						
									
										49
									
								
								package-lock.json
									
										
									
										generated
									
									
									
								
							|  | @ -1,12 +1,12 @@ | |||
| { | ||||
|   "name": "mapcomplete", | ||||
|   "version": "0.37.0", | ||||
|   "version": "0.37.2", | ||||
|   "lockfileVersion": 2, | ||||
|   "requires": true, | ||||
|   "packages": { | ||||
|     "": { | ||||
|       "name": "mapcomplete", | ||||
|       "version": "0.37.0", | ||||
|       "version": "0.37.2", | ||||
|       "license": "GPL-3.0-or-later", | ||||
|       "dependencies": { | ||||
|         "@rgossiaux/svelte-headlessui": "^1.0.2", | ||||
|  | @ -44,6 +44,7 @@ | |||
|         "lz-string": "^1.4.4", | ||||
|         "mangrove-reviews-typescript": "^1.1.0", | ||||
|         "maplibre-gl": "^3.5.0", | ||||
|         "monaco-editor": "^0.46.0", | ||||
|         "nano-markdown": "^1.2.2", | ||||
|         "opening_hours": "^3.6.0", | ||||
|         "osm-auth": "^2.2.0", | ||||
|  | @ -68,6 +69,7 @@ | |||
|         "@babeard/svelte-heroicons": "^2.0.0-rc.0", | ||||
|         "@babel/polyfill": "^7.10.4", | ||||
|         "@babel/preset-env": "7.13.8", | ||||
|         "@monaco-editor/loader": "^1.4.0", | ||||
|         "@parcel/service-worker": "^2.6.0", | ||||
|         "@rollup/plugin-json": "^6.0.0", | ||||
|         "@sveltejs/vite-plugin-svelte": "^2.0.2", | ||||
|  | @ -2355,6 +2357,18 @@ | |||
|         "gl-style-validate": "dist/gl-style-validate.mjs" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@monaco-editor/loader": { | ||||
|       "version": "1.4.0", | ||||
|       "resolved": "https://registry.npmjs.org/@monaco-editor/loader/-/loader-1.4.0.tgz", | ||||
|       "integrity": "sha512-00ioBig0x642hytVspPl7DbQyaSWRaolYie/UFNjoTdvoKPzo6xrXLhTk9ixgIKcLH5b5vDOjVNiGyY+uDCUlg==", | ||||
|       "dev": true, | ||||
|       "dependencies": { | ||||
|         "state-local": "^1.0.6" | ||||
|       }, | ||||
|       "peerDependencies": { | ||||
|         "monaco-editor": ">= 0.21.0 < 1" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@nodelib/fs.scandir": { | ||||
|       "version": "2.1.5", | ||||
|       "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", | ||||
|  | @ -9377,6 +9391,11 @@ | |||
|         "url": "https://github.com/chalk/supports-color?sponsor=1" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/monaco-editor": { | ||||
|       "version": "0.46.0", | ||||
|       "resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.46.0.tgz", | ||||
|       "integrity": "sha512-ADwtLIIww+9FKybWscd7OCfm9odsFYHImBRI1v9AviGce55QY8raT+9ihH8jX/E/e6QVSGM+pKj4jSUSRmALNQ==" | ||||
|     }, | ||||
|     "node_modules/monotone-convex-hull-2d": { | ||||
|       "version": "1.0.1", | ||||
|       "resolved": "https://registry.npmjs.org/monotone-convex-hull-2d/-/monotone-convex-hull-2d-1.0.1.tgz", | ||||
|  | @ -11499,6 +11518,12 @@ | |||
|         "node": ">=0.1.14" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/state-local": { | ||||
|       "version": "1.0.7", | ||||
|       "resolved": "https://registry.npmjs.org/state-local/-/state-local-1.0.7.tgz", | ||||
|       "integrity": "sha512-HTEHMNieakEnoe33shBYcZ7NX83ACUjCu8c40iOGEZsngj9zRnkqS9j1pqQPXwobB0ZcVTk27REb7COQ0UR59w==", | ||||
|       "dev": true | ||||
|     }, | ||||
|     "node_modules/std-env": { | ||||
|       "version": "3.3.2", | ||||
|       "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.3.2.tgz", | ||||
|  | @ -15357,6 +15382,15 @@ | |||
|         "sort-object": "^3.0.3" | ||||
|       } | ||||
|     }, | ||||
|     "@monaco-editor/loader": { | ||||
|       "version": "1.4.0", | ||||
|       "resolved": "https://registry.npmjs.org/@monaco-editor/loader/-/loader-1.4.0.tgz", | ||||
|       "integrity": "sha512-00ioBig0x642hytVspPl7DbQyaSWRaolYie/UFNjoTdvoKPzo6xrXLhTk9ixgIKcLH5b5vDOjVNiGyY+uDCUlg==", | ||||
|       "dev": true, | ||||
|       "requires": { | ||||
|         "state-local": "^1.0.6" | ||||
|       } | ||||
|     }, | ||||
|     "@nodelib/fs.scandir": { | ||||
|       "version": "2.1.5", | ||||
|       "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", | ||||
|  | @ -20688,6 +20722,11 @@ | |||
|         } | ||||
|       } | ||||
|     }, | ||||
|     "monaco-editor": { | ||||
|       "version": "0.46.0", | ||||
|       "resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.46.0.tgz", | ||||
|       "integrity": "sha512-ADwtLIIww+9FKybWscd7OCfm9odsFYHImBRI1v9AviGce55QY8raT+9ihH8jX/E/e6QVSGM+pKj4jSUSRmALNQ==" | ||||
|     }, | ||||
|     "monotone-convex-hull-2d": { | ||||
|       "version": "1.0.1", | ||||
|       "resolved": "https://registry.npmjs.org/monotone-convex-hull-2d/-/monotone-convex-hull-2d-1.0.1.tgz", | ||||
|  | @ -22222,6 +22261,12 @@ | |||
|       "integrity": "sha512-EeNzTVfj+1In7aSLPKDD03F/ly4RxEuF/EX0YcOG0cKoPXs+SLZxDawQbexQDBzwROs4VKLWTOaZQlZkGBFEIQ==", | ||||
|       "optional": true | ||||
|     }, | ||||
|     "state-local": { | ||||
|       "version": "1.0.7", | ||||
|       "resolved": "https://registry.npmjs.org/state-local/-/state-local-1.0.7.tgz", | ||||
|       "integrity": "sha512-HTEHMNieakEnoe33shBYcZ7NX83ACUjCu8c40iOGEZsngj9zRnkqS9j1pqQPXwobB0ZcVTk27REb7COQ0UR59w==", | ||||
|       "dev": true | ||||
|     }, | ||||
|     "std-env": { | ||||
|       "version": "3.3.2", | ||||
|       "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.3.2.tgz", | ||||
|  |  | |||
|  | @ -142,6 +142,7 @@ | |||
|     "lz-string": "^1.4.4", | ||||
|     "mangrove-reviews-typescript": "^1.1.0", | ||||
|     "maplibre-gl": "^3.5.0", | ||||
|     "monaco-editor": "^0.46.0", | ||||
|     "nano-markdown": "^1.2.2", | ||||
|     "opening_hours": "^3.6.0", | ||||
|     "osm-auth": "^2.2.0", | ||||
|  | @ -166,6 +167,7 @@ | |||
|     "@babeard/svelte-heroicons": "^2.0.0-rc.0", | ||||
|     "@babel/polyfill": "^7.10.4", | ||||
|     "@babel/preset-env": "7.13.8", | ||||
|     "@monaco-editor/loader": "^1.4.0", | ||||
|     "@parcel/service-worker": "^2.6.0", | ||||
|     "@rollup/plugin-json": "^6.0.0", | ||||
|     "@sveltejs/vite-plugin-svelte": "^2.0.2", | ||||
|  |  | |||
|  | @ -28,6 +28,9 @@ | |||
|       window.setTimeout(() => tabElements[tab.data].click(), 50) | ||||
|     } | ||||
|   } | ||||
|   export function getTab() { | ||||
|     return tab | ||||
|   } | ||||
| </script> | ||||
| 
 | ||||
| <div class="tabbedgroup flex h-full w-full"> | ||||
|  |  | |||
|  | @ -17,14 +17,24 @@ | |||
|   import AllTagsPanel from "../Popup/AllTagsPanel.svelte" | ||||
|   import QuestionPreview from "./QuestionPreview.svelte" | ||||
|   import ShowConversionMessages from "./ShowConversionMessages.svelte" | ||||
|   import loader from "@monaco-editor/loader" | ||||
|   import type * as Monaco from "monaco-editor/esm/vs/editor/editor.api" | ||||
|   import { onMount } from "svelte" | ||||
|   import layerSchemaJSON from "../../../Docs/Schemas/LayerConfigJson.schema.json" | ||||
| 
 | ||||
|   const layerSchema: ConfigMeta[] = <any>layerSchemaRaw | ||||
| 
 | ||||
|   export let state: EditLayerState | ||||
| 
 | ||||
|   // Throw error if we don't have a state | ||||
|   if (!state) { | ||||
|     throw new Error("No state provided") | ||||
|   } | ||||
| 
 | ||||
|   export let backToStudio: () => void | ||||
|   let messages = state.messages | ||||
|   let hasErrors = messages.mapD( | ||||
|     (m: ConversionMessage[]) => m.filter((m) => m.level === "error").length, | ||||
|     (m: ConversionMessage[]) => m.filter((m) => m.level === "error").length | ||||
|   ) | ||||
|   const configuration = state.configuration | ||||
| 
 | ||||
|  | @ -78,6 +88,61 @@ | |||
|     state.delete() | ||||
|     backToStudio() | ||||
|   } | ||||
| 
 | ||||
|   let tabbedGroup: TabbedGroup | ||||
|   let openTab: UIEventSource<number> = new UIEventSource<number>(0) | ||||
| 
 | ||||
|   let monaco: typeof Monaco | ||||
|   let editorContainer: HTMLDivElement | ||||
|   let layerEditor: Monaco.editor.IStandaloneCodeEditor | ||||
|   let model: Monaco.editor.ITextModel | ||||
| 
 | ||||
|   onMount(async () => { | ||||
|     openTab = tabbedGroup.getTab() | ||||
| 
 | ||||
|     const monacoEditor = await import("monaco-editor") | ||||
|     loader.config({ monaco: monacoEditor.default }) | ||||
| 
 | ||||
|     monaco = await loader.init() | ||||
| 
 | ||||
|     // Prepare the Monaco editor (language settings) | ||||
|     // A.K.A. The schemas for the Monaco editor | ||||
|     monaco.languages.json.jsonDefaults.setDiagnosticsOptions({ | ||||
|       validate: true, | ||||
|       schemas: [ | ||||
|         { | ||||
|           uri: "https://mapcomplete.org/schemas/layerconfig.json", | ||||
|           fileMatch: ["layer.json"], | ||||
|           schema: layerSchemaJSON, | ||||
|         }, | ||||
|       ], | ||||
|     }) | ||||
|     let modelUri = monaco.Uri.parse("inmemory://inmemory/layer.json") | ||||
|     model = monaco.editor.createModel( | ||||
|       JSON.stringify(state.configuration.data, null, "  "), | ||||
|       "json", | ||||
|       modelUri | ||||
|     ) | ||||
| 
 | ||||
|     layerEditor = monaco.editor.create(editorContainer, { | ||||
|       model: model, | ||||
|       automaticLayout: true, | ||||
|     }) | ||||
| 
 | ||||
|     // When the editor is changed, update the configuration, but only if the user hasn't typed for 500ms and the JSON is valid | ||||
|     let timeout: number | ||||
|     layerEditor.onDidChangeModelContent(() => { | ||||
|       clearTimeout(timeout) | ||||
|       timeout = setTimeout(() => { | ||||
|         try { | ||||
|           const newConfig = JSON.parse(layerEditor.getValue()) | ||||
|           state.configuration.setData(newConfig) | ||||
|         } catch (e) { | ||||
|           console.error(e) | ||||
|         } | ||||
|       }, 500) | ||||
|     }) | ||||
|   }) | ||||
| </script> | ||||
| 
 | ||||
| <div class="flex h-screen flex-col"> | ||||
|  | @ -102,10 +167,7 @@ | |||
|           rel="noopener" | ||||
|         > | ||||
|           <div class="flex flex-col"> | ||||
| 
 | ||||
|             <b> | ||||
|               Test in safe mode | ||||
|             </b> | ||||
|             <b>Test in safe mode</b> | ||||
|             <div>No changes are recoded to OSM</div> | ||||
|           </div> | ||||
|           <ChevronRightIcon class="h-6 w-6 shrink-0" /> | ||||
|  | @ -129,7 +191,7 @@ | |||
|     {/each} | ||||
|   {:else} | ||||
|     <div class="m4 h-full overflow-y-auto"> | ||||
|       <TabbedGroup> | ||||
|       <TabbedGroup bind:this={tabbedGroup}> | ||||
|         <div slot="title0" class="flex"> | ||||
|           General properties | ||||
|           <ErrorIndicatorForRegion firstPaths={firstPathsFor("Basic")} {state} /> | ||||
|  | @ -190,11 +252,9 @@ | |||
|         <div slot="content5"> | ||||
|           <div> | ||||
|             Below, you'll find the raw configuration file in `.json`-format. This is mostly for | ||||
|             debugging purposes | ||||
|           </div> | ||||
|           <div class="literal-code"> | ||||
|             <FromHtml src={JSON.stringify($configuration, null, "  ").replaceAll("\n", "</br>")} /> | ||||
|             debugging purposes, but you can also edit the file directly if you want. | ||||
|           </div> | ||||
|           <div class="literal-code h-64 w-full" bind:this={editorContainer} /> | ||||
| 
 | ||||
|           <ShowConversionMessages messages={$messages} /> | ||||
|           <div> | ||||
|  | @ -209,11 +269,9 @@ | |||
|     {#if $highlightedItem !== undefined} | ||||
|       <FloatOver on:close={() => highlightedItem.setData(undefined)}> | ||||
|         <div> | ||||
|           <TagRenderingInput | ||||
|             path={$highlightedItem.path} | ||||
|             {state} | ||||
|             schema={$highlightedItem.schema} | ||||
|           /> | ||||
|           <TagRenderingInput path={$highlightedItem.path} {state} /> | ||||
|           <!--  | ||||
|             schema={$highlightedItem.schema} --> | ||||
|         </div> | ||||
|       </FloatOver> | ||||
|     {/if} | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue