Merge pull request #6409 from Budibase/useful-features
"On screen load" actions & query params binding
This commit is contained in:
commit
df839e7aa8
|
@ -390,11 +390,17 @@ const getUrlBindings = asset => {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
const safeURL = makePropSafe("url")
|
const safeURL = makePropSafe("url")
|
||||||
return params.map(param => ({
|
const urlParamBindings = params.map(param => ({
|
||||||
type: "context",
|
type: "context",
|
||||||
runtimeBinding: `${safeURL}.${makePropSafe(param)}`,
|
runtimeBinding: `${safeURL}.${makePropSafe(param)}`,
|
||||||
readableBinding: `URL.${param}`,
|
readableBinding: `URL.${param}`,
|
||||||
}))
|
}))
|
||||||
|
const queryParamsBinding = {
|
||||||
|
type: "context",
|
||||||
|
runtimeBinding: makePropSafe("query"),
|
||||||
|
readableBinding: "Query params",
|
||||||
|
}
|
||||||
|
return urlParamBindings.concat([queryParamsBinding])
|
||||||
}
|
}
|
||||||
|
|
||||||
const getRoleBindings = () => {
|
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
|
// Extract all state keys from any "update state" actions in each setting
|
||||||
let bindingSet = new Set()
|
let bindingSet = new Set()
|
||||||
eventSettings.forEach(setting => {
|
eventSettings.forEach(setting => {
|
||||||
|
|
|
@ -17,6 +17,10 @@
|
||||||
import { selectedScreen, store } from "builderStore"
|
import { selectedScreen, store } from "builderStore"
|
||||||
import sanitizeUrl from "builderStore/store/screenTemplates/utils/sanitizeUrl"
|
import sanitizeUrl from "builderStore/store/screenTemplates/utils/sanitizeUrl"
|
||||||
import { goto } from "@roxi/routify"
|
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 = {}
|
let errors = {}
|
||||||
|
|
||||||
|
@ -147,6 +151,11 @@
|
||||||
disabled: !!$selectedScreen.layoutId,
|
disabled: !!$selectedScreen.layoutId,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
key: "onLoad",
|
||||||
|
label: "On screen load",
|
||||||
|
control: ButtonActionEditor,
|
||||||
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
const removeCustomLayout = async () => {
|
const removeCustomLayout = async () => {
|
||||||
|
@ -178,6 +187,7 @@
|
||||||
value={deepGet($selectedScreen, setting.key)}
|
value={deepGet($selectedScreen, setting.key)}
|
||||||
onChange={val => setScreenSetting(setting, val)}
|
onChange={val => setScreenSetting(setting, val)}
|
||||||
props={{ ...setting.props, error: errors[setting.key] }}
|
props={{ ...setting.props, error: errors[setting.key] }}
|
||||||
|
{bindings}
|
||||||
/>
|
/>
|
||||||
{/each}
|
{/each}
|
||||||
<Button cta on:click={() => $goto("../components")}>View components</Button>
|
<Button cta on:click={() => $goto("../components")}>View components</Button>
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
import DeviceBindingsProvider from "components/context/DeviceBindingsProvider.svelte"
|
import DeviceBindingsProvider from "components/context/DeviceBindingsProvider.svelte"
|
||||||
import StateBindingsProvider from "components/context/StateBindingsProvider.svelte"
|
import StateBindingsProvider from "components/context/StateBindingsProvider.svelte"
|
||||||
import RowSelectionProvider from "components/context/RowSelectionProvider.svelte"
|
import RowSelectionProvider from "components/context/RowSelectionProvider.svelte"
|
||||||
|
import QueryParamsProvider from "components/context/QueryParamsProvider.svelte"
|
||||||
import SettingsBar from "components/preview/SettingsBar.svelte"
|
import SettingsBar from "components/preview/SettingsBar.svelte"
|
||||||
import SelectionIndicator from "components/preview/SelectionIndicator.svelte"
|
import SelectionIndicator from "components/preview/SelectionIndicator.svelte"
|
||||||
import HoverIndicator from "components/preview/HoverIndicator.svelte"
|
import HoverIndicator from "components/preview/HoverIndicator.svelte"
|
||||||
|
@ -94,95 +95,97 @@
|
||||||
<UserBindingsProvider>
|
<UserBindingsProvider>
|
||||||
<StateBindingsProvider>
|
<StateBindingsProvider>
|
||||||
<RowSelectionProvider>
|
<RowSelectionProvider>
|
||||||
<!-- Settings bar can be rendered outside of device preview -->
|
<QueryParamsProvider>
|
||||||
<!-- Key block needs to be outside the if statement or it breaks -->
|
<!-- Settings bar can be rendered outside of device preview -->
|
||||||
{#key $builderStore.selectedComponentId}
|
<!-- Key block needs to be outside the if statement or it breaks -->
|
||||||
{#if $builderStore.inBuilder}
|
{#key $builderStore.selectedComponentId}
|
||||||
<SettingsBar />
|
{#if $builderStore.inBuilder}
|
||||||
{/if}
|
<SettingsBar />
|
||||||
{/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 />
|
|
||||||
{/if}
|
{/if}
|
||||||
|
{/key}
|
||||||
|
|
||||||
<div id="app-body">
|
<!-- Clip boundary for selection indicators -->
|
||||||
{#if permissionError}
|
<div
|
||||||
<div class="error">
|
id="clip-root"
|
||||||
<Layout justifyItems="center" gap="S">
|
class:preview={$builderStore.inBuilder}
|
||||||
{@html ErrorSVG}
|
class:tablet-preview={$builderStore.previewDevice === "tablet"}
|
||||||
<Heading size="L">
|
class:mobile-preview={$builderStore.previewDevice === "mobile"}
|
||||||
You don't have permission to use this app
|
>
|
||||||
</Heading>
|
<!-- Actual app -->
|
||||||
<Body size="S">
|
<div id="app-root">
|
||||||
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}
|
{#if showDevTools}
|
||||||
<DevTools />
|
<DevToolsHeader />
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Preview and dev tools utilities -->
|
<div id="app-body">
|
||||||
{#if $appStore.isDevApp}
|
{#if permissionError}
|
||||||
<SelectionIndicator />
|
<div class="error">
|
||||||
{/if}
|
<Layout justifyItems="center" gap="S">
|
||||||
{#if $builderStore.inBuilder || $devToolsStore.allowSelection}
|
{@html ErrorSVG}
|
||||||
<HoverIndicator />
|
<Heading size="L">
|
||||||
{/if}
|
You don't have permission to use this app
|
||||||
{#if $builderStore.inBuilder}
|
</Heading>
|
||||||
<DNDHandler />
|
<Body size="S">
|
||||||
{/if}
|
Ask your administrator to grant you access
|
||||||
</div>
|
</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>
|
</RowSelectionProvider>
|
||||||
</StateBindingsProvider>
|
</StateBindingsProvider>
|
||||||
</UserBindingsProvider>
|
</UserBindingsProvider>
|
||||||
|
|
|
@ -1,21 +1,36 @@
|
||||||
<script>
|
<script>
|
||||||
import { screenStore, routeStore } from "stores"
|
import { screenStore, routeStore, builderStore } from "stores"
|
||||||
import Component from "./Component.svelte"
|
import Component from "./Component.svelte"
|
||||||
import Provider from "./context/Provider.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
|
// Keep route params up to date
|
||||||
export let params = {}
|
|
||||||
$: routeStore.actions.setRouteParams(params || {})
|
$: routeStore.actions.setRouteParams(params || {})
|
||||||
|
|
||||||
// Get the screen definition for the current route
|
// Get the screen definition for the current route
|
||||||
$: screenDefinition = $screenStore.activeScreen?.props
|
$: screenDefinition = $screenStore.activeScreen?.props
|
||||||
|
|
||||||
// Mark the router as loaded whenever the screen mounts
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
|
// Mark the router as loaded whenever the screen mounts
|
||||||
if (!$routeStore.routerLoaded) {
|
if (!$routeStore.routerLoaded) {
|
||||||
routeStore.actions.setRouterLoaded()
|
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>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
<script>
|
||||||
|
import Provider from "./Provider.svelte"
|
||||||
|
import { routeStore } from "stores"
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<Provider key="query" data={$routeStore.queryParams}>
|
||||||
|
<slot />
|
||||||
|
</Provider>
|
Loading…
Reference in New Issue