Studio(UX): small fixes to studio

This commit is contained in:
Pieter Vander Vennet 2025-02-28 13:14:14 +01:00
parent cddf319c9e
commit 5f5960e909
6 changed files with 72 additions and 40 deletions

View file

@ -218,10 +218,10 @@ export interface QuestionableTagRenderingConfigJson extends TagRenderingConfigJs
*/ */
freeform?: { freeform?: {
/** /**
* question: What is the name of the attribute that should be written to? * question: What is the name of the key (attribute) that should be filled if an answer is given?
* This is the OpenStreetMap-key that that value will be written to * This data will be uploaded to OpenStreetMap
* ifunset: do not offer a freeform textfield as answer option * If this key is present in the feature, then 'render' is used to display the value and should contain this.
* * ifunset: Do not allow a text/value field that a contributor can type into. (Only if no question is defined): always show "render", no matter the values
*/ */
key?: string key?: string

View file

@ -147,9 +147,10 @@ export interface TagRenderingConfigJson {
*/ */
freeform?: { freeform?: {
/** /**
* What attribute should be filled out * question: What is the name of the key (attribute) that should be filled if an answer is given?
* If this key is present in the feature, then 'render' is used to display the value. * This data will be uploaded to OpenStreetMap
* If this is undefined, the rendering is _always_ shown * If this key is present in the feature, then 'render' is used to display the value and should contain this.
* ifunset: Do not allow a text/value field that a contributor can type into. (Only if no question is defined): always show "render", no matter the values
*/ */
key?: string key?: string
} }

View file

@ -1,16 +1,17 @@
<script lang="ts"> <script lang="ts">
import { OsmConnection } from "../../Logic/Osm/OsmConnection" import { OsmConnection } from "../../Logic/Osm/OsmConnection"
import EditItemButton from "./EditItemButton.svelte" import EditItemButton from "./EditItemButton.svelte"
import { Store } from "../../Logic/UIEventSource"
export let layerIds: { id: string; owner: number }[] export let layerIds: Store<{ id: string; owner: number }[]>
export let category: "layers" | "themes" = "layers" export let category: "layers" | "themes" = "layers"
export let osmConnection: OsmConnection export let osmConnection: OsmConnection
</script> </script>
{#if layerIds.length > 0} {#if $layerIds.length > 0}
<slot name="title" /> <slot name="title" />
<div class="flex flex-wrap"> <div class="flex flex-wrap">
{#each Array.from(layerIds) as layer} {#each Array.from($layerIds) as layer (layer)}
<EditItemButton info={layer} {category} {osmConnection} on:layerSelected /> <EditItemButton info={layer} {category} {osmConnection} on:layerSelected />
{/each} {/each}
</div> </div>

View file

@ -58,9 +58,7 @@
fakeUser: fakeUser.data, fakeUser: fakeUser.data,
}) })
const expertMode = UIEventSource.asBoolean( const expertMode = UIEventSource.asBoolean(
osmConnection.GetPreference("studio-expert-mode", "false", { osmConnection.GetPreference("studio-expert-mode", "false")
documentation: "Indicates if more options are shown in mapcomplete studio",
})
) )
expertMode.addCallbackAndRunD((expert) => console.log("Expert mode is", expert)) expertMode.addCallbackAndRunD((expert) => console.log("Expert mode is", expert))
const createdBy = osmConnection.userDetails.data?.name const createdBy = osmConnection.userDetails.data?.name
@ -71,63 +69,63 @@
const studio = new StudioServer(studioUrl, uid) const studio = new StudioServer(studioUrl, uid)
let layersWithErr = studio.fetchOverview() let layersWithErr = studio.fetchOverview()
let layerFilterTerm: string = "" let layerFilterTerm: UIEventSource<string> = new UIEventSource<string>("")
let layers: Store<{ owner: number; id: string }[]> = layersWithErr.mapD((l) => let layers: Store<{ owner: number; id: string }[]> = layersWithErr.mapD((l) =>
l["success"]?.filter((l) => l.category === "layers") l["success"]?.filter((l) => l.category === "layers")
) )
$: selfLayers = layers.mapD( let selfLayers = layers.mapD(
(ls) => (ls) =>
ls.filter( ls.filter(
(l) => l.owner === uid.data && l.id.toLowerCase().includes(layerFilterTerm.toLowerCase()) (l) => l.owner === uid.data && l.id.toLowerCase().includes(layerFilterTerm.data.toLowerCase())
), ),
[uid] [uid, layerFilterTerm]
) )
$: otherLayers = layers.mapD( let otherLayers = layers.mapD(
(ls) => (ls) =>
ls.filter( ls.filter(
(l) => (l) =>
l.owner !== undefined && l.owner !== undefined &&
l.owner !== uid.data && l.owner !== uid.data &&
l.id.toLowerCase().includes(layerFilterTerm.toLowerCase()) l.id.toLowerCase().includes(layerFilterTerm.data.toLowerCase())
), ),
[uid] [uid, layerFilterTerm]
) )
$: officialLayers = layers.mapD( let officialLayers = layers.mapD(
(ls) => (ls) =>
ls.filter( ls.filter(
(l) => l.owner === undefined && l.id.toLowerCase().includes(layerFilterTerm.toLowerCase()) (l) => l.owner === undefined && l.id.toLowerCase().includes(layerFilterTerm.data.toLowerCase())
), ),
[uid] [uid, layerFilterTerm]
) )
let themeFilterTerm: string = "" let themeFilterTerm: UIEventSource<string> = new UIEventSource("")
let themes: Store<{ owner: number; id: string }[]> = layersWithErr.mapD((l) => let themes: Store<{ owner: number; id: string }[]> = layersWithErr.mapD((l) =>
l["success"]?.filter((l) => l.category === "themes") l["success"]?.filter((l) => l.category === "themes")
) )
$: selfThemes = themes.mapD( let selfThemes = themes.mapD(
(ls) => (ls) =>
ls.filter( ls.filter(
(l) => l.owner === uid.data && l.id.toLowerCase().includes(themeFilterTerm.toLowerCase()) (l) => l.owner === uid.data && l.id.toLowerCase().includes(themeFilterTerm.data.toLowerCase())
), ),
[uid] [uid, themeFilterTerm]
) )
$: otherThemes = themes.mapD( let otherThemes = themes.mapD(
(ls) => (ls) =>
ls.filter( ls.filter(
(l) => (l) =>
l.owner !== undefined && l.owner !== undefined &&
l.owner !== uid.data && l.owner !== uid.data &&
l.id.toLowerCase().includes(themeFilterTerm.toLowerCase()) l.id.toLowerCase().includes(themeFilterTerm.data.toLowerCase())
), ),
[uid] [uid, themeFilterTerm]
) )
$: officialThemes = themes.mapD( let officialThemes = themes.mapD(
(ls) => (ls) =>
ls.filter( ls.filter(
(l) => l.owner === undefined && l.id.toLowerCase().includes(themeFilterTerm.toLowerCase()) (l) => l.owner === undefined && l.id.toLowerCase().includes(themeFilterTerm.data.toLowerCase())
), ),
[uid] [uid, themeFilterTerm]
) )
let state: let state:
@ -321,12 +319,12 @@
id="layer-search" id="layer-search"
type="search" type="search"
placeholder="Filter layers by name" placeholder="Filter layers by name"
bind:value={layerFilterTerm} bind:value={$layerFilterTerm}
/> />
</label> </label>
</form> </form>
<ChooseLayerToEdit {osmConnection} layerIds={$selfLayers} on:layerSelected={editLayer}> <ChooseLayerToEdit {osmConnection} layerIds={selfLayers} on:layerSelected={editLayer}>
<h3 slot="title">Your layers</h3> <h3 slot="title">Your layers</h3>
<div class="subtle">Your id is {$uid}</div> <div class="subtle">Your id is {$uid}</div>
</ChooseLayerToEdit> </ChooseLayerToEdit>
@ -335,7 +333,7 @@
Selecting a layer will create a copy in your account that you edit. You will not change Selecting a layer will create a copy in your account that you edit. You will not change
the version of the other contributor the version of the other contributor
</div> </div>
<ChooseLayerToEdit {osmConnection} layerIds={$otherLayers} on:layerSelected={editLayer} /> <ChooseLayerToEdit {osmConnection} layerIds={otherLayers} on:layerSelected={editLayer} />
<h3>Official layers by MapComplete</h3> <h3>Official layers by MapComplete</h3>
<div> <div>
@ -344,7 +342,7 @@
</div> </div>
<ChooseLayerToEdit <ChooseLayerToEdit
{osmConnection} {osmConnection}
layerIds={$officialLayers} layerIds={officialLayers}
on:layerSelected={editLayer} on:layerSelected={editLayer}
/> />
</div> </div>
@ -370,15 +368,15 @@
</label> </label>
</form> </form>
<ChooseLayerToEdit {osmConnection} layerIds={$selfThemes} on:layerSelected={editTheme}> <ChooseLayerToEdit {osmConnection} layerIds={selfThemes} on:layerSelected={editTheme}>
<h3 slot="title">Your themes</h3> <h3 slot="title">Your themes</h3>
</ChooseLayerToEdit> </ChooseLayerToEdit>
<h3>Themes by other contributors</h3> <h3>Themes by other contributors</h3>
<ChooseLayerToEdit {osmConnection} layerIds={$otherThemes} on:layerSelected={editTheme} /> <ChooseLayerToEdit {osmConnection} layerIds={otherThemes} on:layerSelected={editTheme} />
<h3>Official themes by MapComplete</h3> <h3>Official themes by MapComplete</h3>
<ChooseLayerToEdit <ChooseLayerToEdit
{osmConnection} {osmConnection}
layerIds={$officialThemes} layerIds={officialThemes}
on:layerSelected={editTheme} on:layerSelected={editTheme}
/> />
</div> </div>

View file

@ -10820,6 +10820,10 @@
"if": "value=brothel", "if": "value=brothel",
"then": "brothel - An establishment specifically dedicated to prostitution." "then": "brothel - An establishment specifically dedicated to prostitution."
}, },
{
"if": "value=building",
"then": "building - All buildings"
},
{ {
"if": "value=cafe_pub", "if": "value=cafe_pub",
"then": "cafe_pub - A layer showing cafés and pubs where one can gather around a drink. The layer asks for some relevant questions" "then": "cafe_pub - A layer showing cafés and pubs where one can gather around a drink. The layer asks for some relevant questions"
@ -10900,6 +10904,10 @@
"if": "value=cycle_highways", "if": "value=cycle_highways",
"then": "cycle_highways - undefined" "then": "cycle_highways - undefined"
}, },
{
"if": "value=cyclestreets",
"then": "cyclestreets - A cyclestreet is a street where motorized traffic is not allowed to overtake a cyclist"
},
{ {
"if": "value=cycleways_and_roads", "if": "value=cycleways_and_roads",
"then": "cycleways_and_roads - All infrastructure that someone can cycle over, accompanied with questions about this infrastructure" "then": "cycleways_and_roads - All infrastructure that someone can cycle over, accompanied with questions about this infrastructure"

View file

@ -699,6 +699,10 @@
"if": "value=brothel", "if": "value=brothel",
"then": "<b>brothel</b> (builtin) - An establishment specifically dedicated to prostitution." "then": "<b>brothel</b> (builtin) - An establishment specifically dedicated to prostitution."
}, },
{
"if": "value=building",
"then": "<b>building</b> (builtin) - All buildings"
},
{ {
"if": "value=cafe_pub", "if": "value=cafe_pub",
"then": "<b>cafe_pub</b> (builtin) - A layer showing cafés and pubs where one can gather around a drink. The layer asks for some relevant questions" "then": "<b>cafe_pub</b> (builtin) - A layer showing cafés and pubs where one can gather around a drink. The layer asks for some relevant questions"
@ -779,6 +783,10 @@
"if": "value=cycle_highways", "if": "value=cycle_highways",
"then": "<b>cycle_highways</b> (builtin) - undefined" "then": "<b>cycle_highways</b> (builtin) - undefined"
}, },
{
"if": "value=cyclestreets",
"then": "<b>cyclestreets</b> (builtin) - A cyclestreet is a street where motorized traffic is not allowed to overtake a cyclist"
},
{ {
"if": "value=cycleways_and_roads", "if": "value=cycleways_and_roads",
"then": "<b>cycleways_and_roads</b> (builtin) - All infrastructure that someone can cycle over, accompanied with questions about this infrastructure" "then": "<b>cycleways_and_roads</b> (builtin) - All infrastructure that someone can cycle over, accompanied with questions about this infrastructure"
@ -13439,6 +13447,10 @@
"if": "value=brothel", "if": "value=brothel",
"then": "brothel - An establishment specifically dedicated to prostitution." "then": "brothel - An establishment specifically dedicated to prostitution."
}, },
{
"if": "value=building",
"then": "building - All buildings"
},
{ {
"if": "value=cafe_pub", "if": "value=cafe_pub",
"then": "cafe_pub - A layer showing cafés and pubs where one can gather around a drink. The layer asks for some relevant questions" "then": "cafe_pub - A layer showing cafés and pubs where one can gather around a drink. The layer asks for some relevant questions"
@ -13519,6 +13531,10 @@
"if": "value=cycle_highways", "if": "value=cycle_highways",
"then": "cycle_highways - undefined" "then": "cycle_highways - undefined"
}, },
{
"if": "value=cyclestreets",
"then": "cyclestreets - A cyclestreet is a street where motorized traffic is not allowed to overtake a cyclist"
},
{ {
"if": "value=cycleways_and_roads", "if": "value=cycleways_and_roads",
"then": "cycleways_and_roads - All infrastructure that someone can cycle over, accompanied with questions about this infrastructure" "then": "cycleways_and_roads - All infrastructure that someone can cycle over, accompanied with questions about this infrastructure"
@ -35215,6 +35231,10 @@
"if": "value=brothel", "if": "value=brothel",
"then": "brothel - An establishment specifically dedicated to prostitution." "then": "brothel - An establishment specifically dedicated to prostitution."
}, },
{
"if": "value=building",
"then": "building - All buildings"
},
{ {
"if": "value=cafe_pub", "if": "value=cafe_pub",
"then": "cafe_pub - A layer showing cafés and pubs where one can gather around a drink. The layer asks for some relevant questions" "then": "cafe_pub - A layer showing cafés and pubs where one can gather around a drink. The layer asks for some relevant questions"
@ -35295,6 +35315,10 @@
"if": "value=cycle_highways", "if": "value=cycle_highways",
"then": "cycle_highways - undefined" "then": "cycle_highways - undefined"
}, },
{
"if": "value=cyclestreets",
"then": "cyclestreets - A cyclestreet is a street where motorized traffic is not allowed to overtake a cyclist"
},
{ {
"if": "value=cycleways_and_roads", "if": "value=cycleways_and_roads",
"then": "cycleways_and_roads - All infrastructure that someone can cycle over, accompanied with questions about this infrastructure" "then": "cycleways_and_roads - All infrastructure that someone can cycle over, accompanied with questions about this infrastructure"