🚧 Allow editing of layer file in Studio

This commit is contained in:
Robin van der Linde 2024-02-13 00:52:50 +01:00
parent 2b12715f5c
commit a093d52647
Signed by untrusted user: Robin-van-der-Linde
GPG key ID: 53956B3252478F0D
4 changed files with 125 additions and 17 deletions

View file

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