Studio: Add deeplinks, fix #1926

This commit is contained in:
Pieter Vander Vennet 2024-04-28 00:23:20 +02:00
parent 204027b4e9
commit 504cc1fe33
5 changed files with 82 additions and 40 deletions

View file

@ -20,12 +20,16 @@
import NextButton from "../Base/NextButton.svelte"
import BackButton from "../Base/BackButton.svelte"
import DeleteButton from "./DeleteButton.svelte"
import StudioHashSetter from "./StudioHashSetter"
const layerSchema: ConfigMeta[] = <any>layerSchemaRaw
export let state: EditLayerState
export let backToStudio: () => void
new StudioHashSetter("layer", state.selectedTab, state.getStoreFor(["id"]))
let messages = state.messages
let hasErrors = messages.mapD(
(m: ConversionMessage[]) => m.filter((m) => m.level === "error").length
@ -127,7 +131,7 @@
{/each}
{:else}
<div class="m4 h-full overflow-y-auto">
<TabbedGroup>
<TabbedGroup tab={state.selectedTab}>
<div slot="title0" class="flex">
General properties
<ErrorIndicatorForRegion firstPaths={firstPathsFor("Basic")} {state} />

View file

@ -42,6 +42,11 @@ export abstract class EditJsonState<T> {
public readonly configuration: UIEventSource<Partial<T>> = new UIEventSource<Partial<T>>({})
public readonly messages: Store<ConversionMessage[]>
/**
* The tab in the UI that is selected, used for deeplinks
*/
public readonly selectedTab: UIEventSource<number> = new UIEventSource<number>(0)
/**
* The EditLayerUI shows a 'schemaBasedInput' for this path to pop advanced questions out
*/

View file

@ -9,12 +9,15 @@
import RawEditor from "./RawEditor.svelte"
import { OsmConnection } from "../../Logic/Osm/OsmConnection"
import DeleteButton from "./DeleteButton.svelte"
import { UIEventSource } from "../../Logic/UIEventSource"
import StudioHashSetter from "./StudioHashSetter"
export let state: EditThemeState
export let osmConnection: OsmConnection
export let backToStudio: () => void
let schema: ConfigMeta[] = state.schema.filter((schema) => schema.path.length > 0)
new StudioHashSetter("theme", state.selectedTab, state.getStoreFor(["id"]))
export let selfLayers: { owner: number; id: string }[]
export let otherLayers: { owner: number; id: string }[]
@ -94,7 +97,7 @@
<div class="m4 h-full overflow-y-auto">
<!-- {Object.keys(perRegion).join(";")} -->
<TabbedGroup>
<TabbedGroup tab={state.selectedTab}>
<div slot="title0">Basic properties</div>
<div slot="content0" class="mb-8">
<Region configs={perRegion["basic"]} path={[]} {state} title="Basic properties" />

View file

@ -0,0 +1,11 @@
import { Store, UIEventSource } from "../../Logic/UIEventSource"
import Hash from "../../Logic/Web/Hash"
export default class StudioHashSetter {
constructor(mode: "layer" | "theme", tab: Store<number>, name: Store<string>) {
tab.mapD(tab => {
Hash.hash.setData(mode + "/" + name.data + "/" + tab)
}
, [name])
}
}

View file

@ -1,7 +1,7 @@
<script lang="ts">
import NextButton from "./Base/NextButton.svelte"
import { Store, UIEventSource } from "../Logic/UIEventSource"
import EditLayerState, { EditThemeState } from "./Studio/EditLayerState"
import EditLayerState, { EditJsonState, EditThemeState } from "./Studio/EditLayerState"
import EditLayer from "./Studio/EditLayer.svelte"
import Loading from "../assets/svg/Loading.svelte"
import StudioServer from "./Studio/StudioServer"
@ -30,6 +30,7 @@
import Tr from "./Base/Tr.svelte"
import Add from "../assets/svg/Add.svelte"
import { SearchIcon } from "@rgossiaux/svelte-heroicons/solid"
import Hash from "../Logic/Web/Hash"
export let studioUrl =
window.location.hostname === "127.0.0.2"
@ -43,11 +44,11 @@
)
let osmConnection = new OsmConnection({
oauth_token,
checkOnlineRegularly: true,
checkOnlineRegularly: true
})
const expertMode = UIEventSource.asBoolean(
osmConnection.GetPreference("studio-expert-mode", "false", {
documentation: "Indicates if more options are shown in mapcomplete studio",
documentation: "Indicates if more options are shown in mapcomplete studio"
})
)
expertMode.addCallbackAndRunD((expert) => console.log("Expert mode is", expert))
@ -61,12 +62,12 @@
l["success"]?.filter((l) => l.category === "layers")
)
$: selfLayers = layers.mapD(
(ls) =>
ls.filter(
(l) => l.owner === uid.data && l.id.toLowerCase().includes(layerFilterTerm.toLowerCase())
),
[uid]
)
(ls) =>
ls.filter(
(l) => l.owner === uid.data && l.id.toLowerCase().includes(layerFilterTerm.toLowerCase())
),
[uid]
)
$: otherLayers = layers.mapD(
(ls) =>
ls.filter(
@ -132,16 +133,17 @@
const version = meta.version
async function editLayer(event: Event) {
async function editLayer(event: { detail }): Promise<EditLayerState> {
const layerId: { owner: number; id: string } = event["detail"]
state = "loading"
editLayerState.startSavingUpdates(false)
editLayerState.configuration.setData(await studio.fetch(layerId.id, "layers", layerId.owner))
editLayerState.startSavingUpdates()
state = "editing_layer"
return editLayerState
}
async function editTheme(event: Event) {
async function editTheme(event: { detail }): Promise<EditThemeState> {
const id: { id: string; owner: number } = event["detail"]
state = "loading"
editThemeState.startSavingUpdates(false)
@ -149,6 +151,7 @@
editThemeState.configuration.setData(layout)
editThemeState.startSavingUpdates()
state = "editing_theme"
return editThemeState
}
async function createNewLayer() {
@ -162,23 +165,50 @@
marker: [
{
icon: "circle",
color: "white",
},
],
},
color: "white"
}
]
}
],
tagRenderings: ["images"],
lineRendering: [
{
width: 1,
color: "blue",
},
],
color: "blue"
}
]
}
editLayerState.configuration.setData(initialLayerConfig)
editLayerState.startSavingUpdates()
state = "editing_layer"
}
async function selectStateBasedOnHash() {
const hash = Hash.hash.data
if (!hash) {
return
}
console.log("Selecting state based on ", hash)
const [mode, id, tab] = hash.split("/")
// Not really an event, we just set the 'detail'
const event = {
detail: {
id,
owner: uid.data
}
}
const statePromise: Promise<EditJsonState<any>> = mode === "layer" ? editLayer(event) : editTheme(event)
const state = await statePromise
state.selectedTab.setData(Number(tab))
}
selectStateBasedOnHash()
function backToStudio() {
console.log("Back to studio")
state = undefined
Hash.hash.setData(undefined)
}
</script>
<If condition={layersWithErr.map((d) => d?.["error"] !== undefined)}>
@ -191,8 +221,8 @@
<li>Try again in a few minutes</li>
<li>
Contact <a href="https://app.element.io/#/room/#MapComplete:matrix.org">
the MapComplete community via the chat.
</a>
the MapComplete community via the chat.
</a>
Someone might be able to help you
</li>
<li>
@ -257,9 +287,7 @@
<BackButton
clss="small p-1"
imageClass="w-8 h-8"
on:click={() => {
state = undefined
}}
on:click={() => backToStudio()}
>
MapComplete Studio
</BackButton>
@ -306,9 +334,7 @@
<BackButton
clss="small p-1"
imageClass="w-8 h-8"
on:click={() => {
state = undefined
}}
on:click={() => backToStudio()}
>
MapComplete Studio
</BackButton>
@ -348,30 +374,23 @@
{:else if state === "editing_layer"}
<EditLayer
state={editLayerState}
backToStudio={() => {
state = undefined
}}
{backToStudio}
>
<BackButton
clss="small p-1"
imageClass="w-8 h-8"
on:click={() => {
state = undefined
}}
on:click={() => backToStudio()}
>
MapComplete Studio
</BackButton>
</EditLayer>
{:else if state === "editing_theme"}
<EditTheme state={editThemeState} selfLayers={$selfLayers} otherLayers={$otherLayers} {osmConnection} backToStudio={() => {
state = undefined
}}>
<EditTheme state={editThemeState} selfLayers={$selfLayers} otherLayers={$otherLayers} {osmConnection}
{backToStudio}>
<BackButton
clss="small p-1"
imageClass="w-8 h-8"
on:click={() => {
state = undefined
}}
on:click={() => backToStudio()}
>
MapComplete Studio
</BackButton>