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
				
			
		|  | @ -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