Merge pull request #10844 from Budibase/cheeks-lab-day-preview

Preview apps inside builder
This commit is contained in:
Andrew Kingston 2023-06-13 15:15:29 +01:00 committed by GitHub
commit cfe86194cd
13 changed files with 168 additions and 44 deletions

View File

@ -74,6 +74,7 @@ const INITIAL_FRONTEND_STATE = {
propertyFocus: null,
builderSidePanel: false,
hasLock: true,
showPreview: false,
// URL params
selectedScreenId: null,

View File

@ -69,7 +69,7 @@
name: "App",
description: "",
icon: "Play",
action: () => window.open(`/${$store.appId}`),
action: () => store.update(state => ({ ...state, showPreview: true })),
},
{
type: "Preview",

View File

@ -62,7 +62,10 @@
}
const previewApp = () => {
window.open(`/${application}`)
store.update(state => ({
...state,
showPreview: true,
}))
}
const viewApp = () => {

View File

@ -0,0 +1,91 @@
<script>
import { onMount } from "svelte"
import { fade, fly } from "svelte/transition"
import { store, selectedScreen } from "builderStore"
import { ProgressCircle } from "@budibase/bbui"
$: route = $selectedScreen?.routing.route || "/"
$: src = `/${$store.appId}#${route}`
const close = () => {
store.update(state => ({
...state,
showPreview: false,
}))
}
onMount(() => {
window.closePreview = () => {
store.update(state => ({
...state,
showPreview: false,
}))
}
})
</script>
<div
class="preview-overlay"
transition:fade={{ duration: 260 }}
on:click|self={close}
>
<div
class="container spectrum {$store.theme}"
transition:fly={{ duration: 260, y: 130 }}
>
<div class="header placeholder" />
<div class="loading placeholder">
<ProgressCircle />
</div>
<iframe title="Budibase App Preview" {src} />
</div>
</div>
<style>
.preview-overlay {
top: 0;
right: 0;
left: 0;
bottom: 0;
z-index: 999;
position: absolute;
background: rgba(255, 255, 255, 0.1);
display: flex;
align-items: stretch;
padding: 48px;
}
.container {
flex: 1 1 auto;
background: var(--spectrum-global-color-gray-75);
border-radius: 4px;
display: flex;
flex-direction: column;
overflow: hidden;
position: relative;
box-shadow: 0 0 80px 0 rgba(0, 0, 0, 0.5);
}
iframe {
position: absolute;
height: 100%;
width: 100%;
border: none;
outline: none;
z-index: 1;
}
.header {
height: 60px;
width: 100%;
background: black;
top: 0;
position: absolute;
}
.loading {
position: absolute;
top: 50%;
left: 50%;
transform: translateY(-50%) translateX(-50%);
}
.placeholder {
z-index: 0;
}
</style>

View File

@ -24,6 +24,7 @@
import BuilderSidePanel from "./_components/BuilderSidePanel.svelte"
import UserAvatars from "./_components/UserAvatars.svelte"
import { TOUR_KEYS, TOURS } from "components/portal/onboarding/tours.js"
import PreviewOverlay from "./_components/PreviewOverlay.svelte"
export let application
@ -140,7 +141,7 @@
<BuilderSidePanel />
{/if}
<div class="root">
<div class="root" class:blur={$store.showPreview}>
<div class="top-nav">
{#if $store.initialised}
<div class="topleftnav">
@ -230,6 +231,10 @@
{/await}
</div>
{#if $store.showPreview}
<PreviewOverlay />
{/if}
<svelte:window on:keydown={handleKeyDown} />
<Modal bind:this={commandPaletteModal}>
<CommandPalette />
@ -248,6 +253,10 @@
width: 100%;
display: flex;
flex-direction: column;
transition: filter 260ms ease-out;
}
.root.blur {
filter: blur(8px);
}
.top-nav {

View File

@ -1,7 +1,6 @@
import { createAPIClient } from "@budibase/frontend-core"
import { notificationStore } from "../stores/notification.js"
import { authStore } from "../stores/auth.js"
import { devToolsStore } from "../stores/devTools.js"
import { notificationStore, devToolsEnabled, devToolsStore } from "../stores/"
import { get } from "svelte/store"
export const API = createAPIClient({
@ -25,9 +24,10 @@ export const API = createAPIClient({
}
// Add role header
const devToolsState = get(devToolsStore)
if (devToolsState.enabled && devToolsState.role) {
headers["x-budibase-role"] = devToolsState.role
const $devToolsStore = get(devToolsStore)
const $devToolsEnabled = get(devToolsEnabled)
if ($devToolsEnabled && $devToolsStore.role) {
headers["x-budibase-role"] = $devToolsStore.role
}
},

View File

@ -17,6 +17,7 @@
appStore,
devToolsStore,
environmentStore,
devToolsEnabled,
} from "stores"
import NotificationDisplay from "components/overlay/NotificationDisplay.svelte"
import ConfirmationDisplay from "components/overlay/ConfirmationDisplay.svelte"
@ -47,10 +48,7 @@
let permissionError = false
// Determine if we should show devtools or not
$: showDevTools =
!$builderStore.inBuilder &&
$devToolsStore.enabled &&
!$routeStore.queryParams?.peek
$: showDevTools = $devToolsEnabled && !$routeStore.queryParams?.peek
// Handle no matching route
$: {
@ -107,6 +105,7 @@
lang="en"
dir="ltr"
class="spectrum spectrum--medium {$themeStore.baseTheme} {$themeStore.theme}"
class:builder={$builderStore.inBuilder}
>
<DeviceBindingsProvider>
<UserBindingsProvider>
@ -223,12 +222,14 @@
overflow: hidden;
height: 100%;
width: 100%;
background: transparent;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
}
#spectrum-root.builder {
background: transparent;
}
#clip-root {
max-width: 100%;

View File

@ -1,5 +1,5 @@
<script>
import { Heading, Button, Select } from "@budibase/bbui"
import { Heading, Select, ActionButton } from "@budibase/bbui"
import { devToolsStore } from "../../stores"
import { getContext } from "svelte"
@ -30,7 +30,7 @@
</script>
<div class="dev-preview-header" class:mobile={$context.device.mobile}>
<Heading size="XS">Budibase App Preview</Heading>
<Heading size="XS">Preview</Heading>
<Select
quiet
options={previewOptions}
@ -40,36 +40,57 @@
on:change={e => devToolsStore.actions.changeRole(e.detail)}
/>
{#if !$context.device.mobile}
<Button
<ActionButton
quiet
overBackground
icon="Code"
on:click={() => devToolsStore.actions.setVisible(!$devToolsStore.visible)}
>
{$devToolsStore.visible ? "Close" : "Open"} DevTools
</Button>
</ActionButton>
{/if}
<ActionButton
quiet
icon="Close"
on:click={() => window.parent.closePreview?.()}
>
Close preview
</ActionButton>
</div>
<style>
.dev-preview-header {
flex: 0 0 50px;
height: 50px;
flex: 0 0 60px;
display: grid;
align-items: center;
background-color: var(--spectrum-global-color-blue-400);
background-color: black;
padding: 0 var(--spacing-xl);
grid-template-columns: 1fr auto auto;
grid-template-columns: 1fr auto auto auto;
grid-gap: var(--spacing-xl);
}
.dev-preview-header.mobile {
flex: 0 0 50px;
grid-template-columns: 1fr auto;
grid-template-columns: 1fr auto auto;
}
.dev-preview-header :global(.spectrum-Heading),
.dev-preview-header :global(.spectrum-Picker-menuIcon),
.dev-preview-header :global(.spectrum-Picker-label) {
color: white !important;
.dev-preview-header :global(.spectrum-Icon),
.dev-preview-header :global(.spectrum-Picker-label),
.dev-preview-header :global(.spectrum-ActionButton) {
font-weight: 600;
color: white;
}
.dev-preview-header :global(.spectrum-Picker) {
padding-left: 8px;
padding-right: 8px;
transition: background 130ms ease-out;
border-radius: 4px;
}
.dev-preview-header :global(.spectrum-ActionButton:hover),
.dev-preview-header :global(.spectrum-Picker:hover),
.dev-preview-header :global(.spectrum-Picker.is-open) {
background: rgba(255, 255, 255, 0.1);
}
.dev-preview-header :global(.spectrum-ActionButton:active) {
background: rgba(255, 255, 255, 0.2);
}
@media print {
.dev-preview-header {

View File

@ -2,7 +2,6 @@ import ClientApp from "./components/ClientApp.svelte"
import {
builderStore,
appStore,
devToolsStore,
blockStore,
componentStore,
environmentStore,
@ -51,11 +50,6 @@ const loadBudibase = async () => {
await environmentStore.actions.fetchEnvironment()
}
// Enable dev tools or not. We need to be using a dev app and not inside
// the builder preview to enable them.
const enableDevTools = !get(builderStore).inBuilder && get(appStore).isDevApp
devToolsStore.actions.setEnabled(enableDevTools)
// Register handler for runtime events from the builder
window.handleBuilderRuntimeEvent = (type, data) => {
if (!window["##BUDIBASE_IN_BUILDER##"]) {

View File

@ -2,13 +2,14 @@ import { derived } from "svelte/store"
import { Constants } from "@budibase/frontend-core"
import { devToolsStore } from "../devTools.js"
import { authStore } from "../auth.js"
import { devToolsEnabled } from "./devToolsEnabled.js"
// Derive the current role of the logged-in user
export const currentRole = derived(
[devToolsStore, authStore],
([$devToolsStore, $authStore]) => {
[devToolsEnabled, devToolsStore, authStore],
([$devToolsEnabled, $devToolsStore, $authStore]) => {
return (
($devToolsStore.enabled && $devToolsStore.role) ||
($devToolsEnabled && $devToolsStore.role) ||
$authStore?.roleId ||
Constants.Roles.PUBLIC
)

View File

@ -0,0 +1,10 @@
import { derived } from "svelte/store"
import { appStore } from "../app.js"
import { builderStore } from "../builder.js"
export const devToolsEnabled = derived(
[appStore, builderStore],
([$appStore, $builderStore]) => {
return !$builderStore.inBuilder && $appStore.isDevApp
}
)

View File

@ -3,3 +3,4 @@
// separately we can keep our actual stores lean and performant.
export { currentRole } from "./currentRole.js"
export { dndComponentPath } from "./dndComponentPath.js"
export { devToolsEnabled } from "./devToolsEnabled.js"

View File

@ -4,7 +4,6 @@ import { authStore } from "./auth"
import { API } from "../api"
const initialState = {
enabled: false,
visible: false,
allowSelection: false,
role: null,
@ -13,13 +12,6 @@ const initialState = {
const createDevToolStore = () => {
const store = createLocalStorageStore("bb-devtools", initialState)
const setEnabled = enabled => {
store.update(state => ({
...state,
enabled,
}))
}
const setVisible = visible => {
store.update(state => ({
...state,
@ -46,7 +38,7 @@ const createDevToolStore = () => {
return {
subscribe: store.subscribe,
actions: { setEnabled, setVisible, setAllowSelection, changeRole },
actions: { setVisible, setAllowSelection, changeRole },
}
}