forked from MapComplete/MapComplete
Themes: add validation check if a mapping does not erase another mapping completely
This commit is contained in:
parent
7d43bb5983
commit
556f6d0b93
43 changed files with 5015 additions and 4778 deletions
|
|
@ -32,7 +32,6 @@
|
|||
{#each layer.tagRenderings as config (config.id)}
|
||||
{#if (config.condition?.matchesProperties($tags) ?? true) && config.metacondition?.matchesProperties({ ...$tags, ..._metatags } ?? true)}
|
||||
{#if config.IsKnown($tags)}
|
||||
{config.id}
|
||||
<TagRenderingEditable
|
||||
{tags}
|
||||
{config}
|
||||
|
|
|
|||
|
|
@ -110,10 +110,6 @@ export abstract class EditJsonState<T> {
|
|||
public getStoreFor<T>(path: ReadonlyArray<string | number>): UIEventSource<T | undefined> {
|
||||
const key = path.join(".")
|
||||
|
||||
// TODO check if this gives problems when changing the order of e.g. mappings and questions
|
||||
if (this._stores.has(key)) {
|
||||
return this._stores.get(key)
|
||||
}
|
||||
const store = new UIEventSource<any>(this.getCurrentValueFor(path))
|
||||
store.addCallback((v) => {
|
||||
this.setValueAt(path, v)
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@
|
|||
|
||||
let thenText: UIEventSource<Record<string, string>> = state.getStoreFor([...path, "then"])
|
||||
let thenTextEn = thenText .mapD(translation => typeof translation === "string" ? translation : translation["en"] )
|
||||
let editMode = Object.keys($thenText).length === 0;
|
||||
let editMode = Object.keys($thenText ?? {})?.length === 0;
|
||||
|
||||
let mappingConfigs: ConfigMeta[] = configs.filter(c => c.path[0] === "mappings")
|
||||
.map(c => <ConfigMeta>Utils.Clone(c))
|
||||
|
|
|
|||
|
|
@ -13,7 +13,8 @@ export let title: string | undefined = undefined;
|
|||
export let path: (string | number)[] = [];
|
||||
|
||||
let expertMode = state.expertMode
|
||||
let configsFiltered = $expertMode ? configs : configs.filter(schema => schema.hints?.group !== "expert")
|
||||
let configsNoHidden = configs.filter(schema => schema.hints?.group !== "hidden")
|
||||
let configsFiltered = $expertMode ? configsNoHidden : configsNoHidden.filter(schema => schema.hints?.group !== "expert")
|
||||
|
||||
</script>
|
||||
{#if configs === undefined}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@
|
|||
import SchemaBasedField from "./SchemaBasedField.svelte";
|
||||
import { TrashIcon } from "@babeard/svelte-heroicons/mini";
|
||||
import QuestionPreview from "./QuestionPreview.svelte";
|
||||
import { Utils } from "../../Utils";
|
||||
import SchemaBasedMultiType from "./SchemaBasedMultiType.svelte";
|
||||
import ShowConversionMessage from "./ShowConversionMessage.svelte";
|
||||
|
||||
|
|
@ -24,6 +23,7 @@
|
|||
article = "an";
|
||||
}
|
||||
export let path: (string | number)[] = [];
|
||||
|
||||
const isTagRenderingBlock = path.length === 1 && path[0] === "tagRenderings";
|
||||
|
||||
if (isTagRenderingBlock) {
|
||||
|
|
@ -33,37 +33,24 @@
|
|||
|
||||
const subparts: ConfigMeta = state.getSchemaStartingWith(schema.path)
|
||||
.filter(part => part.path.length - 1 === schema.path.length);
|
||||
/**
|
||||
* Store the _indices_
|
||||
*/
|
||||
export let values: UIEventSource<number[]> = new UIEventSource<number[]>([]);
|
||||
|
||||
const currentValue = <[]>state.getCurrentValueFor(path);
|
||||
if (currentValue) {
|
||||
if (!Array.isArray(currentValue)) {
|
||||
console.error("SchemaBaseArray for path", path, "expected an array as initial value, but got a", typeof currentValue, currentValue);
|
||||
} else {
|
||||
values.setData(currentValue.map((_, i) => i));
|
||||
}
|
||||
}
|
||||
let createdItems = values.data.length;
|
||||
|
||||
let messages = state.messagesFor(path)
|
||||
|
||||
|
||||
|
||||
const currentValue : UIEventSource<any[]> = state.getStoreFor(path);
|
||||
if(currentValue.data === undefined){
|
||||
currentValue.setData([])
|
||||
}
|
||||
|
||||
function createItem(valueToSet?: any) {
|
||||
values.data.push(createdItems);
|
||||
if (valueToSet) {
|
||||
state.getStoreFor([...path, createdItems]).setData(valueToSet);
|
||||
if(currentValue.data === undefined){
|
||||
currentValue.setData([])
|
||||
}
|
||||
createdItems++;
|
||||
values.ping();
|
||||
currentValue.data.push(valueToSet)
|
||||
currentValue.ping()
|
||||
|
||||
if(isTagRenderingBlock){
|
||||
if(typeof valueToSet === "string"){
|
||||
// THis is very broken state.highlightedItem.setData({path: [...path, createdItems], schema})
|
||||
}else{
|
||||
state.highlightedItem.setData({path: [...path, createdItems], schema})
|
||||
}
|
||||
state.highlightedItem.setData({path: [...path, currentValue.data.length - 1], schema})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -73,54 +60,40 @@
|
|||
for (const part of path) {
|
||||
if (toAdd[0] === part) {
|
||||
toAdd.splice(0, 1);
|
||||
}else{
|
||||
break
|
||||
}
|
||||
}
|
||||
newPath.push(...toAdd);
|
||||
console.log({newPath})
|
||||
return newPath;
|
||||
}
|
||||
|
||||
function del(i) {
|
||||
const index = i;
|
||||
console.log("Deleting", index);
|
||||
values.data.splice(index, 1);
|
||||
values.ping();
|
||||
|
||||
const store = <UIEventSource<[]>>state.getStoreFor(path);
|
||||
store.data.splice(index, 1);
|
||||
store.setData(Utils.NoNull(store.data));
|
||||
state.configuration.ping();
|
||||
}
|
||||
|
||||
function swap(indexA, indexB) {
|
||||
const valueA = values.data[indexA];
|
||||
const valueB = values.data[indexB];
|
||||
|
||||
values.data[indexA] = valueB;
|
||||
values.data[indexB] = valueA;
|
||||
values.ping();
|
||||
|
||||
const store = <UIEventSource<[]>>state.getStoreFor(path);
|
||||
const svalueA = store.data[indexA];
|
||||
const svalueB = store.data[indexB];
|
||||
store.data[indexA] = svalueB;
|
||||
store.data[indexB] = svalueA;
|
||||
store.ping();
|
||||
state.configuration.ping();
|
||||
}
|
||||
|
||||
function moveTo(currentIndex, targetIndex) {
|
||||
const direction = currentIndex > targetIndex ? -1 : +1;
|
||||
do {
|
||||
swap(currentIndex, currentIndex + direction);
|
||||
currentIndex = currentIndex + direction;
|
||||
} while (currentIndex !== targetIndex);
|
||||
}
|
||||
|
||||
function schemaForMultitype() {
|
||||
const sch = {...schema}
|
||||
sch.hints.typehint = undefined
|
||||
return sch
|
||||
}
|
||||
|
||||
|
||||
function del(i: number){
|
||||
currentValue.data.splice(i, 1)
|
||||
currentValue.ping()
|
||||
}
|
||||
|
||||
function swap(i: number, j: number) {
|
||||
const x = currentValue.data[i]
|
||||
currentValue.data[i] = currentValue.data[j]
|
||||
currentValue.data[j] = x
|
||||
currentValue.ping()
|
||||
}
|
||||
|
||||
function moveTo(source: number, target: number){
|
||||
const x = currentValue.data[source]
|
||||
currentValue.data.splice(source, 1)
|
||||
currentValue.data.splice(target, 0, x)
|
||||
currentValue.ping()
|
||||
}
|
||||
|
||||
|
||||
</script>
|
||||
|
|
@ -132,8 +105,9 @@
|
|||
{schema.description}
|
||||
</span>
|
||||
{/if}
|
||||
|
||||
{#if $values.length === 0}
|
||||
{#if $currentValue === undefined}
|
||||
No array defined
|
||||
{:else if $currentValue.length === 0}
|
||||
No values are defined
|
||||
{#if $messages.length > 0}
|
||||
{#each $messages as message}
|
||||
|
|
@ -142,9 +116,9 @@
|
|||
{/if}
|
||||
{:else if subparts.length === 0}
|
||||
<!-- We need an array of values, so we use the typehint of the _parent_ element as field -->
|
||||
{#each $values as value, i (value)}
|
||||
{#each $currentValue as value, i}
|
||||
<div class="flex w-full">
|
||||
<SchemaBasedField {state} {schema} path={[...path, value]} />
|
||||
<SchemaBasedField {state} {schema} path={[...path, i]} />
|
||||
<button class="border-black border rounded-full p-1 w-fit h-fit"
|
||||
on:click={() => {del(i)}}>
|
||||
<TrashIcon class="w-4 h-4" />
|
||||
|
|
@ -152,11 +126,10 @@
|
|||
</div>
|
||||
{/each}
|
||||
{:else}
|
||||
{#each $values as value, i (value)}
|
||||
|
||||
{#each $currentValue as value, i}
|
||||
{#if !isTagRenderingBlock}
|
||||
<div class="flex justify-between items-center">
|
||||
<h3 class="m-0">{singular} {value}</h3>
|
||||
<h3 class="m-0">{singular} {i}</h3>
|
||||
<button class="border-black border rounded-full p-1 w-fit h-fit"
|
||||
on:click={() => {del(i)}}>
|
||||
<TrashIcon class="w-4 h-4" />
|
||||
|
|
@ -165,7 +138,7 @@
|
|||
{/if}
|
||||
<div class="border border-black">
|
||||
{#if isTagRenderingBlock}
|
||||
<QuestionPreview {state} path={[...path, value]} {schema}>
|
||||
<QuestionPreview {state} path={[...path, i]} {schema}>
|
||||
<button on:click={() => {del(i)}}>
|
||||
<TrashIcon class="w-4 h-4" />
|
||||
Delete this question
|
||||
|
|
@ -180,21 +153,21 @@
|
|||
Move up
|
||||
</button>
|
||||
{/if}
|
||||
{#if i + 1 < $values.length}
|
||||
{#if i + 1 < $currentValue.length}
|
||||
<button on:click={() => {swap(i, i+1)}}>
|
||||
Move down
|
||||
</button>
|
||||
<button on:click={() => {moveTo(i, $values.length-1)}}>
|
||||
<button on:click={() => {moveTo(i, $currentValue.length-1)}}>
|
||||
Move to back
|
||||
</button>
|
||||
{/if}
|
||||
|
||||
</QuestionPreview>
|
||||
{:else if schema.hints.types}
|
||||
<SchemaBasedMultiType {state} path={fusePath(value, [])} schema={schemaForMultitype()}/>
|
||||
<SchemaBasedMultiType {state} path={fusePath(i, [])} schema={schemaForMultitype()}/>
|
||||
{:else}
|
||||
{#each subparts as subpart}
|
||||
<SchemaBasedInput {state} path={fusePath(value, subpart.path)} schema={subpart} />
|
||||
<SchemaBasedInput {state} path={fusePath(i, subpart.path)} schema={subpart} />
|
||||
{/each}
|
||||
{/if}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -17,21 +17,21 @@
|
|||
export let state: EditLayerState;
|
||||
export let path: (string | number)[] = [];
|
||||
export let schema: ConfigMeta;
|
||||
export let startInEditModeIfUnset: boolean = schema.hints && !schema.hints.ifunset
|
||||
export let startInEditModeIfUnset: boolean = schema.hints && !schema.hints.ifunset;
|
||||
let value = new UIEventSource<string | any>(undefined);
|
||||
|
||||
const isTranslation = schema.hints?.typehint === "translation" || schema.hints?.typehint === "rendered" || ConfigMetaUtils.isTranslation(schema);
|
||||
let type = schema.hints.typehint ?? "string";
|
||||
|
||||
let rendervalue = (schema.hints.inline ?? schema.path.join(".")) + (isTranslation ? " <b>{translated(value)}</b>": " <b>{value}</b>");
|
||||
|
||||
if(schema.type === "boolean"){
|
||||
rendervalue = undefined
|
||||
let rendervalue = (schema.hints.inline ?? schema.path.join(".")) + (isTranslation ? " <b>{translated(value)}</b>" : " <b>{value}</b>");
|
||||
|
||||
if (schema.type === "boolean") {
|
||||
rendervalue = undefined;
|
||||
}
|
||||
if(schema.hints.typehint === "tag" || schema.hints.typehint === "simple_tag") {
|
||||
rendervalue = "{tags()}"
|
||||
if (schema.hints.typehint === "tag" || schema.hints.typehint === "simple_tag") {
|
||||
rendervalue = "{tags()}";
|
||||
}
|
||||
|
||||
|
||||
let helperArgs = schema.hints.typehelper?.split(",");
|
||||
let inline = schema.hints.inline !== undefined;
|
||||
if (isTranslation) {
|
||||
|
|
@ -111,7 +111,7 @@
|
|||
}
|
||||
let config: TagRenderingConfig;
|
||||
let err: string = undefined;
|
||||
let messages = state.messagesFor(path)
|
||||
let messages = state.messagesFor(path);
|
||||
try {
|
||||
config = new TagRenderingConfig(configJson, "config based on " + schema.path.join("."));
|
||||
} catch (e) {
|
||||
|
|
@ -119,13 +119,13 @@
|
|||
err = path.join(".") + " " + e;
|
||||
}
|
||||
let startValue = state.getCurrentValueFor(path);
|
||||
let startInEditMode = !startValue && startInEditModeIfUnset
|
||||
let startInEditMode = !startValue && startInEditModeIfUnset;
|
||||
const tags = new UIEventSource<Record<string, string>>({ value: startValue });
|
||||
try {
|
||||
onDestroy(state.register(path, tags.map(tgs => {
|
||||
const v = tgs["value"];
|
||||
if (typeof v !== "string") {
|
||||
return { ... v };
|
||||
return { ...v };
|
||||
}
|
||||
if (schema.type === "boolan") {
|
||||
return v === "true" || v === "yes" || v === "1";
|
||||
|
|
@ -156,18 +156,21 @@
|
|||
console.error("Could not register", path, "due to", e);
|
||||
}
|
||||
</script>
|
||||
|
||||
{#if err !== undefined}
|
||||
<span class="alert">{err}</span>
|
||||
{:else}
|
||||
<div class="w-full flex flex-col">
|
||||
<TagRenderingEditable editMode={startInEditMode} {config} selectedElement={undefined} showQuestionIfUnknown={true} {state} {tags} />
|
||||
<TagRenderingEditable editMode={startInEditMode} {config} selectedElement={undefined} showQuestionIfUnknown={true}
|
||||
{state} {tags} />
|
||||
{#if $messages.length > 0}
|
||||
{#each $messages as message}
|
||||
<ShowConversionMessage {message}/>
|
||||
<ShowConversionMessage {message} />
|
||||
{/each}
|
||||
{/if}
|
||||
{#if window.location.hostname === "127.0.0.1"}
|
||||
<span class="subtle">SchemaBasedField <b>{path.join(".")}</b> <span class="cursor-pointer" on:click={() => console.log(schema)}>{schema.hints.typehint}</span></span>
|
||||
<span class="subtle" on:click={() => console.log(schema)}>SchemaBasedField <b>{path.join(".")}</b> <span class="cursor-pointer"
|
||||
on:click={() => console.log(schema)}>{schema.hints.typehint}</span> Group: {schema.hints.group}</span>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
|
|
|
|||
|
|
@ -9,17 +9,21 @@
|
|||
export let schema: ConfigMeta;
|
||||
export let state: EditLayerState;
|
||||
export let path: (string | number)[] = [];
|
||||
|
||||
let expertMode = state.expertMode;
|
||||
</script>
|
||||
{#if schema.hints?.typehint?.endsWith("[]")}
|
||||
<!-- We cheat a bit here by matching this 'magical' type... -->
|
||||
<SchemaBasedArray {path} {state} {schema} />
|
||||
{:else if schema.type === "array" && schema.hints.multianswer === "true"}
|
||||
<ArrayMultiAnswer {path} {state} {schema}/>
|
||||
{:else if schema.type === "array"}
|
||||
<SchemaBasedArray {path} {state} {schema} />
|
||||
{:else if schema.hints?.types}
|
||||
<SchemaBasedMultiType {path} {state} {schema} />
|
||||
{:else}
|
||||
<SchemaBasedField {path} {state} {schema} />
|
||||
{#if (schema.hints?.group !== "expert" || $expertMode) && schema.hints.group !== "hidden"}
|
||||
{#if schema.hints?.typehint?.endsWith("[]")}
|
||||
<!-- We cheat a bit here by matching this 'magical' type... -->
|
||||
<SchemaBasedArray {path} {state} {schema} />
|
||||
{:else if schema.type === "array" && schema.hints.multianswer === "true"}
|
||||
<ArrayMultiAnswer {path} {state} {schema} />
|
||||
{:else if schema.type === "array"}
|
||||
<SchemaBasedArray {path} {state} {schema} />
|
||||
{:else if schema.hints?.types}
|
||||
<SchemaBasedMultiType {path} {state} {schema} />
|
||||
{:else}
|
||||
<SchemaBasedField {path} {state} {schema} />
|
||||
{/if}
|
||||
{:else if window.location.hostname === "127.0.0.1"}
|
||||
<div class="subtle">Not showing SBI {schema.path.join(".")} due to group {schema.hints.group}</div>
|
||||
{/if}
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@
|
|||
// @ts-ignore
|
||||
import nmd from "nano-markdown";
|
||||
import ShowConversionMessage from "./ShowConversionMessage.svelte";
|
||||
import exp from "constants";
|
||||
|
||||
/**
|
||||
* If 'types' is defined: allow the user to pick one of the types to input.
|
||||
|
|
@ -196,7 +195,6 @@
|
|||
}));
|
||||
let messages = state.messagesFor(path);
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<div class="p-2 border-2 border-dashed border-gray-300 flex flex-col gap-y-2 m-1">
|
||||
|
|
@ -209,7 +207,7 @@
|
|||
Studio
|
||||
{:else}
|
||||
<div>
|
||||
<TagRenderingEditable {config} selectedElement={undefined} showQuestionIfUnknown={true} {state} {tags} />
|
||||
<TagRenderingEditable {config} selectedElement={undefined} showQuestionIfUnknown={!schema.hints?.ifunset} {state} {tags} />
|
||||
</div>
|
||||
|
||||
{#if chosenOption !== undefined}
|
||||
|
|
@ -217,9 +215,9 @@
|
|||
{#if $expertMode || subschema.hints?.group !== "expert"}
|
||||
<SchemaBasedInput {state} schema={subschema}
|
||||
path={[...subpath, (subschema?.path?.at(-1) ?? "???")]}></SchemaBasedInput>
|
||||
{:else if window.location.hostname === "127.0.0.1"}
|
||||
<span class="subtle">Omitted expert question {subschema.path.join(".")}</span>
|
||||
|
||||
{:else if window.location.hostname === "127.0.0.1"}
|
||||
<span class="subtle">Omitted expert question {subschema.path.join(".")}</span>
|
||||
|
||||
{/if}
|
||||
{/each}
|
||||
{:else if $messages.length > 0}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@
|
|||
* Markdown
|
||||
*/
|
||||
export let pages: string[];
|
||||
console.log("Walkthrough pages are", pages)
|
||||
|
||||
let currentPage: number = 0;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue