Update and improve state <-> URL binding
This commit is contained in:
parent
a6ad8e1ab0
commit
fba2f27638
|
@ -13,12 +13,7 @@ import { fetchComponentLibDefinitions } from "../loadComponentLibraries"
|
||||||
import api from "../api"
|
import api from "../api"
|
||||||
import { FrontendTypes } from "constants"
|
import { FrontendTypes } from "constants"
|
||||||
import analytics from "analytics"
|
import analytics from "analytics"
|
||||||
import {
|
import { findComponentType, findComponentParent } from "../storeUtils"
|
||||||
findComponentType,
|
|
||||||
findComponentParent,
|
|
||||||
findComponentPath,
|
|
||||||
findComponent,
|
|
||||||
} from "../storeUtils"
|
|
||||||
import { uuid } from "../uuid"
|
import { uuid } from "../uuid"
|
||||||
|
|
||||||
const INITIAL_FRONTEND_STATE = {
|
const INITIAL_FRONTEND_STATE = {
|
||||||
|
@ -487,21 +482,6 @@ export const getFrontendStore = () => {
|
||||||
})
|
})
|
||||||
store.actions.preview.saveSelected()
|
store.actions.preview.saveSelected()
|
||||||
},
|
},
|
||||||
findRoute: component => {
|
|
||||||
const selectedAsset = get(currentAsset)
|
|
||||||
if (!component || !selectedAsset) {
|
|
||||||
return "/"
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the path to this component
|
|
||||||
const path = findComponentPath(selectedAsset.props, component._id) || []
|
|
||||||
|
|
||||||
// Remove root entry since it's the screen or layout
|
|
||||||
return path
|
|
||||||
.slice(1)
|
|
||||||
.map(component => component._id)
|
|
||||||
.join("/")
|
|
||||||
},
|
|
||||||
links: {
|
links: {
|
||||||
save: async (url, title) => {
|
save: async (url, title) => {
|
||||||
const layout = get(mainLayout)
|
const layout = get(mainLayout)
|
||||||
|
|
|
@ -46,11 +46,7 @@
|
||||||
popover.show()
|
popover.show()
|
||||||
} else {
|
} else {
|
||||||
// Add this component
|
// Add this component
|
||||||
const newComponent = store.actions.components.create(item.component)
|
store.actions.components.create(item.component)
|
||||||
if (newComponent) {
|
|
||||||
const path = store.actions.components.findRoute(newComponent)
|
|
||||||
$goto(`./${$currentAssetId}/${path}`)
|
|
||||||
}
|
|
||||||
popover.hide()
|
popover.hide()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
<script>
|
<script>
|
||||||
import { goto } from "@sveltech/routify"
|
|
||||||
import { get } from "svelte/store"
|
import { get } from "svelte/store"
|
||||||
import { store, currentAsset } from "builderStore"
|
import { store, currentAsset } from "builderStore"
|
||||||
import ConfirmDialog from "components/common/ConfirmDialog.svelte"
|
import ConfirmDialog from "components/common/ConfirmDialog.svelte"
|
||||||
|
@ -27,8 +26,6 @@
|
||||||
|
|
||||||
const selectComponent = component => {
|
const selectComponent = component => {
|
||||||
store.actions.components.select(component)
|
store.actions.components.select(component)
|
||||||
const path = store.actions.components.findRoute(component)
|
|
||||||
$goto(`./${$store.currentFrontEndType}/${path}`)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const moveUpComponent = () => {
|
const moveUpComponent = () => {
|
||||||
|
|
|
@ -15,8 +15,6 @@
|
||||||
|
|
||||||
const selectComponent = component => {
|
const selectComponent = component => {
|
||||||
store.actions.components.select(component)
|
store.actions.components.select(component)
|
||||||
const path = store.actions.components.findRoute(component)
|
|
||||||
$goto(`./${$currentAssetId}/${path}`)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const dragstart = component => e => {
|
const dragstart = component => e => {
|
||||||
|
|
|
@ -24,9 +24,7 @@
|
||||||
$: selectedScreen = $currentAsset
|
$: selectedScreen = $currentAsset
|
||||||
|
|
||||||
const changeScreen = screenId => {
|
const changeScreen = screenId => {
|
||||||
// select the route
|
|
||||||
store.actions.screens.select(screenId)
|
store.actions.screens.select(screenId)
|
||||||
$goto(`./${screenId}`)
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,7 @@
|
||||||
|
|
||||||
let modal
|
let modal
|
||||||
let routes = {}
|
let routes = {}
|
||||||
let tab = $params.assetType
|
$: tab = $params.assetType
|
||||||
|
|
||||||
const navigate = ({ detail }) => {
|
const navigate = ({ detail }) => {
|
||||||
if (!detail) {
|
if (!detail) {
|
||||||
|
|
|
@ -19,7 +19,6 @@
|
||||||
|
|
||||||
const selectLayout = () => {
|
const selectLayout = () => {
|
||||||
store.actions.layouts.select(layout._id)
|
store.actions.layouts.select(layout._id)
|
||||||
$goto(`./${layout._id}`)
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -8,8 +8,7 @@
|
||||||
|
|
||||||
async function save() {
|
async function save() {
|
||||||
try {
|
try {
|
||||||
const layout = await store.actions.layouts.save({ name })
|
await store.actions.layouts.save({ name })
|
||||||
$goto(`./${layout._id}`)
|
|
||||||
notifier.success(`Layout ${name} created successfully`)
|
notifier.success(`Layout ${name} created successfully`)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
notifier.danger(`Error creating layout ${name}.`)
|
notifier.danger(`Error creating layout ${name}.`)
|
||||||
|
|
|
@ -63,7 +63,7 @@
|
||||||
draftScreen.props._component = baseComponent
|
draftScreen.props._component = baseComponent
|
||||||
draftScreen.routing = { route, roleId }
|
draftScreen.routing = { route, roleId }
|
||||||
|
|
||||||
const createdScreen = await store.actions.screens.create(draftScreen)
|
await store.actions.screens.create(draftScreen)
|
||||||
if (createLink) {
|
if (createLink) {
|
||||||
await store.actions.components.links.save(route, name)
|
await store.actions.components.links.save(route, name)
|
||||||
}
|
}
|
||||||
|
@ -75,8 +75,6 @@
|
||||||
template: template.id || template.name,
|
template: template.id || template.name,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
$goto(`./${createdScreen._id}`)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const routeExists = (route, roleId) => {
|
const routeExists = (route, roleId) => {
|
||||||
|
|
|
@ -35,7 +35,6 @@
|
||||||
$currentAsset.props,
|
$currentAsset.props,
|
||||||
$store.selectedComponentId
|
$store.selectedComponentId
|
||||||
)
|
)
|
||||||
$: console.log(bindableProperties)
|
|
||||||
|
|
||||||
$: links = bindableProperties
|
$: links = bindableProperties
|
||||||
.filter(x => x.fieldSchema?.type === "link")
|
.filter(x => x.fieldSchema?.type === "link")
|
||||||
|
|
|
@ -1,64 +1,92 @@
|
||||||
<script>
|
<script>
|
||||||
|
import { onMount } from "svelte"
|
||||||
|
import { get } from "svelte/store"
|
||||||
import { params, leftover, goto } from "@sveltech/routify"
|
import { params, leftover, goto } from "@sveltech/routify"
|
||||||
import { FrontendTypes } from "constants"
|
import { FrontendTypes } from "constants"
|
||||||
import { store, allScreens } from "builderStore"
|
import { store, allScreens, currentAsset } from "builderStore"
|
||||||
|
import { findComponent, findComponentPath } from "builderStore/storeUtils"
|
||||||
|
|
||||||
// Get any leftover params not caught by Routifys params store.
|
let initialised = false
|
||||||
const componentIds = $leftover.split("/").filter(id => id !== "")
|
|
||||||
|
|
||||||
const currentAssetId = decodeURI($params.asset)
|
// Hydrate state from query param on mount
|
||||||
|
onMount(() => {
|
||||||
|
const assetId = decodeURI($params.asset)
|
||||||
|
let assetList
|
||||||
|
let actions
|
||||||
|
|
||||||
let assetList
|
// Determine screens or layouts based on the URL
|
||||||
let actions
|
if ($params.assetType === FrontendTypes.SCREEN) {
|
||||||
|
assetList = $allScreens
|
||||||
|
actions = store.actions.screens
|
||||||
|
} else {
|
||||||
|
assetList = $store.layouts
|
||||||
|
actions = store.actions.layouts
|
||||||
|
}
|
||||||
|
|
||||||
// Determine screens or layouts based on the URL
|
// Find and select the current asset
|
||||||
if ($params.assetType === FrontendTypes.SCREEN) {
|
const asset = assetList.find(asset => asset._id === assetId)
|
||||||
assetList = $allScreens
|
if (asset) {
|
||||||
actions = store.actions.screens
|
actions.select(assetId)
|
||||||
} else {
|
|
||||||
assetList = $store.layouts
|
// Select the component ID if one is present in the URL
|
||||||
actions = store.actions.layouts
|
const selectedComponentId = $leftover.split("/").pop()
|
||||||
|
if (selectedComponentId) {
|
||||||
|
const component = findComponent(asset.props, selectedComponentId)
|
||||||
|
if (component) {
|
||||||
|
store.actions.components.select(component)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
initialised = true
|
||||||
|
})
|
||||||
|
|
||||||
|
// Updates the route params in the URL to the specified values
|
||||||
|
const updateParams = (assetType, asset, componentId) => {
|
||||||
|
// Wait until the initial state rehydration to avoid a wasted update
|
||||||
|
if (!initialised) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract current URL params
|
||||||
|
const currentParams = get(params)
|
||||||
|
const currentLeftover = get(leftover)
|
||||||
|
const paramAssetType = currentParams.assetType
|
||||||
|
const paramAssetId = currentParams.asset
|
||||||
|
const paramComponentId = currentLeftover.split("/").pop()
|
||||||
|
|
||||||
|
// Only update params if the params actually changed
|
||||||
|
if (
|
||||||
|
assetType !== paramAssetType ||
|
||||||
|
asset?._id !== paramAssetId ||
|
||||||
|
componentId !== paramComponentId
|
||||||
|
) {
|
||||||
|
// Build and navigate to a valid URL
|
||||||
|
let url = "../../"
|
||||||
|
if ([FrontendTypes.SCREEN, FrontendTypes.LAYOUT].includes(assetType)) {
|
||||||
|
url += `${assetType}`
|
||||||
|
if (asset?._id) {
|
||||||
|
url += `/${asset._id}`
|
||||||
|
if (componentId) {
|
||||||
|
const componentPath = findComponentPath(asset.props, componentId)
|
||||||
|
const componentURL = componentPath
|
||||||
|
.slice(1)
|
||||||
|
.map(comp => comp._id)
|
||||||
|
.join("/")
|
||||||
|
url += `/${componentURL}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$goto(url)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// select the screen or layout in the UI
|
// Automatically keep URL up to date with state
|
||||||
actions.select(currentAssetId)
|
$: updateParams(
|
||||||
|
$store.currentFrontEndType,
|
||||||
// There are leftover stuff, like IDs, so navigate the components and find the ID and select it.
|
$currentAsset,
|
||||||
if ($leftover) {
|
$store.selectedComponentId
|
||||||
// Get the correct screen children.
|
)
|
||||||
const assetChildren =
|
|
||||||
assetList.find(
|
|
||||||
asset =>
|
|
||||||
asset._id === $params.asset ||
|
|
||||||
asset._id === decodeURIComponent($params.asset)
|
|
||||||
)?.props._children ?? []
|
|
||||||
findComponent(componentIds, assetChildren)
|
|
||||||
}
|
|
||||||
// }
|
|
||||||
|
|
||||||
// Find Component with ID and continue
|
|
||||||
function findComponent(ids, children) {
|
|
||||||
// Setup stuff
|
|
||||||
let componentToSelect
|
|
||||||
let currentChildren = children
|
|
||||||
|
|
||||||
// Loop through each ID
|
|
||||||
ids.forEach(id => {
|
|
||||||
// Find ID
|
|
||||||
const component = currentChildren.find(child => child._id === id)
|
|
||||||
|
|
||||||
// If it does not exist, ignore (use last valid route)
|
|
||||||
if (!component) return
|
|
||||||
|
|
||||||
componentToSelect = component
|
|
||||||
|
|
||||||
// Update childrens array to selected components children
|
|
||||||
currentChildren = componentToSelect._children
|
|
||||||
})
|
|
||||||
|
|
||||||
// Select Component!
|
|
||||||
if (componentToSelect) store.actions.components.select(componentToSelect)
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<slot />
|
<slot />
|
||||||
|
|
|
@ -11,25 +11,11 @@
|
||||||
import ComponentSelectionList from "components/design/AppPreview/ComponentSelectionList.svelte"
|
import ComponentSelectionList from "components/design/AppPreview/ComponentSelectionList.svelte"
|
||||||
import FrontendNavigatePane from "components/design/NavigationPanel/FrontendNavigatePane.svelte"
|
import FrontendNavigatePane from "components/design/NavigationPanel/FrontendNavigatePane.svelte"
|
||||||
|
|
||||||
$: instance = $store.appInstance
|
|
||||||
|
|
||||||
async function selectDatabase(database) {
|
|
||||||
backendUiStore.actions.database.select(database)
|
|
||||||
}
|
|
||||||
|
|
||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
if ($store.appInstance && !$backendUiStore.database) {
|
if ($store.appInstance && !$backendUiStore.database) {
|
||||||
await selectDatabase($store.appInstance)
|
backendUiStore.actions.database.select($store.appInstance)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
let confirmDeleteDialog
|
|
||||||
let componentToDelete = ""
|
|
||||||
|
|
||||||
let settingsView
|
|
||||||
const settings = () => {
|
|
||||||
settingsView.show()
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<!-- routify:options index=1 -->
|
<!-- routify:options index=1 -->
|
||||||
|
|
|
@ -1,37 +1,45 @@
|
||||||
<script>
|
<script>
|
||||||
|
import { onMount } from "svelte"
|
||||||
|
import { goto } from "@sveltech/routify"
|
||||||
import { store, allScreens } from "builderStore"
|
import { store, allScreens } from "builderStore"
|
||||||
import { FrontendTypes } from "constants"
|
import { FrontendTypes } from "constants"
|
||||||
import { goto, params } from "@sveltech/routify"
|
import { params } from "@sveltech/routify"
|
||||||
|
|
||||||
// Go to first layout
|
onMount(() => {
|
||||||
if ($params.assetType === FrontendTypes.LAYOUT) {
|
|
||||||
// Try to use previously selected layout first
|
|
||||||
let id
|
let id
|
||||||
if (
|
|
||||||
$store.selectedLayoutId &&
|
|
||||||
$store.layouts.find(layout => layout._id === $store.selectedLayoutId)
|
|
||||||
) {
|
|
||||||
id = $store.selectedLayoutId
|
|
||||||
} else {
|
|
||||||
id = $store.layouts[0]?._id
|
|
||||||
}
|
|
||||||
$goto(`../${id}`)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Go to first screen
|
// Get valid asset type
|
||||||
if ($params.assetType === FrontendTypes.SCREEN) {
|
let assetType = $params.assetType
|
||||||
// Try to use previously selected layout first
|
if (![FrontendTypes.LAYOUT, FrontendTypes.SCREEN].includes(assetType)) {
|
||||||
let id
|
assetType = FrontendTypes.SCREEN
|
||||||
if (
|
|
||||||
$store.selectedScreenId &&
|
|
||||||
$allScreens.find(screen => screen._id === $store.selectedScreenId)
|
|
||||||
) {
|
|
||||||
id = $store.selectedScreenId
|
|
||||||
} else {
|
|
||||||
id = $allScreens[0]?._id
|
|
||||||
}
|
}
|
||||||
$goto(`../${id}`)
|
|
||||||
}
|
// Get ID or first correct asset type
|
||||||
|
if (assetType === FrontendTypes.LAYOUT) {
|
||||||
|
if (
|
||||||
|
$store.selectedLayoutId &&
|
||||||
|
$store.layouts.find(layout => layout._id === $store.selectedLayoutId)
|
||||||
|
) {
|
||||||
|
id = $store.selectedLayoutId
|
||||||
|
} else {
|
||||||
|
id = $store.layouts[0]?._id
|
||||||
|
}
|
||||||
|
} else if (assetType === FrontendTypes.SCREEN) {
|
||||||
|
if (
|
||||||
|
$store.selectedScreenId &&
|
||||||
|
$allScreens.find(screen => screen._id === $store.selectedScreenId)
|
||||||
|
) {
|
||||||
|
id = $store.selectedScreenId
|
||||||
|
} else {
|
||||||
|
id = $allScreens[0]?._id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send correct URL which will then update state
|
||||||
|
if (id) {
|
||||||
|
$goto(`../../${assetType}/${id}`)
|
||||||
|
}
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<!-- routify:options index=false -->
|
<!-- routify:options index=false -->
|
||||||
|
|
Loading…
Reference in New Issue