forked from MapComplete/MapComplete
		
	Studio: UX improvements after usertest
This commit is contained in:
		
							parent
							
								
									44c1548e89
								
							
						
					
					
						commit
						a9bfe4f37b
					
				
					 11 changed files with 173 additions and 122 deletions
				
			
		| 
						 | 
					@ -18,5 +18,6 @@ The participant has extensive OpenStreetMap-knowledge but only used MapComplete
 | 
				
			||||||
- [x] The 'try it out'-button should be a 'next'-button
 | 
					- [x] The 'try it out'-button should be a 'next'-button
 | 
				
			||||||
- [x] Entering an incorrect ID and pressing enter still takes you to the layer editor with an incorrect ID 
 | 
					- [x] Entering an incorrect ID and pressing enter still takes you to the layer editor with an incorrect ID 
 | 
				
			||||||
- [x] A name and description are obligatory to use the layer as single-layer-theme; but those error messages are unclear. 
 | 
					- [x] A name and description are obligatory to use the layer as single-layer-theme; but those error messages are unclear. 
 | 
				
			||||||
- [ ] 
 | 
					- [x] This user had an expression with two tags in an AND. There was some confusion if the taginfo-count gave the totals for the tags individually or for the entire expression.
 | 
				
			||||||
- [ ] 
 | 
					        Fix: play with padding and wording
 | 
				
			||||||
 | 
					- [x] BUG: having a complex expression for tags (e.g. with `and: [key=value, key0=value0]`) fails as the JSON would be stringified
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1109,7 +1109,7 @@ export class ValidateLayer extends Conversion<
 | 
				
			||||||
                    const doMatch = baseTags.matchesProperties(properties)
 | 
					                    const doMatch = baseTags.matchesProperties(properties)
 | 
				
			||||||
                    if (!doMatch) {
 | 
					                    if (!doMatch) {
 | 
				
			||||||
                        context
 | 
					                        context
 | 
				
			||||||
                            .enters("presets", i)
 | 
					                            .enters("presets", i, "tags")
 | 
				
			||||||
                            .err(
 | 
					                            .err(
 | 
				
			||||||
                                "This preset does not match the required tags of this layer. This implies that a newly added point will not show up.\n    A newly created point will have properties: " +
 | 
					                                "This preset does not match the required tags of this layer. This implies that a newly added point will not show up.\n    A newly created point will have properties: " +
 | 
				
			||||||
                                    JSON.stringify(properties) +
 | 
					                                    JSON.stringify(properties) +
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -5,7 +5,7 @@ import { UIEventSource } from "../../../Logic/UIEventSource";
 | 
				
			||||||
import type { TagConfigJson } from "../../../Models/ThemeConfig/Json/TagConfigJson";
 | 
					import type { TagConfigJson } from "../../../Models/ThemeConfig/Json/TagConfigJson";
 | 
				
			||||||
import FullTagInput from "../../Studio/TagInput/FullTagInput.svelte";
 | 
					import FullTagInput from "../../Studio/TagInput/FullTagInput.svelte";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export let value: UIEventSource<undefined | string>;
 | 
					export let value: UIEventSource<TagConfigJson>;
 | 
				
			||||||
export let uploadableOnly: boolean;
 | 
					export let uploadableOnly: boolean;
 | 
				
			||||||
export let overpassSupportNeeded: boolean;
 | 
					export let overpassSupportNeeded: boolean;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -14,18 +14,7 @@ export let overpassSupportNeeded: boolean;
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
export let silent: boolean = false;
 | 
					export let silent: boolean = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
let tag: UIEventSource<string | TagConfigJson> = value.sync(s => {
 | 
					let tag: UIEventSource<string | TagConfigJson> = value
 | 
				
			||||||
  try {
 | 
					 | 
				
			||||||
    return JSON.parse(s);
 | 
					 | 
				
			||||||
  } catch (e) {
 | 
					 | 
				
			||||||
    return s;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}, [], t => {
 | 
					 | 
				
			||||||
  if(typeof t === "string"){
 | 
					 | 
				
			||||||
    return t
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  return JSON.stringify(t);
 | 
					 | 
				
			||||||
});
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
</script>
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -20,7 +20,7 @@
 | 
				
			||||||
  import OpeningHoursInput from "./Helpers/OpeningHoursInput.svelte";
 | 
					  import OpeningHoursInput from "./Helpers/OpeningHoursInput.svelte";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  export let type: ValidatorType;
 | 
					  export let type: ValidatorType;
 | 
				
			||||||
  export let value: UIEventSource<string>;
 | 
					  export let value: UIEventSource<string | object>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  export let feature: Feature;
 | 
					  export let feature: Feature;
 | 
				
			||||||
  export let args: (string | number | boolean)[] = undefined;
 | 
					  export let args: (string | number | boolean)[] = undefined;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -74,7 +74,12 @@
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        feedback?.setData(undefined)
 | 
					        feedback?.setData(undefined)
 | 
				
			||||||
        value.setData(v + (selectedUnit.data ?? ""))
 | 
					        if(selectedUnit.data){
 | 
				
			||||||
 | 
					            value.setData(v + selectedUnit.data)
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					        }else{
 | 
				
			||||||
 | 
					            value.setData(v)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -238,7 +238,7 @@
 | 
				
			||||||
              bind:group={selectedMapping}
 | 
					              bind:group={selectedMapping}
 | 
				
			||||||
              name={"mappings-radio-" + config.id}
 | 
					              name={"mappings-radio-" + config.id}
 | 
				
			||||||
              value={i}
 | 
					              value={i}
 | 
				
			||||||
              on:keypress={e => {console.log(e) ; if(e.key === "Enter") onSave()}}
 | 
					              on:keypress={e => {if(e.key === "Enter") onSave()}}
 | 
				
			||||||
            />
 | 
					            />
 | 
				
			||||||
          </TagRenderingMappingInput>
 | 
					          </TagRenderingMappingInput>
 | 
				
			||||||
        {/each}
 | 
					        {/each}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -75,6 +75,7 @@ import AllReviews from "./Reviews/AllReviews.svelte"
 | 
				
			||||||
import StarsBarIcon from "./Reviews/StarsBarIcon.svelte"
 | 
					import StarsBarIcon from "./Reviews/StarsBarIcon.svelte"
 | 
				
			||||||
import ReviewForm from "./Reviews/ReviewForm.svelte"
 | 
					import ReviewForm from "./Reviews/ReviewForm.svelte"
 | 
				
			||||||
import Questionbox from "./Popup/TagRendering/Questionbox.svelte"
 | 
					import Questionbox from "./Popup/TagRendering/Questionbox.svelte"
 | 
				
			||||||
 | 
					import { TagUtils } from "../Logic/Tags/TagUtils"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class NearbyImageVis implements SpecialVisualization {
 | 
					class NearbyImageVis implements SpecialVisualization {
 | 
				
			||||||
    // Class must be in SpecialVisualisations due to weird cyclical import that breaks the tests
 | 
					    // Class must be in SpecialVisualisations due to weird cyclical import that breaks the tests
 | 
				
			||||||
| 
						 | 
					@ -1400,6 +1401,49 @@ export default class SpecialVisualizations {
 | 
				
			||||||
                    return new FixedUiElement("{" + args[0] + "}")
 | 
					                    return new FixedUiElement("{" + args[0] + "}")
 | 
				
			||||||
                },
 | 
					                },
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                funcName: "tags",
 | 
				
			||||||
 | 
					                docs: "Shows a (json of) tags in a human-readable way + links to the wiki",
 | 
				
			||||||
 | 
					                needsUrls: [],
 | 
				
			||||||
 | 
					                args: [
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        name: "key",
 | 
				
			||||||
 | 
					                        defaultValue: "value",
 | 
				
			||||||
 | 
					                        doc: "The key to look for the tags",
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                ],
 | 
				
			||||||
 | 
					                constr(
 | 
				
			||||||
 | 
					                    state: SpecialVisualizationState,
 | 
				
			||||||
 | 
					                    tagSource: UIEventSource<Record<string, string>>,
 | 
				
			||||||
 | 
					                    argument: string[],
 | 
				
			||||||
 | 
					                    feature: Feature,
 | 
				
			||||||
 | 
					                    layer: LayerConfig
 | 
				
			||||||
 | 
					                ): BaseUIElement {
 | 
				
			||||||
 | 
					                    const key = argument[0] ?? "value"
 | 
				
			||||||
 | 
					                    return new VariableUiElement(
 | 
				
			||||||
 | 
					                        tagSource.map((tags) => {
 | 
				
			||||||
 | 
					                            let value = tags[key]
 | 
				
			||||||
 | 
					                            if (!value) {
 | 
				
			||||||
 | 
					                                return new FixedUiElement("No tags found").SetClass("font-bold")
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                            if (typeof value === "string" && value.startsWith("{")) {
 | 
				
			||||||
 | 
					                                value = JSON.parse(value)
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                            try {
 | 
				
			||||||
 | 
					                                const parsed = TagUtils.Tag(value)
 | 
				
			||||||
 | 
					                                return parsed.asHumanString(true, false, {})
 | 
				
			||||||
 | 
					                            } catch (e) {
 | 
				
			||||||
 | 
					                                return new FixedUiElement(
 | 
				
			||||||
 | 
					                                    "Could not parse this tag: " +
 | 
				
			||||||
 | 
					                                        JSON.stringify(value) +
 | 
				
			||||||
 | 
					                                        " due to " +
 | 
				
			||||||
 | 
					                                        e
 | 
				
			||||||
 | 
					                                ).SetClass("alert")
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                        })
 | 
				
			||||||
 | 
					                    )
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
        ]
 | 
					        ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        specialVisualizations.push(new AutoApplyButton(specialVisualizations))
 | 
					        specialVisualizations.push(new AutoApplyButton(specialVisualizations))
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -21,7 +21,15 @@
 | 
				
			||||||
  const isTranslation = schema.hints.typehint === "translation" || schema.hints.typehint === "rendered" || ConfigMetaUtils.isTranslation(schema);
 | 
					  const isTranslation = schema.hints.typehint === "translation" || schema.hints.typehint === "rendered" || ConfigMetaUtils.isTranslation(schema);
 | 
				
			||||||
  let type = schema.hints.typehint ?? "string";
 | 
					  let type = schema.hints.typehint ?? "string";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  let rendervalue = schema.type === "boolean" ? undefined : ((schema.hints.inline ?? schema.path.join(".")) + " <b>{translated(value)}</b>");
 | 
					  let rendervalue = ((schema.hints.inline ?? schema.path.join(".")) + " <b>{translated(value)}</b>");
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  if(schema.type === "boolean"){
 | 
				
			||||||
 | 
					    rendervalue = undefined
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  if(schema.hints.typehint === "tag") {
 | 
				
			||||||
 | 
					    rendervalue = "{tags()}"
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
  let helperArgs = schema.hints.typehelper?.split(",");
 | 
					  let helperArgs = schema.hints.typehelper?.split(",");
 | 
				
			||||||
  let inline = schema.hints.inline !== undefined;
 | 
					  let inline = schema.hints.inline !== undefined;
 | 
				
			||||||
  if (isTranslation) {
 | 
					  if (isTranslation) {
 | 
				
			||||||
| 
						 | 
					@ -165,7 +173,7 @@
 | 
				
			||||||
      {/each}
 | 
					      {/each}
 | 
				
			||||||
    {/if}
 | 
					    {/if}
 | 
				
			||||||
    {#if window.location.hostname === "127.0.0.1"}
 | 
					    {#if window.location.hostname === "127.0.0.1"}
 | 
				
			||||||
      <span class="subtle">{schema.path.join(".")}</span>
 | 
					      <span class="subtle">{schema.path.join(".")} {schema.hints.typehint}</span>
 | 
				
			||||||
    {/if}
 | 
					    {/if}
 | 
				
			||||||
  </div>
 | 
					  </div>
 | 
				
			||||||
{/if}
 | 
					{/if}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -92,9 +92,13 @@ let initialTag: TagConfigJson = tag.data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function initWith(initialTag: TagConfigJson) {
 | 
					function initWith(initialTag: TagConfigJson) {
 | 
				
			||||||
  if (typeof initialTag === "string") {
 | 
					  if (typeof initialTag === "string") {
 | 
				
			||||||
 | 
					    if (initialTag.startsWith("{")) {
 | 
				
			||||||
 | 
					      initialTag = JSON.parse(initialTag);
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
      addBasicTag(initialTag);
 | 
					      addBasicTag(initialTag);
 | 
				
			||||||
      return;
 | 
					      return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
  mode = <"or" | "and">Object.keys(initialTag)[0];
 | 
					  mode = <"or" | "and">Object.keys(initialTag)[0];
 | 
				
			||||||
  const subExprs = (<TagConfigJson[]>initialTag[mode]);
 | 
					  const subExprs = (<TagConfigJson[]>initialTag[mode]);
 | 
				
			||||||
  if (!subExprs || subExprs.length == 0) {
 | 
					  if (!subExprs || subExprs.length == 0) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -58,6 +58,6 @@ const total = tagInfoStats.mapD(data => data.data.find(i => i.type === "all").co
 | 
				
			||||||
    {/if}
 | 
					    {/if}
 | 
				
			||||||
{:else if $tagInfoStats && (!silent || $total < 250) }
 | 
					{:else if $tagInfoStats && (!silent || $total < 250) }
 | 
				
			||||||
    <a href={$tagInfoUrl} target="_blank" class={twMerge(($total < 250) ? "alert" : "thanks", "w-fit link-underline")}>
 | 
					    <a href={$tagInfoUrl} target="_blank" class={twMerge(($total < 250) ? "alert" : "thanks", "w-fit link-underline")}>
 | 
				
			||||||
        {$total} features on OSM have this tag
 | 
					        {$total} features have <span class="literal-code">{$tag}</span>
 | 
				
			||||||
    </a>
 | 
					    </a>
 | 
				
			||||||
{/if}
 | 
					{/if}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue