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

View File

@ -1,49 +1,61 @@
<script>
import { peekStore, dataSourceStore, routeStore } from "../store"
import { peekStore, dataSourceStore, notificationStore } from "../store"
import { Modal, ModalContent, Button } from "@budibase/bbui"
import { onDestroy } from "svelte"
let iframe
let fullscreen = false
let listenersAttached = false
const invalidateDataSource = event => {
const { dataSourceId } = event.detail
dataSourceStore.actions.invalidateDataSource(dataSourceId)
}
const handleCancel = () => {
iframe.contentWindow.removeEventListener(
"invalidate-datasource",
invalidateDataSource
)
peekStore.actions.hidePeek()
fullscreen = false
const proxyNotification = event => {
const { message, type, icon } = event.detail
notificationStore.actions.send(message, type, icon)
}
const navigate = () => {
if ($peekStore.external) {
window.location = $peekStore.href
} else {
routeStore.actions.navigate($peekStore.url)
}
peekStore.actions.hidePeek()
}
$: {
if (iframe) {
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 = () => {
peekStore.actions.hidePeek()
iframe.contentWindow.removeEventListener(
"invalidate-datasource",
invalidateDataSource
)
iframe.contentWindow.removeEventListener(
"close-screen-peek",
peekStore.actions.hidePeek
)
iframe.contentWindow.removeEventListener("notification", proxyNotification)
}
$: {
if (iframe && !listenersAttached) {
attachListeners()
listenersAttached = true
} else if (!iframe) {
listenersAttached = false
}
}
onDestroy(() => {
if (iframe) {
iframe.contentWindow.removeEventListener(
"invalidate-datasource",
invalidateDataSource
)
handleCancel()
}
})
</script>
@ -53,7 +65,7 @@
<ModalContent
showCancelButton={false}
showConfirmButton={false}
size="XL"
size="L"
showDivider={false}
showCloseIcon={false}
>

View File

@ -1,5 +1,6 @@
import { writable, get } from "svelte/store"
import { generate } from "shortid"
import { routeStore } from "./routes"
const NOTIFICATION_TIMEOUT = 3000
@ -22,6 +23,17 @@ const createNotificationStore = () => {
if (block) {
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({
id: generate(),
type,
@ -38,6 +50,7 @@ const createNotificationStore = () => {
return {
subscribe: store.subscribe,
actions: {
send,
info: msg => send(msg, "info", "Info"),
success: msg => send(msg, "success", "CheckmarkCircle"),
warning: msg => send(msg, "warning", "Alert"),

View File

@ -44,7 +44,12 @@ const createRouteStore = () => {
}
const setQueryParams = queryParams => {
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
})
}

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 = {
["Save Row"]: saveRowHandler,
["Delete Row"]: deleteRowHandler,
@ -109,6 +115,7 @@ const handlerMap = {
["Refresh Datasource"]: refreshDatasourceHandler,
["Log Out"]: logoutHandler,
["Clear Form"]: clearFormHandler,
["Close Screen-Peek Modal"]: closeScreenPeekModalHandler,
}
const confirmTextMap = {