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 NextButton from "../Base/NextButton.svelte"
import BackButton from "../Base/BackButton.svelte" import BackButton from "../Base/BackButton.svelte"
import DeleteButton from "./DeleteButton.svelte" import DeleteButton from "./DeleteButton.svelte"
import StudioHashSetter from "./StudioHashSetter"
const layerSchema: ConfigMeta[] = <any>layerSchemaRaw const layerSchema: ConfigMeta[] = <any>layerSchemaRaw
export let state: EditLayerState export let state: EditLayerState
export let backToStudio: () => void export let backToStudio: () => void
new StudioHashSetter("layer", state.selectedTab, state.getStoreFor(["id"]))
let messages = state.messages let messages = state.messages
let hasErrors = messages.mapD( let hasErrors = messages.mapD(
(m: ConversionMessage[]) => m.filter((m) => m.level === "error").length (m: ConversionMessage[]) => m.filter((m) => m.level === "error").length
@ -127,7 +131,7 @@
{/each} {/each}
{:else} {:else}
<div class="m4 h-full overflow-y-auto"> <div class="m4 h-full overflow-y-auto">
<TabbedGroup> <TabbedGroup tab={state.selectedTab}>
<div slot="title0" class="flex"> <div slot="title0" class="flex">
General properties General properties
<ErrorIndicatorForRegion firstPaths={firstPathsFor("Basic")} {state} /> <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 configuration: UIEventSource<Partial<T>> = new UIEventSource<Partial<T>>({})
public readonly messages: Store<ConversionMessage[]> 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 * 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 RawEditor from "./RawEditor.svelte"
import { OsmConnection } from "../../Logic/Osm/OsmConnection" import { OsmConnection } from "../../Logic/Osm/OsmConnection"
import DeleteButton from "./DeleteButton.svelte" import DeleteButton from "./DeleteButton.svelte"
import { UIEventSource } from "../../Logic/UIEventSource"
import StudioHashSetter from "./StudioHashSetter"
export let state: EditThemeState export let state: EditThemeState
export let osmConnection: OsmConnection export let osmConnection: OsmConnection
export let backToStudio: () => void export let backToStudio: () => void
let schema: ConfigMeta[] = state.schema.filter((schema) => schema.path.length > 0) 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 selfLayers: { owner: number; id: string }[]
export let otherLayers: { owner: number; id: string }[] export let otherLayers: { owner: number; id: string }[]
@ -94,7 +97,7 @@
<div class="m4 h-full overflow-y-auto"> <div class="m4 h-full overflow-y-auto">
<!-- {Object.keys(perRegion).join(";")} --> <!-- {Object.keys(perRegion).join(";")} -->
<TabbedGroup> <TabbedGroup tab={state.selectedTab}>
<div slot="title0">Basic properties</div> <div slot="title0">Basic properties</div>
<div slot="content0" class="mb-8"> <div slot="content0" class="mb-8">
<Region configs={perRegion["basic"]} path={[]} {state} title="Basic properties" /> <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"> <script lang="ts">
import NextButton from "./Base/NextButton.svelte" import NextButton from "./Base/NextButton.svelte"
import { Store, UIEventSource } from "../Logic/UIEventSource" 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 EditLayer from "./Studio/EditLayer.svelte"
import Loading from "../assets/svg/Loading.svelte" import Loading from "../assets/svg/Loading.svelte"
import StudioServer from "./Studio/StudioServer" import StudioServer from "./Studio/StudioServer"
@ -30,6 +30,7 @@
import Tr from "./Base/Tr.svelte" import Tr from "./Base/Tr.svelte"
import Add from "../assets/svg/Add.svelte" import Add from "../assets/svg/Add.svelte"
import { SearchIcon } from "@rgossiaux/svelte-heroicons/solid" import { SearchIcon } from "@rgossiaux/svelte-heroicons/solid"
import Hash from "../Logic/Web/Hash"
export let studioUrl = export let studioUrl =
window.location.hostname === "127.0.0.2" window.location.hostname === "127.0.0.2"
@ -43,11 +44,11 @@
) )
let osmConnection = new OsmConnection({ let osmConnection = new OsmConnection({
oauth_token, oauth_token,
checkOnlineRegularly: true, checkOnlineRegularly: true
}) })
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", 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))
@ -132,16 +133,17 @@
const version = meta.version const version = meta.version
async function editLayer(event: Event) { async function editLayer(event: { detail }): Promise<EditLayerState> {
const layerId: { owner: number; id: string } = event["detail"] const layerId: { owner: number; id: string } = event["detail"]
state = "loading" state = "loading"
editLayerState.startSavingUpdates(false) editLayerState.startSavingUpdates(false)
editLayerState.configuration.setData(await studio.fetch(layerId.id, "layers", layerId.owner)) editLayerState.configuration.setData(await studio.fetch(layerId.id, "layers", layerId.owner))
editLayerState.startSavingUpdates() editLayerState.startSavingUpdates()
state = "editing_layer" 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"] const id: { id: string; owner: number } = event["detail"]
state = "loading" state = "loading"
editThemeState.startSavingUpdates(false) editThemeState.startSavingUpdates(false)
@ -149,6 +151,7 @@
editThemeState.configuration.setData(layout) editThemeState.configuration.setData(layout)
editThemeState.startSavingUpdates() editThemeState.startSavingUpdates()
state = "editing_theme" state = "editing_theme"
return editThemeState
} }
async function createNewLayer() { async function createNewLayer() {
@ -162,23 +165,50 @@
marker: [ marker: [
{ {
icon: "circle", icon: "circle",
color: "white", color: "white"
}, }
], ]
}, }
], ],
tagRenderings: ["images"], tagRenderings: ["images"],
lineRendering: [ lineRendering: [
{ {
width: 1, width: 1,
color: "blue", color: "blue"
}, }
], ]
} }
editLayerState.configuration.setData(initialLayerConfig) editLayerState.configuration.setData(initialLayerConfig)
editLayerState.startSavingUpdates() editLayerState.startSavingUpdates()
state = "editing_layer" 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> </script>
<If condition={layersWithErr.map((d) => d?.["error"] !== undefined)}> <If condition={layersWithErr.map((d) => d?.["error"] !== undefined)}>
@ -257,9 +287,7 @@
<BackButton <BackButton
clss="small p-1" clss="small p-1"
imageClass="w-8 h-8" imageClass="w-8 h-8"
on:click={() => { on:click={() => backToStudio()}
state = undefined
}}
> >
MapComplete Studio MapComplete Studio
</BackButton> </BackButton>
@ -306,9 +334,7 @@
<BackButton <BackButton
clss="small p-1" clss="small p-1"
imageClass="w-8 h-8" imageClass="w-8 h-8"
on:click={() => { on:click={() => backToStudio()}
state = undefined
}}
> >
MapComplete Studio MapComplete Studio
</BackButton> </BackButton>
@ -348,30 +374,23 @@
{:else if state === "editing_layer"} {:else if state === "editing_layer"}
<EditLayer <EditLayer
state={editLayerState} state={editLayerState}
backToStudio={() => { {backToStudio}
state = undefined
}}
> >
<BackButton <BackButton
clss="small p-1" clss="small p-1"
imageClass="w-8 h-8" imageClass="w-8 h-8"
on:click={() => { on:click={() => backToStudio()}
state = undefined
}}
> >
MapComplete Studio MapComplete Studio
</BackButton> </BackButton>
</EditLayer> </EditLayer>
{:else if state === "editing_theme"} {:else if state === "editing_theme"}
<EditTheme state={editThemeState} selfLayers={$selfLayers} otherLayers={$otherLayers} {osmConnection} backToStudio={() => { <EditTheme state={editThemeState} selfLayers={$selfLayers} otherLayers={$otherLayers} {osmConnection}
state = undefined {backToStudio}>
}}>
<BackButton <BackButton
clss="small p-1" clss="small p-1"
imageClass="w-8 h-8" imageClass="w-8 h-8"
on:click={() => { on:click={() => backToStudio()}
state = undefined
}}
> >
MapComplete Studio MapComplete Studio
</BackButton> </BackButton>