Make block ejection work properly via the builder rather than client app button hack
This commit is contained in:
parent
25454bff9d
commit
80bcfd2692
|
@ -354,6 +354,16 @@ export const getFrontendStore = () => {
|
||||||
return state
|
return state
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
sendEvent: (name, payload) => {
|
||||||
|
const { previewEventHandler } = get(store)
|
||||||
|
previewEventHandler?.(name, payload)
|
||||||
|
},
|
||||||
|
registerEventHandler: handler => {
|
||||||
|
store.update(state => {
|
||||||
|
state.previewEventHandler = handler
|
||||||
|
return state
|
||||||
|
})
|
||||||
|
},
|
||||||
},
|
},
|
||||||
layouts: {
|
layouts: {
|
||||||
select: layoutId => {
|
select: layoutId => {
|
||||||
|
@ -895,7 +905,12 @@ export const getFrontendStore = () => {
|
||||||
component[name] = value
|
component[name] = value
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
ejectBlock: async (componentId, ejectedDefinition) => {
|
requestEjectBlock: componentId => {
|
||||||
|
store.actions.preview.sendEvent("eject-block", componentId)
|
||||||
|
},
|
||||||
|
handleEjectBlock: async (componentId, ejectedDefinition) => {
|
||||||
|
let nextSelectedComponentId
|
||||||
|
|
||||||
await store.actions.screens.patch(screen => {
|
await store.actions.screens.patch(screen => {
|
||||||
const parent = findComponentParent(screen.props, componentId)
|
const parent = findComponentParent(screen.props, componentId)
|
||||||
|
|
||||||
|
@ -908,8 +923,18 @@ export const getFrontendStore = () => {
|
||||||
const childIndex = parent._children.findIndex(
|
const childIndex = parent._children.findIndex(
|
||||||
child => child._id === componentId
|
child => child._id === componentId
|
||||||
)
|
)
|
||||||
|
makeComponentUnique(ejectedDefinition)
|
||||||
parent._children[childIndex] = ejectedDefinition
|
parent._children[childIndex] = ejectedDefinition
|
||||||
|
nextSelectedComponentId = ejectedDefinition._id
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Select new root component
|
||||||
|
if (nextSelectedComponentId) {
|
||||||
|
store.update(state => {
|
||||||
|
state.selectedComponentId = nextSelectedComponentId
|
||||||
|
return state
|
||||||
|
})
|
||||||
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
links: {
|
links: {
|
||||||
|
|
|
@ -96,11 +96,21 @@
|
||||||
`./components/${$selectedComponent?._id}/new`
|
`./components/${$selectedComponent?._id}/new`
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Register handler to send custom to the preview
|
||||||
|
$: store.actions.preview.registerEventHandler((name, payload) => {
|
||||||
|
iframe?.contentWindow.postMessage(
|
||||||
|
JSON.stringify({
|
||||||
|
name,
|
||||||
|
payload,
|
||||||
|
isBudibaseEvent: true,
|
||||||
|
runtimeEvent: true,
|
||||||
|
})
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
// Update the iframe with the builder info to render the correct preview
|
// Update the iframe with the builder info to render the correct preview
|
||||||
const refreshContent = message => {
|
const refreshContent = message => {
|
||||||
if (iframe) {
|
iframe?.contentWindow.postMessage(message)
|
||||||
iframe.contentWindow.postMessage(message)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const receiveMessage = message => {
|
const receiveMessage = message => {
|
||||||
|
@ -198,7 +208,7 @@
|
||||||
}
|
}
|
||||||
} else if (type === "eject-block") {
|
} else if (type === "eject-block") {
|
||||||
const { id, definition } = data
|
const { id, definition } = data
|
||||||
await store.actions.components.ejectBlock(id, definition)
|
await store.actions.components.handleEjectBlock(id, definition)
|
||||||
} else {
|
} else {
|
||||||
console.warn(`Client sent unknown event type: ${type}`)
|
console.warn(`Client sent unknown event type: ${type}`)
|
||||||
}
|
}
|
||||||
|
|
|
@ -112,9 +112,9 @@
|
||||||
} else if (e.key === "Enter") {
|
} else if (e.key === "Enter") {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
$goto("./new")
|
$goto("./new")
|
||||||
} else if (e.key === "Enter") {
|
} else if (e.key === "e") {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
await store.actions.components.ejectBlock()
|
await store.actions.components.requestEjectBlock(component?._id)
|
||||||
}
|
}
|
||||||
} else if (e.key === "Backspace" || e.key === "Delete") {
|
} else if (e.key === "Backspace" || e.key === "Delete") {
|
||||||
// Don't show confirmation for the screen itself
|
// Don't show confirmation for the screen itself
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
<script>
|
<script>
|
||||||
import { getContext, setContext } from "svelte"
|
import { getContext, onDestroy, onMount, setContext } from "svelte"
|
||||||
import { builderStore } from "../stores/builder.js"
|
import { builderStore } from "stores/builder.js"
|
||||||
|
import { blockStore } from "stores/blocks.js"
|
||||||
import { Button } from "@budibase/bbui"
|
import { Button } from "@budibase/bbui"
|
||||||
|
|
||||||
const component = getContext("component")
|
const component = getContext("component")
|
||||||
|
@ -55,6 +56,18 @@
|
||||||
// blocks later on
|
// blocks later on
|
||||||
registerComponent: registerBlockComponent,
|
registerComponent: registerBlockComponent,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
onMount(() => {
|
||||||
|
if ($builderStore.inBuilder) {
|
||||||
|
blockStore.actions.registerBlock($component.id, { eject })
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
onDestroy(() => {
|
||||||
|
if ($builderStore.inBuilder) {
|
||||||
|
blockStore.actions.unregisterBlock($component.id)
|
||||||
|
}
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<slot />
|
<slot />
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import ClientApp from "./components/ClientApp.svelte"
|
import ClientApp from "./components/ClientApp.svelte"
|
||||||
import { builderStore, appStore, devToolsStore } from "./stores"
|
import { builderStore, appStore, devToolsStore, blockStore } from "./stores"
|
||||||
import loadSpectrumIcons from "@budibase/bbui/spectrum-icons-rollup.js"
|
import loadSpectrumIcons from "@budibase/bbui/spectrum-icons-rollup.js"
|
||||||
import { get } from "svelte/store"
|
import { get } from "svelte/store"
|
||||||
|
|
||||||
|
@ -32,6 +32,17 @@ const loadBudibase = () => {
|
||||||
const enableDevTools = !get(builderStore).inBuilder && get(appStore).isDevApp
|
const enableDevTools = !get(builderStore).inBuilder && get(appStore).isDevApp
|
||||||
devToolsStore.actions.setEnabled(enableDevTools)
|
devToolsStore.actions.setEnabled(enableDevTools)
|
||||||
|
|
||||||
|
// Register handler for runtime events from the builder
|
||||||
|
window.handleBuilderRuntimeEvent = (name, payload) => {
|
||||||
|
if (!window["##BUDIBASE_IN_BUILDER##"]) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (name === "eject-block") {
|
||||||
|
const block = blockStore.actions.getBlock(payload)
|
||||||
|
block?.eject()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Create app if one hasn't been created yet
|
// Create app if one hasn't been created yet
|
||||||
if (!app) {
|
if (!app) {
|
||||||
app = new ClientApp({
|
app = new ClientApp({
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
import { get, writable } from "svelte/store"
|
||||||
|
|
||||||
|
const createBlockStore = () => {
|
||||||
|
const store = writable({})
|
||||||
|
|
||||||
|
const registerBlock = (id, instance) => {
|
||||||
|
store.update(state => ({
|
||||||
|
...state,
|
||||||
|
[id]: instance,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
const unregisterBlock = id => {
|
||||||
|
store.update(state => {
|
||||||
|
delete state[id]
|
||||||
|
return state
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const getBlock = id => {
|
||||||
|
return get(store)[id]
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
subscribe: store.subscribe,
|
||||||
|
actions: {
|
||||||
|
registerBlock,
|
||||||
|
unregisterBlock,
|
||||||
|
getBlock,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const blockStore = createBlockStore()
|
|
@ -17,6 +17,7 @@ export { devToolsStore } from "./devTools"
|
||||||
export { componentStore } from "./components"
|
export { componentStore } from "./components"
|
||||||
export { uploadStore } from "./uploads.js"
|
export { uploadStore } from "./uploads.js"
|
||||||
export { rowSelectionStore } from "./rowSelection.js"
|
export { rowSelectionStore } from "./rowSelection.js"
|
||||||
|
export { blockStore } from "./blocks.js"
|
||||||
|
|
||||||
// Context stores are layered and duplicated, so it is not a singleton
|
// Context stores are layered and duplicated, so it is not a singleton
|
||||||
export { createContextStore } from "./context"
|
export { createContextStore } from "./context"
|
||||||
|
|
|
@ -56,6 +56,16 @@
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If this is a custom event, try and handle it
|
||||||
|
if (parsed.runtimeEvent) {
|
||||||
|
const { name, payload } = parsed
|
||||||
|
if (window.handleBuilderRuntimeEvent) {
|
||||||
|
window.handleBuilderRuntimeEvent(name, payload)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise this is a full reload message
|
||||||
// Extract data from message
|
// Extract data from message
|
||||||
const {
|
const {
|
||||||
selectedComponentId,
|
selectedComponentId,
|
||||||
|
|
Loading…
Reference in New Issue