Merge pull request #6409 from Budibase/useful-features

"On screen load" actions & query params binding
This commit is contained in:
Andrew Kingston 2022-06-22 08:49:51 +01:00 committed by GitHub
commit 1811926515
5 changed files with 138 additions and 89 deletions

View File

@ -390,11 +390,17 @@ const getUrlBindings = asset => {
}
})
const safeURL = makePropSafe("url")
return params.map(param => ({
const urlParamBindings = params.map(param => ({
type: "context",
runtimeBinding: `${safeURL}.${makePropSafe(param)}`,
readableBinding: `URL.${param}`,
}))
const queryParamsBinding = {
type: "context",
runtimeBinding: makePropSafe("query"),
readableBinding: "Query params",
}
return urlParamBindings.concat([queryParamsBinding])
}
const getRoleBindings = () => {
@ -694,6 +700,13 @@ export const getAllStateVariables = () => {
})
})
// Add on load settings from screens
get(store).screens.forEach(screen => {
if (screen.onLoad) {
eventSettings.push(screen.onLoad)
}
})
// Extract all state keys from any "update state" actions in each setting
let bindingSet = new Set()
eventSettings.forEach(setting => {

View File

@ -17,6 +17,10 @@
import { selectedScreen, store } from "builderStore"
import sanitizeUrl from "builderStore/store/screenTemplates/utils/sanitizeUrl"
import { goto } from "@roxi/routify"
import ButtonActionEditor from "components/design/settings/controls/ButtonActionEditor/ButtonActionEditor.svelte"
import { getBindableProperties } from "builderStore/dataBinding"
$: bindings = getBindableProperties($selectedScreen, null)
let errors = {}
@ -147,6 +151,11 @@
disabled: !!$selectedScreen.layoutId,
},
},
{
key: "onLoad",
label: "On screen load",
control: ButtonActionEditor,
},
]
const removeCustomLayout = async () => {
@ -178,6 +187,7 @@
value={deepGet($selectedScreen, setting.key)}
onChange={val => setScreenSetting(setting, val)}
props={{ ...setting.props, error: errors[setting.key] }}
{bindings}
/>
{/each}
<Button cta on:click={() => $goto("../components")}>View components</Button>

View File

@ -24,6 +24,7 @@
import DeviceBindingsProvider from "components/context/DeviceBindingsProvider.svelte"
import StateBindingsProvider from "components/context/StateBindingsProvider.svelte"
import RowSelectionProvider from "components/context/RowSelectionProvider.svelte"
import QueryParamsProvider from "components/context/QueryParamsProvider.svelte"
import SettingsBar from "components/preview/SettingsBar.svelte"
import SelectionIndicator from "components/preview/SelectionIndicator.svelte"
import HoverIndicator from "components/preview/HoverIndicator.svelte"
@ -94,95 +95,97 @@
<UserBindingsProvider>
<StateBindingsProvider>
<RowSelectionProvider>
<!-- Settings bar can be rendered outside of device preview -->
<!-- Key block needs to be outside the if statement or it breaks -->
{#key $builderStore.selectedComponentId}
{#if $builderStore.inBuilder}
<SettingsBar />
{/if}
{/key}
<!-- Clip boundary for selection indicators -->
<div
id="clip-root"
class:preview={$builderStore.inBuilder}
class:tablet-preview={$builderStore.previewDevice === "tablet"}
class:mobile-preview={$builderStore.previewDevice === "mobile"}
>
<!-- Actual app -->
<div id="app-root">
{#if showDevTools}
<DevToolsHeader />
<QueryParamsProvider>
<!-- Settings bar can be rendered outside of device preview -->
<!-- Key block needs to be outside the if statement or it breaks -->
{#key $builderStore.selectedComponentId}
{#if $builderStore.inBuilder}
<SettingsBar />
{/if}
{/key}
<div id="app-body">
{#if permissionError}
<div class="error">
<Layout justifyItems="center" gap="S">
{@html ErrorSVG}
<Heading size="L">
You don't have permission to use this app
</Heading>
<Body size="S">
Ask your administrator to grant you access
</Body>
</Layout>
</div>
{:else if !$screenStore.activeLayout}
<div class="error">
<Layout justifyItems="center" gap="S">
{@html ErrorSVG}
<Heading size="L">
Something went wrong rendering your app
</Heading>
<Body size="S">
Get in touch with support if this issue persists
</Body>
</Layout>
</div>
{:else}
<CustomThemeWrapper>
{#key $screenStore.activeLayout._id}
<Component
isLayout
instance={$screenStore.activeLayout.props}
/>
{/key}
<!--
Flatpickr needs to be inside the theme wrapper.
It also needs its own container because otherwise it hijacks
key events on the whole page. It is painful to work with.
-->
<div id="flatpickr-root" />
<!-- Modal container to ensure they sit on top -->
<div class="modal-container" />
<!-- Layers on top of app -->
<NotificationDisplay />
<ConfirmationDisplay />
<PeekScreenDisplay />
</CustomThemeWrapper>
{/if}
<!-- Clip boundary for selection indicators -->
<div
id="clip-root"
class:preview={$builderStore.inBuilder}
class:tablet-preview={$builderStore.previewDevice === "tablet"}
class:mobile-preview={$builderStore.previewDevice === "mobile"}
>
<!-- Actual app -->
<div id="app-root">
{#if showDevTools}
<DevTools />
<DevToolsHeader />
{/if}
</div>
</div>
<!-- Preview and dev tools utilities -->
{#if $appStore.isDevApp}
<SelectionIndicator />
{/if}
{#if $builderStore.inBuilder || $devToolsStore.allowSelection}
<HoverIndicator />
{/if}
{#if $builderStore.inBuilder}
<DNDHandler />
{/if}
</div>
<div id="app-body">
{#if permissionError}
<div class="error">
<Layout justifyItems="center" gap="S">
{@html ErrorSVG}
<Heading size="L">
You don't have permission to use this app
</Heading>
<Body size="S">
Ask your administrator to grant you access
</Body>
</Layout>
</div>
{:else if !$screenStore.activeLayout}
<div class="error">
<Layout justifyItems="center" gap="S">
{@html ErrorSVG}
<Heading size="L">
Something went wrong rendering your app
</Heading>
<Body size="S">
Get in touch with support if this issue persists
</Body>
</Layout>
</div>
{:else}
<CustomThemeWrapper>
{#key $screenStore.activeLayout._id}
<Component
isLayout
instance={$screenStore.activeLayout.props}
/>
{/key}
<!--
Flatpickr needs to be inside the theme wrapper.
It also needs its own container because otherwise it hijacks
key events on the whole page. It is painful to work with.
-->
<div id="flatpickr-root" />
<!-- Modal container to ensure they sit on top -->
<div class="modal-container" />
<!-- Layers on top of app -->
<NotificationDisplay />
<ConfirmationDisplay />
<PeekScreenDisplay />
</CustomThemeWrapper>
{/if}
{#if showDevTools}
<DevTools />
{/if}
</div>
</div>
<!-- Preview and dev tools utilities -->
{#if $appStore.isDevApp}
<SelectionIndicator />
{/if}
{#if $builderStore.inBuilder || $devToolsStore.allowSelection}
<HoverIndicator />
{/if}
{#if $builderStore.inBuilder}
<DNDHandler />
{/if}
</div>
</QueryParamsProvider>
</RowSelectionProvider>
</StateBindingsProvider>
</UserBindingsProvider>

View File

@ -1,21 +1,36 @@
<script>
import { screenStore, routeStore } from "stores"
import { screenStore, routeStore, builderStore } from "stores"
import Component from "./Component.svelte"
import Provider from "./context/Provider.svelte"
import { onMount } from "svelte"
import { onMount, getContext } from "svelte"
import { enrichButtonActions } from "utils/buttonActions.js"
export let params = {}
const context = getContext("context")
// Keep route params up to date
export let params = {}
$: routeStore.actions.setRouteParams(params || {})
// Get the screen definition for the current route
$: screenDefinition = $screenStore.activeScreen?.props
// Mark the router as loaded whenever the screen mounts
onMount(() => {
// Mark the router as loaded whenever the screen mounts
if (!$routeStore.routerLoaded) {
routeStore.actions.setRouterLoaded()
}
// Enrich and execute and on load actions.
// We manually construct the full context here as this component is the
// one that provides the url context, so it is not available in $context yet
if ($screenStore.activeScreen?.onLoad && !$builderStore.inBuilder) {
const actions = enrichButtonActions($screenStore.activeScreen.onLoad, {
...$context,
url: params,
})
actions()
}
})
</script>

View File

@ -0,0 +1,8 @@
<script>
import Provider from "./Provider.svelte"
import { routeStore } from "stores"
</script>
<Provider key="query" data={$routeStore.queryParams}>
<slot />
</Provider>