Add action to close peek modal and proxy notifications from the iframe

This commit is contained in:
Andrew Kingston 2021-08-02 15:12:38 +01:00
parent 3916b735a1
commit def7f7a949
6 changed files with 83 additions and 24 deletions

View File

@ -0,0 +1,17 @@
<script>
import { Body } from "@budibase/bbui"
</script>
<div class="root">
<Body size="S">This action doesn't require any additional settings.</Body>
<Body size="S">
This action won't do anything if there isn't a screen-peek modal open.
</Body>
</div>
<style>
.root {
max-width: 800px;
margin: 0 auto;
}
</style>

View File

@ -6,6 +6,7 @@ import TriggerAutomation from "./TriggerAutomation.svelte"
import ValidateForm from "./ValidateForm.svelte" import ValidateForm from "./ValidateForm.svelte"
import LogOut from "./LogOut.svelte" import LogOut from "./LogOut.svelte"
import ClearForm from "./ClearForm.svelte" import ClearForm from "./ClearForm.svelte"
import CloseScreenPeekModal from "./CloseScreenPeekModal.svelte"
// Defines which actions are available to configure in the front end. // Defines which actions are available to configure in the front end.
// Unfortunately the "name" property is used as the identifier so please don't // Unfortunately the "name" property is used as the identifier so please don't
@ -47,4 +48,8 @@ export default [
name: "Clear Form", name: "Clear Form",
component: ClearForm, component: ClearForm,
}, },
{
name: "Close Screen-Peek Modal",
component: CloseScreenPeekModal,
},
] ]

View File

@ -1,49 +1,61 @@
<script> <script>
import { peekStore, dataSourceStore, routeStore } from "../store" import { peekStore, dataSourceStore, notificationStore } from "../store"
import { Modal, ModalContent, Button } from "@budibase/bbui" import { Modal, ModalContent, Button } from "@budibase/bbui"
import { onDestroy } from "svelte" import { onDestroy } from "svelte"
let iframe let iframe
let fullscreen = false let listenersAttached = false
const invalidateDataSource = event => { const invalidateDataSource = event => {
const { dataSourceId } = event.detail const { dataSourceId } = event.detail
dataSourceStore.actions.invalidateDataSource(dataSourceId) dataSourceStore.actions.invalidateDataSource(dataSourceId)
} }
const proxyNotification = event => {
const { message, type, icon } = event.detail
notificationStore.actions.send(message, type, icon)
}
const attachListeners = () => {
// Mirror datasource invalidation to keep the parent window up to date
iframe.contentWindow.addEventListener(
"invalidate-datasource",
invalidateDataSource
)
// Listen for a close event to close the screen peek
iframe.contentWindow.addEventListener(
"close-screen-peek",
peekStore.actions.hidePeek
)
// Proxy notifications back to the parent window instead of iframe
iframe.contentWindow.addEventListener("notification", proxyNotification)
}
const handleCancel = () => { const handleCancel = () => {
peekStore.actions.hidePeek()
iframe.contentWindow.removeEventListener( iframe.contentWindow.removeEventListener(
"invalidate-datasource", "invalidate-datasource",
invalidateDataSource invalidateDataSource
) )
peekStore.actions.hidePeek() iframe.contentWindow.removeEventListener(
fullscreen = false "close-screen-peek",
} peekStore.actions.hidePeek
)
const navigate = () => { iframe.contentWindow.removeEventListener("notification", proxyNotification)
if ($peekStore.external) {
window.location = $peekStore.href
} else {
routeStore.actions.navigate($peekStore.url)
}
peekStore.actions.hidePeek()
} }
$: { $: {
if (iframe) { if (iframe && !listenersAttached) {
iframe.contentWindow.addEventListener( attachListeners()
"invalidate-datasource", listenersAttached = true
invalidateDataSource } else if (!iframe) {
) listenersAttached = false
} }
} }
onDestroy(() => { onDestroy(() => {
if (iframe) { if (iframe) {
iframe.contentWindow.removeEventListener( handleCancel()
"invalidate-datasource",
invalidateDataSource
)
} }
}) })
</script> </script>
@ -53,7 +65,7 @@
<ModalContent <ModalContent
showCancelButton={false} showCancelButton={false}
showConfirmButton={false} showConfirmButton={false}
size="XL" size="L"
showDivider={false} showDivider={false}
showCloseIcon={false} showCloseIcon={false}
> >

View File

@ -1,5 +1,6 @@
import { writable, get } from "svelte/store" import { writable, get } from "svelte/store"
import { generate } from "shortid" import { generate } from "shortid"
import { routeStore } from "./routes"
const NOTIFICATION_TIMEOUT = 3000 const NOTIFICATION_TIMEOUT = 3000
@ -22,6 +23,17 @@ const createNotificationStore = () => {
if (block) { if (block) {
return return
} }
// If peeking, pass notifications back to parent window
if (get(routeStore).queryParams?.peek) {
window.dispatchEvent(
new CustomEvent("notification", {
detail: { message, type, icon },
})
)
return
}
store.set({ store.set({
id: generate(), id: generate(),
type, type,
@ -38,6 +50,7 @@ const createNotificationStore = () => {
return { return {
subscribe: store.subscribe, subscribe: store.subscribe,
actions: { actions: {
send,
info: msg => send(msg, "info", "Info"), info: msg => send(msg, "info", "Info"),
success: msg => send(msg, "success", "CheckmarkCircle"), success: msg => send(msg, "success", "CheckmarkCircle"),
warning: msg => send(msg, "warning", "Alert"), warning: msg => send(msg, "warning", "Alert"),

View File

@ -44,7 +44,12 @@ const createRouteStore = () => {
} }
const setQueryParams = queryParams => { const setQueryParams = queryParams => {
store.update(state => { store.update(state => {
state.queryParams = queryParams state.queryParams = {
...queryParams,
// Never unset the peek param - screen peek modals should always be
// in a peek state, even if they navigate to a different page
peek: queryParams.peek || state.queryParams?.peek,
}
return state return state
}) })
} }

View File

@ -99,6 +99,12 @@ const clearFormHandler = async (action, context) => {
) )
} }
const closeScreenPeekModalHandler = () => {
// Emit this as a window event, so parent screens which are iframing us in
// can close the modal
window.dispatchEvent(new Event("close-screen-peek"))
}
const handlerMap = { const handlerMap = {
["Save Row"]: saveRowHandler, ["Save Row"]: saveRowHandler,
["Delete Row"]: deleteRowHandler, ["Delete Row"]: deleteRowHandler,
@ -109,6 +115,7 @@ const handlerMap = {
["Refresh Datasource"]: refreshDatasourceHandler, ["Refresh Datasource"]: refreshDatasourceHandler,
["Log Out"]: logoutHandler, ["Log Out"]: logoutHandler,
["Clear Form"]: clearFormHandler, ["Clear Form"]: clearFormHandler,
["Close Screen-Peek Modal"]: closeScreenPeekModalHandler,
} }
const confirmTextMap = { const confirmTextMap = {