Merge pull request #10844 from Budibase/cheeks-lab-day-preview
Preview apps inside builder
This commit is contained in:
commit
cfe86194cd
|
@ -74,6 +74,7 @@ const INITIAL_FRONTEND_STATE = {
|
|||
propertyFocus: null,
|
||||
builderSidePanel: false,
|
||||
hasLock: true,
|
||||
showPreview: false,
|
||||
|
||||
// URL params
|
||||
selectedScreenId: null,
|
||||
|
|
|
@ -69,7 +69,7 @@
|
|||
name: "App",
|
||||
description: "",
|
||||
icon: "Play",
|
||||
action: () => window.open(`/${$store.appId}`),
|
||||
action: () => store.update(state => ({ ...state, showPreview: true })),
|
||||
},
|
||||
{
|
||||
type: "Preview",
|
||||
|
|
|
@ -62,7 +62,10 @@
|
|||
}
|
||||
|
||||
const previewApp = () => {
|
||||
window.open(`/${application}`)
|
||||
store.update(state => ({
|
||||
...state,
|
||||
showPreview: true,
|
||||
}))
|
||||
}
|
||||
|
||||
const viewApp = () => {
|
||||
|
|
|
@ -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>
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
}
|
||||
},
|
||||
|
||||
|
|
|
@ -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%;
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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##"]) {
|
||||
|
|
|
@ -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
|
||||
)
|
||||
|
|
|
@ -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
|
||||
}
|
||||
)
|
|
@ -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"
|
||||
|
|
|
@ -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 },
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue