Studo: WIP

This commit is contained in:
Pieter Vander Vennet 2023-09-15 01:16:33 +02:00
parent 7ebb3d721c
commit 338599454c
30 changed files with 42794 additions and 749 deletions

View file

@ -2,7 +2,7 @@
import { UIEventSource } from "../../../Logic/UIEventSource";
import LanguageUtils from "../../../Utils/LanguageUtils";
import { onDestroy } from "svelte";
import { createEventDispatcher, onDestroy } from "svelte";
import ValidatedInput from "../ValidatedInput.svelte";
export let value: UIEventSource<string> = new UIEventSource<string>("");
@ -18,6 +18,7 @@
const allLanguages: string[] = LanguageUtils.usedLanguagesSorted;
let currentLang = new UIEventSource("en");
const currentVal = new UIEventSource<string>("");
let dispatch = createEventDispatcher<{ submit }>()
function update() {
const v = currentVal.data;
@ -49,5 +50,5 @@
</option>
{/each}
</select>
<ValidatedInput type="string" value={currentVal} />
<ValidatedInput type="string" value={currentVal} on:submit={() => dispatch("submit")} />
</div>

View file

@ -4,30 +4,59 @@
* Note that all values are stringified
*/
import { UIEventSource } from "../../Logic/UIEventSource"
import type { ValidatorType } from "./Validators"
import InputHelpers from "./InputHelpers"
import ToSvelte from "../Base/ToSvelte.svelte"
import type { Feature } from "geojson"
import BaseUIElement from "../BaseUIElement"
import { VariableUiElement } from "../Base/VariableUIElement"
import { UIEventSource } from "../../Logic/UIEventSource";
import type { ValidatorType } from "./Validators";
import InputHelpers from "./InputHelpers";
import ToSvelte from "../Base/ToSvelte.svelte";
import type { Feature } from "geojson";
import BaseUIElement from "../BaseUIElement";
import { VariableUiElement } from "../Base/VariableUIElement";
import { createEventDispatcher } from "svelte";
import ImageHelper from "./Helpers/ImageHelper.svelte";
import TranslationInput from "./Helpers/TranslationInput.svelte";
import TagInput from "./Helpers/TagInput.svelte";
import SimpleTagInput from "./Helpers/SimpleTagInput.svelte";
import DirectionInput from "./Helpers/DirectionInput.svelte";
import DateInput from "./Helpers/DateInput.svelte";
import ColorInput from "./Helpers/ColorInput.svelte";
export let type: ValidatorType
export let value: UIEventSource<string>
export let type: ValidatorType;
export let value: UIEventSource<string>;
export let feature: Feature
export let args: (string | number | boolean)[] = undefined
export let feature: Feature;
export let args: (string | number | boolean)[] = undefined;
let properties = { feature, args: args ?? [] }
let construct = new UIEventSource<(value, extraProperties) => BaseUIElement>(undefined)
let properties = { feature, args: args ?? [] };
let construct = new UIEventSource<(value, extraProperties) => BaseUIElement>(undefined);
$: {
construct.setData(InputHelpers.AvailableInputHelpers[type])
const helper = InputHelpers.AvailableInputHelpers[type];
construct.setData(helper);
}
let dispatch = createEventDispatcher<{ selected, submit }>();
</script>
{#if construct !== undefined}
<ToSvelte
construct={() =>
{#if type === "translation" }
<TranslationInput {value} on:submit={() => dispatch("submit")} />
{:else if type === "direction"}
<DirectionInput {value} mapProperties={InputHelpers.constructMapProperties(properties)} />
{:else if type === "date"}
<DateInput { value } />
{:else if type === "color"}
<ColorInput { value } />
{:else if type === "image"}
<ImageHelper { value } />
{:else if type === "tag"}
<TagInput { value } />
{:else if type === "simple_tag"}
<SimpleTagInput { value } />
{:else if $construct !== undefined}
{#if isBaseUIElement}
<ToSvelte
construct={() =>
new VariableUiElement(construct.mapD((construct) => construct(value, properties)))}
/>
/>
{/if}
{/if}

View file

@ -1,10 +1,7 @@
import { ValidatorType } from "./Validators"
import { UIEventSource } from "../../Logic/UIEventSource"
import SvelteUIElement from "../Base/SvelteUIElement"
import DirectionInput from "./Helpers/DirectionInput.svelte"
import { MapProperties } from "../../Models/MapProperties"
import DateInput from "./Helpers/DateInput.svelte"
import ColorInput from "./Helpers/ColorInput.svelte"
import BaseUIElement from "../BaseUIElement"
import OpeningHoursInput from "../OpeningHours/OpeningHoursInput"
import WikidataSearchBox from "../Wikipedia/WikidataSearchBox"
@ -13,10 +10,6 @@ import { Utils } from "../../Utils"
import Locale from "../i18n/Locale"
import { Feature } from "geojson"
import { GeoOperations } from "../../Logic/GeoOperations"
import ImageHelper from "./Helpers/ImageHelper.svelte"
import TranslationInput from "./Helpers/TranslationInput.svelte"
import TagInput from "./Helpers/TagInput.svelte"
import SimpleTagInput from "./Helpers/SimpleTagInput.svelte"
export interface InputHelperProperties {
/**
@ -39,6 +32,9 @@ export interface InputHelperProperties {
}
export default class InputHelpers {
/**
* @deprecated
*/
public static readonly AvailableInputHelpers: Readonly<
Partial<
Record<
@ -50,30 +46,21 @@ export default class InputHelpers {
>
>
> = {
direction: (value, properties) =>
new SvelteUIElement(DirectionInput, {
value,
mapProperties: InputHelpers.constructMapProperties(properties),
}),
date: (value) => new SvelteUIElement(DateInput, { value }),
color: (value) => new SvelteUIElement(ColorInput, { value }),
// TODO: remake in svelte,move selection logic to 'inputHelper.svelte'
opening_hours: (value) => new OpeningHoursInput(value),
wikidata: InputHelpers.constructWikidataHelper,
image: (value) => new SvelteUIElement(ImageHelper, { value }),
translation: (value) => new SvelteUIElement(TranslationInput, { value }),
tag: (value) => new SvelteUIElement(TagInput, { value }),
simple_tag: (value) => new SvelteUIElement(SimpleTagInput, { value }),
} as const
public static hideInputField: string[] = ["translation", "simple_tag", "tag"]
// noinspection JSUnusedLocalSymbols
/**
* Constructs a mapProperties-object for the given properties.
* Assumes that the first helper-args contains the desired zoom-level
* @param properties
* @private
*/
private static constructMapProperties(
public static constructMapProperties(
properties: InputHelperProperties
): Partial<MapProperties> {
let location = properties?.mapProperties?.location

View file

@ -110,7 +110,7 @@
placeholder={_placeholder}></textarea>
</form>
{:else}
<form class="inline-flex" on:submit={() => dispatch("submit")}>
<form class="inline-flex" on:submit|preventDefault={() => dispatch("submit")}>
<input
bind:this={htmlElem}
bind:value={$_value}

View file

@ -66,5 +66,5 @@
/>
{/if}
<InputHelper args={config.freeform.helperArgs} {feature} type={config.freeform.type} {value} />
<InputHelper args={config.freeform.helperArgs} {feature} type={config.freeform.type} {value} on:submit={() => dispatch("submit")} />
</div>

View file

@ -1,52 +1,52 @@
<script lang="ts">
import {ImmutableStore, Store, UIEventSource} from "../../../Logic/UIEventSource"
import type { SpecialVisualizationState } from "../../SpecialVisualization"
import Tr from "../../Base/Tr.svelte"
import type { Feature } from "geojson"
import type { Mapping } from "../../../Models/ThemeConfig/TagRenderingConfig"
import TagRenderingConfig from "../../../Models/ThemeConfig/TagRenderingConfig"
import { TagsFilter } from "../../../Logic/Tags/TagsFilter"
import FreeformInput from "./FreeformInput.svelte"
import Translations from "../../i18n/Translations.js"
import ChangeTagAction from "../../../Logic/Osm/Actions/ChangeTagAction"
import { createEventDispatcher, onDestroy } from "svelte"
import LayerConfig from "../../../Models/ThemeConfig/LayerConfig"
import SpecialTranslation from "./SpecialTranslation.svelte"
import TagHint from "../TagHint.svelte"
import LoginToggle from "../../Base/LoginToggle.svelte"
import SubtleButton from "../../Base/SubtleButton.svelte"
import Loading from "../../Base/Loading.svelte"
import TagRenderingMappingInput from "./TagRenderingMappingInput.svelte"
import { Translation } from "../../i18n/Translation"
import Constants from "../../../Models/Constants"
import { Unit } from "../../../Models/Unit"
import UserRelatedState from "../../../Logic/State/UserRelatedState"
import { twJoin } from "tailwind-merge"
import { ImmutableStore, UIEventSource } from "../../../Logic/UIEventSource";
import type { SpecialVisualizationState } from "../../SpecialVisualization";
import Tr from "../../Base/Tr.svelte";
import type { Feature } from "geojson";
import type { Mapping } from "../../../Models/ThemeConfig/TagRenderingConfig";
import TagRenderingConfig from "../../../Models/ThemeConfig/TagRenderingConfig";
import { TagsFilter } from "../../../Logic/Tags/TagsFilter";
import FreeformInput from "./FreeformInput.svelte";
import Translations from "../../i18n/Translations.js";
import ChangeTagAction from "../../../Logic/Osm/Actions/ChangeTagAction";
import { createEventDispatcher, onDestroy } from "svelte";
import LayerConfig from "../../../Models/ThemeConfig/LayerConfig";
import SpecialTranslation from "./SpecialTranslation.svelte";
import TagHint from "../TagHint.svelte";
import LoginToggle from "../../Base/LoginToggle.svelte";
import SubtleButton from "../../Base/SubtleButton.svelte";
import Loading from "../../Base/Loading.svelte";
import TagRenderingMappingInput from "./TagRenderingMappingInput.svelte";
import { Translation } from "../../i18n/Translation";
import Constants from "../../../Models/Constants";
import { Unit } from "../../../Models/Unit";
import UserRelatedState from "../../../Logic/State/UserRelatedState";
import { twJoin } from "tailwind-merge";
export let config: TagRenderingConfig
export let tags: UIEventSource<Record<string, string>>
export let selectedElement: Feature
export let state: SpecialVisualizationState
export let layer: LayerConfig | undefined
export let config: TagRenderingConfig;
export let tags: UIEventSource<Record<string, string>>;
export let selectedElement: Feature;
export let state: SpecialVisualizationState;
export let layer: LayerConfig | undefined;
let feedback: UIEventSource<Translation> = new UIEventSource<Translation>(undefined)
let feedback: UIEventSource<Translation> = new UIEventSource<Translation>(undefined);
let unit: Unit = layer?.units?.find((unit) => unit.appliesToKeys.has(config.freeform?.key))
let unit: Unit = layer?.units?.find((unit) => unit.appliesToKeys.has(config.freeform?.key));
// Will be bound if a freeform is available
let freeformInput = new UIEventSource<string>(tags?.[config.freeform?.key])
let selectedMapping: number = undefined
let checkedMappings: boolean[]
let freeformInput = new UIEventSource<string>(tags?.[config.freeform?.key]);
let selectedMapping: number = undefined;
let checkedMappings: boolean[];
$: {
let tgs = $tags
let tgs = $tags;
mappings = config.mappings?.filter((m) => {
if (typeof m.hideInAnswer === "boolean") {
return !m.hideInAnswer
return !m.hideInAnswer;
}
return !m.hideInAnswer.matchesProperties(tgs)
})
return !m.hideInAnswer.matchesProperties(tgs);
});
// We received a new config -> reinit
unit = layer?.units?.find((unit) => unit.appliesToKeys.has(config.freeform?.key))
unit = layer?.units?.find((unit) => unit.appliesToKeys.has(config.freeform?.key));
if (
config.mappings?.length > 0 &&
@ -54,23 +54,23 @@
) {
checkedMappings = [
...config.mappings.map((_) => false),
false /*One element extra in case a freeform value is added*/,
]
false /*One element extra in case a freeform value is added*/
];
}
if (config.freeform?.key) {
if (!config.multiAnswer) {
// Somehow, setting multianswer freeform values is broken if this is not set
freeformInput.setData(tgs[config.freeform.key])
freeformInput.setData(tgs[config.freeform.key]);
}
} else {
freeformInput.setData(undefined)
freeformInput.setData(undefined);
}
feedback.setData(undefined)
feedback.setData(undefined);
}
export let selectedTags: TagsFilter = undefined
export let selectedTags: TagsFilter = undefined;
let mappings: Mapping[] = config?.mappings
let searchTerm: UIEventSource<string> = new UIEventSource("")
let mappings: Mapping[] = config?.mappings;
let searchTerm: UIEventSource<string> = new UIEventSource("");
$: {
try {
@ -79,10 +79,10 @@
selectedMapping,
checkedMappings,
tags.data
)
);
} catch (e) {
console.error("Could not calculate changeSpecification:", e)
selectedTags = undefined
console.error("Could not calculate changeSpecification:", e);
selectedTags = undefined;
}
}
@ -91,53 +91,53 @@
config: TagRenderingConfig
applied: TagsFilter
}
}>()
}>();
function onSave() {
if (selectedTags === undefined) {
return
return;
}
if (layer === undefined || layer?.source === null) {
/**
* This is a special, priviliged layer.
* We simply apply the tags onto the records
*/
const kv = selectedTags.asChange(tags.data)
const kv = selectedTags.asChange(tags.data);
for (const { k, v } of kv) {
if (v === undefined) {
delete tags.data[k]
delete tags.data[k];
} else {
tags.data[k] = v
tags.data[k] = v;
}
}
tags.ping()
return
tags.ping();
return;
}
dispatch("saved", { config, applied: selectedTags })
dispatch("saved", { config, applied: selectedTags });
const change = new ChangeTagAction(tags.data.id, selectedTags, tags.data, {
theme: state.layout.id,
changeType: "answer",
})
freeformInput.setData(undefined)
selectedMapping = undefined
selectedTags = undefined
changeType: "answer"
});
freeformInput.setData(undefined);
selectedMapping = undefined;
selectedTags = undefined;
change
.CreateChangeDescriptions()
.then((changes) => state.changes.applyChanges(changes))
.catch(console.error)
.catch(console.error);
}
let featureSwitchIsTesting = state.featureSwitchIsTesting ?? new ImmutableStore(false)
let featureSwitchIsDebugging = state.featureSwitches?.featureSwitchIsDebugging ?? new ImmutableStore(false)
let showTags = state.userRelatedState?.showTags ?? new ImmutableStore(undefined)
let numberOfCs = state.osmConnection.userDetails.data.csCount
let featureSwitchIsTesting = state.featureSwitchIsTesting ?? new ImmutableStore(false);
let featureSwitchIsDebugging = state.featureSwitches?.featureSwitchIsDebugging ?? new ImmutableStore(false);
let showTags = state.userRelatedState?.showTags ?? new ImmutableStore(undefined);
let numberOfCs = state.osmConnection.userDetails.data.csCount;
onDestroy(
state.osmConnection?.userDetails?.addCallbackAndRun((ud) => {
numberOfCs = ud.csCount
numberOfCs = ud.csCount;
})
)
);
</script>
{#if config.question !== undefined}
@ -218,6 +218,7 @@
value={freeformInput}
on:selected={() => (selectedMapping = config.mappings?.length)}
on:submit={onSave}
submit={onSave}
/>
</label>
{/if}

View file

@ -1,69 +1,75 @@
<script lang="ts">
import EditLayerState from "./EditLayerState";
import layerSchemaRaw from "../../assets/schemas/layerconfigmeta.json"
import Region from "./Region.svelte";
import TabbedGroup from "../Base/TabbedGroup.svelte";
import {UIEventSource} from "../../Logic/UIEventSource";
import type {ConfigMeta} from "./configMeta";
import {Utils} from "../../Utils";
import EditLayerState, { LayerStateSender } from "./EditLayerState";
import layerSchemaRaw from "../../assets/schemas/layerconfigmeta.json";
import Region from "./Region.svelte";
import TabbedGroup from "../Base/TabbedGroup.svelte";
import { Store, UIEventSource } from "../../Logic/UIEventSource";
import type { ConfigMeta } from "./configMeta";
import { Utils } from "../../Utils";
import drinking_water from "../../../assets/layers/drinking_water/drinking_water.json"
const layerSchema: ConfigMeta[] = <any>layerSchemaRaw;
let state = new EditLayerState(layerSchema);
state.configuration.setData({});
const configuration = state.configuration;
new LayerStateSender("http://localhost:1235", state);
/**
* Blacklist of regions for the general area tab
* These are regions which are handled by a different tab
*/
const regionBlacklist = ["hidden", undefined, "infobox", "tagrenderings", "maprendering", "editing", "title"];
const allNames = Utils.Dedup(layerSchema.map(meta => meta.hints.group));
const layerSchema: ConfigMeta[] = <any> layerSchemaRaw
let state = new EditLayerState(layerSchema)
state.configuration.setData(drinking_water)
/**
* Blacklist for the general area tab
*/
const regionBlacklist = ["hidden",undefined,"infobox", "tagrenderings","maprendering", "editing", "title"]
const allNames = Utils.Dedup(layerSchema.map(meta => meta.hints.group))
const perRegion: Record<string, ConfigMeta[]> = {};
for (const region of allNames) {
perRegion[region] = layerSchema.filter(meta => meta.hints.group === region);
}
const perRegion: Record<string, ConfigMeta[]> = {}
for (const region of allNames) {
perRegion[region] = layerSchema.filter(meta => meta.hints.group === region)
const baselayerRegions: string[] = ["Basic", "presets", "filters", "advanced", "expert"];
for (const baselayerRegion of baselayerRegions) {
if (perRegion[baselayerRegion] === undefined) {
console.error("BaseLayerRegions in editLayer: no items have group '" + baselayerRegion + "\"");
}
const baselayerRegions: string[] = ["Basic", "presets","filters","advanced","expert"]
for (const baselayerRegion of baselayerRegions) {
if(perRegion[baselayerRegion] === undefined){
console.error("BaseLayerRegions in editLayer: no items have group '"+baselayerRegion+'"')
}
}
const leftoverRegions : string[] = allNames.filter(r => regionBlacklist.indexOf(r) <0 && baselayerRegions.indexOf(r) <0 )
}
const leftoverRegions: string[] = allNames.filter(r => regionBlacklist.indexOf(r) < 0 && baselayerRegions.indexOf(r) < 0);
const title: Store<string> = state.getStoreFor(["id"]);
</script>
<h3>Edit layer</h3>
<h3>Editing layer {$title}</h3>
<h4>Leftover regions</h4>
{leftoverRegions.join("; ")}
<div class="m4">
{allNames}
<TabbedGroup tab={new UIEventSource(1)}>
<TabbedGroup tab={new UIEventSource(2)}>
<div slot="title0">General properties</div>
<div class="flex flex-col" slot="content0">
{#each baselayerRegions as region}
<Region {state} configs={perRegion[region]} title={region}/>
{/each}
{#each leftoverRegions as region}
<Region {state} configs={perRegion[region]} title={region}/>
{/each}
{#each baselayerRegions as region}
<Region {state} configs={perRegion[region]} title={region} />
{/each}
{#each leftoverRegions as region}
<Region {state} configs={perRegion[region]} title={region} />
{/each}
</div>
<div slot="title1">Information panel (questions and answers)</div>
<div slot="content1">
<Region {state} configs={perRegion["tagrenderings"]} title="Popup contents">
<div slot="description">
The bulk of the popup content
</div>
</Region>
<Region {state} configs={perRegion["title"]} title="Popup title"/>
<Region {state} configs={perRegion["editing"]} title="Other editing elements"/>
<Region configs={perRegion["title"]} {state} title="Popup title" />
<Region configs={perRegion["tagrenderings"]} {state} title="Popup contents"/>
<Region configs={perRegion["editing"]} {state} title="Other editing elements" />
</div>
<div slot="title2">Rendering on the map</div>
<div slot="content2">
TODO: rendering on the map
<Region configs={perRegion["maprendering"]} {state} />
</div>
</TabbedGroup>
<div slot="title3">Configuration file</div>
<div slot="content3">
<div>
Below, you'll find the raw configuration file in `.json`-format.
This is mostly for debugging purposes
</div>
<div class="literal-code">
{JSON.stringify($configuration, null, " ")}
</div>
</div>
</TabbedGroup>
</div>

View file

@ -2,6 +2,30 @@ import { OsmConnection } from "../../Logic/Osm/OsmConnection"
import { ConfigMeta } from "./configMeta"
import { Store, UIEventSource } from "../../Logic/UIEventSource"
import { LayerConfigJson } from "../../Models/ThemeConfig/Json/LayerConfigJson"
import { QueryParameters } from "../../Logic/Web/QueryParameters"
/**
* Sends changes back to the server
*/
export class LayerStateSender {
constructor(serverLocation: string, layerState: EditLayerState) {
layerState.configuration.addCallback(async (config) => {
// console.log("Current config is", Utils.Clone(config))
const id = config.id
if (id === undefined) {
console.log("No id found in layer, not updating")
return
}
const response = await fetch(`${serverLocation}/layers/${id}/${id}.json`, {
method: "POST",
headers: {
"Content-Type": "application/json;charset=utf-8",
},
body: JSON.stringify(config, null, " "),
})
})
}
}
export default class EditLayerState {
public readonly osmConnection: OsmConnection
@ -15,13 +39,17 @@ export default class EditLayerState {
constructor(schema: ConfigMeta[]) {
this.schema = schema
this.osmConnection = new OsmConnection({})
this.osmConnection = new OsmConnection({
oauth_token: QueryParameters.GetQueryParameter(
"oauth_token",
undefined,
"Used to complete the login"
),
})
this.featureSwitches = {
featureSwitchIsDebugging: new UIEventSource<boolean>(true),
}
this.configuration.addCallback((config) => {
// console.log("Current config is", Utils.Clone(config))
})
console.log("Configuration store:", this.configuration)
}
public getCurrentValueFor(path: ReadonlyArray<string | number>): any | undefined {
@ -78,12 +106,17 @@ export default class EditLayerState {
description: origConfig.description ?? "A translatable object",
}
}
public getSchema(path: string[]): ConfigMeta[] {
return this.schema.filter(
const schemas = this.schema.filter(
(sch) =>
sch !== undefined &&
!path.some((part, i) => !(sch.path.length == path.length && sch.path[i] === part))
)
if (schemas.length == 0) {
console.warn("No schemas found for path", path.join("."))
}
return schemas
}
public setValueAt(path: ReadonlyArray<string | number>, v: any) {

View file

@ -13,7 +13,11 @@ export let title: string | undefined = undefined;
export let path: (string | number)[] = [];
</script>
{#if title}
{#if configs === undefined}
Bug: 'Region' received 'undefined'
{:else if configs.length === 0}
Bug: Region received empty list as configuration
{:else if title}
<div class="w-full flex flex-col">
<h3>{title}</h3>
<div class="pl-2 border border-black flex flex-col gap-y-1 w-full">
@ -24,6 +28,9 @@ export let path: (string | number)[] = [];
</div>
</div>
{:else}
<div class="literal-code">
{JSON.stringify(configs, null, " ")}
</div>
<div class="pl-2 flex flex-col gap-y-1 w-full">
{#each configs as config}
<SchemaBasedInput {state} path={path.concat(config.path)} schema={config} />

View file

@ -121,7 +121,7 @@
<div class="flex">
<button on:click={() => createItem()}>Add {article} {singular}</button>
{#if path.length === 1 && path[0] === "tagRenderings"}
<button on:click={() => {createItem();}}>Add a builtin tagRendering</button>
<button on:click={() => {createItem("images");}}>Add a builtin tagRendering</button>
{/if}
<slot name="extra-button" />
</div>

View file

@ -11,21 +11,21 @@
import EditLayerState from "./EditLayerState";
import { onDestroy } from "svelte";
import type { JsonSchemaType } from "./jsonSchema";
import { ConfigMetaUtils } from "./configMeta.ts"
export let state: EditLayerState
export let path: (string | number)[] = []
export let schema: ConfigMeta
let value = new UIEventSource<string>(undefined)
const isTranslation = schema.hints.typehint === "translation" || schema.hints.typehint === "rendered" || ConfigMetaUtils.isTranslation(schema)
let type = schema.hints.typehint ?? "string"
if(type === "rendered"){
if(isTranslation){
type = "translation"
}
if(type.endsWith("[]")){
type = type.substring(0, type.length - 2)
}
const isTranslation =schema.hints.typehint === "translation" || schema.hints.typehint === "rendered"
const configJson: QuestionableTagRenderingConfigJson = {
id: path.join("_"),

View file

@ -5,7 +5,7 @@
import SchemaBasedArray from "./SchemaBasedArray.svelte";
import SchemaBasedMultiType from "./SchemaBasedMultiType.svelte";
import SchemaBasedTranslationInput from "./SchemaBasedTranslationInput.svelte";
import { ConfigMetaUtils } from "./configMeta.ts"
export let schema: ConfigMeta;
export let state: EditLayerState;
export let path: (string | number)[] = [];
@ -16,8 +16,6 @@
<SchemaBasedArray {path} {state} {schema} />
{:else if schema.type === "array"}
<SchemaBasedArray {path} {state} {schema} />
{:else if schema.type === "translation"}
<SchemaBasedTranslationInput {path} {state} {schema} />
{:else if schema.hints.types}
<SchemaBasedMultiType {path} {state} {schema} />
{:else}

View file

@ -45,12 +45,12 @@
configJson.mappings.unshift(
{
if: "direct=true",
then: "Yes " + (schema.hints.iftrue ?? ""),
then: (schema.hints.iftrue ?? "Yes"),
addExtraTags: ["value="]
},
{
if: "direct=false",
then: "No " + (schema.hints.iffalse ?? ""),
then: (schema.hints.iffalse ?? "No"),
addExtraTags: ["value="]
}
);
@ -95,7 +95,6 @@
}
possibleTypes.sort((a, b) => b.optionalMatches - a.optionalMatches);
possibleTypes.sort((a, b) => b.matchingPropertiesCount - a.matchingPropertiesCount);
console.log(">>> possible types", possibleTypes)
if (possibleTypes.length > 0) {
tags.setData({ value: "" + possibleTypes[0].index });
}
@ -122,13 +121,19 @@
onDestroy(tags.addCallbackAndRun(tags => {
const oldOption = chosenOption;
chosenOption = tags["value"] ? Number(tags["value"]) : defaultOption;
const type = schema.type[chosenOption];
console.log("Subtype is", type, {chosenOption, oldOption, schema});
if (chosenOption !== oldOption) {
// Reset the values beneath
subSchemas = [];
state.setValueAt(path, undefined);
const o = state.getCurrentValueFor(path) ?? {}
console.log({o})
for(const key of type?.required ?? []){
console.log(key)
o[key] ??= {}
}
state.setValueAt(path, o);
}
const type = schema.type[chosenOption];
console.log("Subtype is", type);
if (!type) {
return;
}
@ -148,6 +153,7 @@
for (const crumble of Object.keys(type.properties)) {
subSchemas.push(...(state.getSchema([...cleanPath, crumble])));
}
console.log("Got subschemas for", path, ":", subSchemas)
}));

View file

@ -22,3 +22,22 @@ export interface ConfigMeta {
required: boolean
description: string
}
export class ConfigMetaUtils {
static isTranslation(configMeta: ConfigMeta) {
/* {
"$ref": "#/definitions/Record<string,string>"
},
{
"type": "string"
}*/
if (!configMeta.type) {
return false
}
if (Array.isArray(configMeta.type)) {
return configMeta.type.some((t) => t["$ref"] === "#/definitions/Record<string,string>")
} else {
return configMeta.type["$ref"] === "#/definitions/Record<string,string>"
}
}
}