Studio: Fix some usability errors
This commit is contained in:
parent
80b7a038cf
commit
2f8cb91d31
9 changed files with 43 additions and 30 deletions
|
@ -28,7 +28,8 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if $badge}
|
{#if $badge}
|
||||||
{#if !ignoreLoading && $loadingStatus === "loading"}
|
<slot/>
|
||||||
|
<!-- {#if !ignoreLoading && $loadingStatus === "loading"}
|
||||||
<slot name="loading">
|
<slot name="loading">
|
||||||
<Loading />
|
<Loading />
|
||||||
</slot>
|
</slot>
|
||||||
|
@ -41,5 +42,5 @@
|
||||||
<slot />
|
<slot />
|
||||||
{:else if $loadingStatus === "not-attempted"}
|
{:else if $loadingStatus === "not-attempted"}
|
||||||
<slot name="not-logged-in" />
|
<slot name="not-logged-in" />
|
||||||
{/if}
|
{/if} -->
|
||||||
{/if}
|
{/if}
|
||||||
|
|
|
@ -88,7 +88,7 @@ export class LoginToggle extends VariableUiElement {
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
[state.featureSwitchUserbadge, state.osmConnection?.apiIsOnline]
|
[state.featureSwitchUserbadge, state.osmConnection?.apiIsOnline]
|
||||||
) ?? new ImmutableStore(el) //
|
) ?? new ImmutableStore(el)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
export let tags: UIEventSource<Record<string, string>>
|
export let tags: UIEventSource<Record<string, string>>
|
||||||
export let selectedElement: Feature | undefined
|
export let selectedElement: Feature | undefined
|
||||||
export let state: SpecialVisualizationState
|
export let state: SpecialVisualizationState
|
||||||
export let layer: LayerConfig
|
export let layer: LayerConfig = undefined
|
||||||
|
|
||||||
export let editingEnabled : Store<boolean> | undefined = state?.featureSwitchUserbadge
|
export let editingEnabled : Store<boolean> | undefined = state?.featureSwitchUserbadge
|
||||||
|
|
||||||
|
|
|
@ -986,6 +986,9 @@ export default class SpecialVisualizations {
|
||||||
constr: (state, tagsSource) =>
|
constr: (state, tagsSource) =>
|
||||||
new VariableUiElement(
|
new VariableUiElement(
|
||||||
tagsSource.map((tags) => {
|
tagsSource.map((tags) => {
|
||||||
|
if (state.layout === undefined) {
|
||||||
|
return "<feature title>"
|
||||||
|
}
|
||||||
const layer = state.layout.getMatchingLayer(tags)
|
const layer = state.layout.getMatchingLayer(tags)
|
||||||
const title = layer?.title?.GetRenderValue(tags)
|
const title = layer?.title?.GetRenderValue(tags)
|
||||||
if (title === undefined) {
|
if (title === undefined) {
|
||||||
|
@ -1335,10 +1338,10 @@ export default class SpecialVisualizations {
|
||||||
tagSource.map((tags) => {
|
tagSource.map((tags) => {
|
||||||
const v = tags[argument[0] ?? "value"]
|
const v = tags[argument[0] ?? "value"]
|
||||||
try {
|
try {
|
||||||
const tr = JSON.parse(v)
|
const tr = typeof v === "string" ? JSON.parse(v) : v
|
||||||
return new Translation(tr).SetClass("font-bold")
|
return new Translation(tr).SetClass("font-bold")
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return v
|
return JSON.stringify(v)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
|
|
@ -15,6 +15,7 @@ import { AllSharedLayers } from "../../Customizations/AllSharedLayers"
|
||||||
import { QuestionableTagRenderingConfigJson } from "../../Models/ThemeConfig/Json/QuestionableTagRenderingConfigJson"
|
import { QuestionableTagRenderingConfigJson } from "../../Models/ThemeConfig/Json/QuestionableTagRenderingConfigJson"
|
||||||
import { TagUtils } from "../../Logic/Tags/TagUtils"
|
import { TagUtils } from "../../Logic/Tags/TagUtils"
|
||||||
import StudioServer from "./StudioServer"
|
import StudioServer from "./StudioServer"
|
||||||
|
import { Utils } from "../../Utils"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sends changes back to the server
|
* Sends changes back to the server
|
||||||
|
@ -72,9 +73,9 @@ export default class EditLayerState {
|
||||||
}
|
}
|
||||||
this.messages = this.configuration.mapD((config) => {
|
this.messages = this.configuration.mapD((config) => {
|
||||||
const context = ConversionContext.construct([], ["prepare"])
|
const context = ConversionContext.construct([], ["prepare"])
|
||||||
|
const trs = Utils.NoNull(config.tagRenderings ?? [])
|
||||||
for (let i = 0; i < (config.tagRenderings ?? []).length; i++) {
|
for (let i = 0; i < trs.length; i++) {
|
||||||
const tr = config.tagRenderings[i]
|
const tr = trs[i]
|
||||||
if (typeof tr === "string") {
|
if (typeof tr === "string") {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -116,11 +117,19 @@ export default class EditLayerState {
|
||||||
return entry
|
return entry
|
||||||
}
|
}
|
||||||
|
|
||||||
public getStoreFor(path: ReadonlyArray<string | number>): UIEventSource<any | undefined> {
|
private readonly _stores = new Map<string, UIEventSource<any>>()
|
||||||
|
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))
|
const store = new UIEventSource<any>(this.getCurrentValueFor(path))
|
||||||
store.addCallback((v) => {
|
store.addCallback((v) => {
|
||||||
this.setValueAt(path, v)
|
this.setValueAt(path, v)
|
||||||
})
|
})
|
||||||
|
this._stores.set(key, store)
|
||||||
return store
|
return store
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -170,19 +179,24 @@ export default class EditLayerState {
|
||||||
|
|
||||||
public setValueAt(path: ReadonlyArray<string | number>, v: any) {
|
public setValueAt(path: ReadonlyArray<string | number>, v: any) {
|
||||||
let entry = this.configuration.data
|
let entry = this.configuration.data
|
||||||
|
const isUndefined =
|
||||||
|
v !== undefined &&
|
||||||
|
v !== null &&
|
||||||
|
v !== "" &&
|
||||||
|
!(typeof v === "object" && Object.keys({}).length === 0)
|
||||||
|
|
||||||
for (let i = 0; i < path.length - 1; i++) {
|
for (let i = 0; i < path.length - 1; i++) {
|
||||||
const breadcrumb = path[i]
|
const breadcrumb = path[i]
|
||||||
if (entry[breadcrumb] === undefined) {
|
if (entry[breadcrumb] === undefined) {
|
||||||
entry[breadcrumb] = typeof path[i + 1] === "number" ? [] : {}
|
entry[breadcrumb] = typeof path[i + 1] === "number" ? [] : {}
|
||||||
}
|
}
|
||||||
entry = entry[breadcrumb]
|
entry = entry[breadcrumb]
|
||||||
|
if (entry === undefined && isUndefined) {
|
||||||
|
// Nothing to do anymore: we cannot traverse the object, but don't have to set something anyway
|
||||||
|
return
|
||||||
}
|
}
|
||||||
if (
|
}
|
||||||
v !== undefined &&
|
if (isUndefined) {
|
||||||
v !== null &&
|
|
||||||
v !== "" &&
|
|
||||||
!(typeof v === "object" && Object.keys({}).length === 0)
|
|
||||||
) {
|
|
||||||
entry[path.at(-1)] = v
|
entry[path.at(-1)] = v
|
||||||
} else if (entry) {
|
} else if (entry) {
|
||||||
delete entry[path.at(-1)]
|
delete entry[path.at(-1)]
|
||||||
|
|
|
@ -29,7 +29,7 @@
|
||||||
|
|
||||||
const configJson: QuestionableTagRenderingConfigJson = {
|
const configJson: QuestionableTagRenderingConfigJson = {
|
||||||
id: path.join("_"),
|
id: path.join("_"),
|
||||||
render: schema.type === "boolean" ? undefined : ((schema.hints.inline ?? schema.path.at(-1) )+ ": <b>{translated(value)}</b>"),
|
render: schema.type === "boolean" ? undefined : ((schema.hints.inline ?? schema.path.at(-1) )+ ": translated value: <b>{translated(value)}</b>"),
|
||||||
question: schema.hints.question,
|
question: schema.hints.question,
|
||||||
questionHint: nmd(schema.description),
|
questionHint: nmd(schema.description),
|
||||||
freeform: schema.type === "boolean" ? undefined : {
|
freeform: schema.type === "boolean" ? undefined : {
|
||||||
|
@ -100,7 +100,9 @@
|
||||||
try {
|
try {
|
||||||
onDestroy(state.register(path, tags.map(tgs => {
|
onDestroy(state.register(path, tags.map(tgs => {
|
||||||
const v = tgs["value"];
|
const v = tgs["value"];
|
||||||
|
if(v !== ""){
|
||||||
console.log("Registering",path,"setting value to", v)
|
console.log("Registering",path,"setting value to", v)
|
||||||
|
}
|
||||||
if(typeof v !== "string"){
|
if(typeof v !== "string"){
|
||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
|
|
|
@ -113,7 +113,6 @@
|
||||||
|
|
||||||
for (const requiredAttribute of type.required) {
|
for (const requiredAttribute of type.required) {
|
||||||
if (existingValue[requiredAttribute] === undefined) {
|
if (existingValue[requiredAttribute] === undefined) {
|
||||||
console.log(path.join("."), " does not have required field", requiredAttribute, " so it cannot be type ", type);
|
|
||||||
// The 'existingValue' does _not_ have this required attribute, so it cannot be of this type
|
// The 'existingValue' does _not_ have this required attribute, so it cannot be of this type
|
||||||
continue outer;
|
continue outer;
|
||||||
}
|
}
|
||||||
|
@ -128,7 +127,6 @@
|
||||||
}
|
}
|
||||||
possibleTypes.sort((a, b) => b.optionalMatches - a.optionalMatches);
|
possibleTypes.sort((a, b) => b.optionalMatches - a.optionalMatches);
|
||||||
possibleTypes.sort((a, b) => b.matchingPropertiesCount - a.matchingPropertiesCount);
|
possibleTypes.sort((a, b) => b.matchingPropertiesCount - a.matchingPropertiesCount);
|
||||||
console.log("Possible types are", possibleTypes)
|
|
||||||
if (possibleTypes.length > 0) {
|
if (possibleTypes.length > 0) {
|
||||||
chosenOption = possibleTypes[0].index
|
chosenOption = possibleTypes[0].index
|
||||||
tags.setData({ chosen_type_index: "" + chosenOption});
|
tags.setData({ chosen_type_index: "" + chosenOption});
|
||||||
|
@ -157,27 +155,23 @@
|
||||||
let subSchemas: ConfigMeta[] = [];
|
let subSchemas: ConfigMeta[] = [];
|
||||||
|
|
||||||
let subpath = path;
|
let subpath = path;
|
||||||
console.log("Initial chosen option for",path.join("."),"is", chosenOption);
|
const store = state.getStoreFor(path)
|
||||||
onDestroy(tags.addCallbackAndRun(tags => {
|
onDestroy(tags.addCallbackAndRun(tags => {
|
||||||
if (tags["value"] !== undefined && tags["value"] !== "") {
|
if (tags["value"] !== undefined && tags["value"] !== "") {
|
||||||
chosenOption = undefined;
|
chosenOption = undefined;
|
||||||
console.log("Resetting chosenOption as `value` is present in the tags:", tags["value"])
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const oldOption = chosenOption;
|
const oldOption = chosenOption;
|
||||||
console.log("Updating chosenOption based on", tags, oldOption)
|
|
||||||
chosenOption = tags["chosen_type_index"] ? Number(tags["chosen_type_index"]) : defaultOption;
|
chosenOption = tags["chosen_type_index"] ? Number(tags["chosen_type_index"]) : defaultOption;
|
||||||
const type = schema.type[chosenOption];
|
const type = schema.type[chosenOption];
|
||||||
if (chosenOption !== oldOption) {
|
if (chosenOption !== oldOption) {
|
||||||
// Reset the values beneath
|
// Reset the values beneath
|
||||||
subSchemas = [];
|
subSchemas = [];
|
||||||
const o = state.getCurrentValueFor(path) ?? {};
|
const o = state.getCurrentValueFor(path) ?? {};
|
||||||
console.log({ o });
|
|
||||||
for (const key of type?.required ?? []) {
|
for (const key of type?.required ?? []) {
|
||||||
console.log(key);
|
|
||||||
o[key] ??= {};
|
o[key] ??= {};
|
||||||
}
|
}
|
||||||
state.setValueAt(path, o);
|
store.setData(o)
|
||||||
}
|
}
|
||||||
if (!type) {
|
if (!type) {
|
||||||
return;
|
return;
|
||||||
|
@ -187,7 +181,6 @@
|
||||||
if (type["$ref"] === "#/definitions/Record<string,string>") {
|
if (type["$ref"] === "#/definitions/Record<string,string>") {
|
||||||
// The subtype is a translation object
|
// The subtype is a translation object
|
||||||
const schema = state.getTranslationAt(cleanPath);
|
const schema = state.getTranslationAt(cleanPath);
|
||||||
console.log("Got a translation,", schema);
|
|
||||||
subSchemas.push(schema);
|
subSchemas.push(schema);
|
||||||
subpath = path.slice(0, path.length - 2);
|
subpath = path.slice(0, path.length - 2);
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -44,9 +44,9 @@ const configBuiltin = new TagRenderingConfig(<QuestionableTagRenderingConfigJson
|
||||||
|
|
||||||
|
|
||||||
const tags = new UIEventSource({ value });
|
const tags = new UIEventSource({ value });
|
||||||
|
const store = state.getStoreFor(path)
|
||||||
tags.addCallbackAndRunD(tgs => {
|
tags.addCallbackAndRunD(tgs => {
|
||||||
state.setValueAt(path, tgs["value"]);
|
store.setData(tgs["value"])
|
||||||
});
|
});
|
||||||
|
|
||||||
let mappings: UIEventSource<MappingConfigJson[]> = state.getStoreFor([...path, "mappings"]);
|
let mappings: UIEventSource<MappingConfigJson[]> = state.getStoreFor([...path, "mappings"]);
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
import layerSchemaRaw from "../../src/assets/schemas/layerconfigmeta.json";
|
import layerSchemaRaw from "../../src/assets/schemas/layerconfigmeta.json";
|
||||||
import If from "./Base/If.svelte";
|
import If from "./Base/If.svelte";
|
||||||
|
|
||||||
export let studioUrl = /* "https://studio.mapcomplete.org"; /*/ "http://127.0.0.1:1235"; //*/
|
export let studioUrl = window.location.hostname === "127.0.0.1" ? "http://127.0.0.1:1235" : "https://studio.mapcomplete.org";
|
||||||
const studio = new StudioServer(studioUrl);
|
const studio = new StudioServer(studioUrl);
|
||||||
let layersWithErr = UIEventSource.FromPromiseWithErr(studio.fetchLayerOverview());
|
let layersWithErr = UIEventSource.FromPromiseWithErr(studio.fetchLayerOverview());
|
||||||
let layers = layersWithErr.mapD(l => l.success);
|
let layers = layersWithErr.mapD(l => l.success);
|
||||||
|
|
Loading…
Reference in a new issue