2020-11-13 16:42:32 +01:00
|
|
|
<script>
|
2020-11-25 10:50:51 +01:00
|
|
|
import { writable } from "svelte/store"
|
2020-11-19 19:39:22 +01:00
|
|
|
import { setContext, onMount } from "svelte"
|
2020-11-13 16:42:32 +01:00
|
|
|
import Component from "./Component.svelte"
|
2021-01-27 16:52:12 +01:00
|
|
|
import NotificationDisplay from "./NotificationDisplay.svelte"
|
2021-06-21 10:56:46 +02:00
|
|
|
import ConfirmationDisplay from "./ConfirmationDisplay.svelte"
|
2021-07-30 15:01:01 +02:00
|
|
|
import PeekScreenDisplay from "./PeekScreenDisplay.svelte"
|
2021-02-05 12:44:33 +01:00
|
|
|
import Provider from "./Provider.svelte"
|
2020-11-18 20:18:18 +01:00
|
|
|
import SDK from "../sdk"
|
2021-02-01 19:51:22 +01:00
|
|
|
import {
|
|
|
|
createContextStore,
|
|
|
|
initialise,
|
|
|
|
screenStore,
|
|
|
|
authStore,
|
2021-05-20 15:47:17 +02:00
|
|
|
routeStore,
|
|
|
|
builderStore,
|
2021-06-30 21:35:02 +02:00
|
|
|
appStore,
|
2021-02-01 19:51:22 +01:00
|
|
|
} from "../store"
|
2021-02-26 15:04:31 +01:00
|
|
|
import { TableNames, ActionTypes } from "../constants"
|
2021-06-10 19:42:41 +02:00
|
|
|
import SettingsBar from "./preview/SettingsBar.svelte"
|
|
|
|
import SelectionIndicator from "./preview/SelectionIndicator.svelte"
|
|
|
|
import HoverIndicator from "./preview/HoverIndicator.svelte"
|
2021-07-07 12:29:35 +02:00
|
|
|
import { Layout, Heading, Body } from "@budibase/bbui"
|
|
|
|
import ErrorSVG from "../../../builder/assets/error.svg"
|
2020-11-13 16:42:32 +01:00
|
|
|
|
2020-11-20 10:50:10 +01:00
|
|
|
// Provide contexts
|
|
|
|
setContext("sdk", SDK)
|
2020-11-25 10:50:51 +01:00
|
|
|
setContext("component", writable({}))
|
2021-02-01 19:51:22 +01:00
|
|
|
setContext("context", createContextStore())
|
2020-11-13 16:42:32 +01:00
|
|
|
|
2021-05-20 15:47:17 +02:00
|
|
|
let dataLoaded = false
|
2021-07-07 12:29:35 +02:00
|
|
|
let permissionError = false
|
2020-11-19 19:39:22 +01:00
|
|
|
|
|
|
|
// Load app config
|
|
|
|
onMount(async () => {
|
2020-12-11 15:24:19 +01:00
|
|
|
await initialise()
|
2021-01-28 15:29:35 +01:00
|
|
|
await authStore.actions.fetchUser()
|
2021-05-20 15:47:17 +02:00
|
|
|
dataLoaded = true
|
2021-06-30 20:37:03 +02:00
|
|
|
if ($builderStore.inBuilder) {
|
|
|
|
builderStore.actions.notifyLoaded()
|
|
|
|
}
|
2020-11-19 19:39:22 +01:00
|
|
|
})
|
2021-02-26 15:04:31 +01:00
|
|
|
|
|
|
|
// Register this as a refreshable datasource so that user changes cause
|
|
|
|
// the user object to be refreshed
|
|
|
|
$: actions = [
|
|
|
|
{
|
|
|
|
type: ActionTypes.RefreshDatasource,
|
|
|
|
callback: () => authStore.actions.fetchUser(),
|
2021-03-16 14:54:34 +01:00
|
|
|
metadata: { dataSource: { type: "table", tableId: TableNames.USERS } },
|
2021-02-26 15:04:31 +01:00
|
|
|
},
|
|
|
|
]
|
2021-05-20 15:47:17 +02:00
|
|
|
|
2021-07-07 12:29:35 +02:00
|
|
|
// Handle no matching route - this is likely a permission error
|
2021-05-20 15:47:17 +02:00
|
|
|
$: {
|
|
|
|
if (dataLoaded && $routeStore.routerLoaded && !$routeStore.activeRoute) {
|
|
|
|
if ($authStore) {
|
2021-07-07 12:29:35 +02:00
|
|
|
// There is a logged in user, so handle them
|
|
|
|
if ($screenStore.screens.length) {
|
|
|
|
// Screens exist so navigate back to the home screen
|
|
|
|
const firstRoute = $screenStore.screens[0].routing?.route ?? "/"
|
|
|
|
routeStore.actions.navigate(firstRoute)
|
|
|
|
} else {
|
|
|
|
// No screens likely means the user has no permissions to view this app
|
|
|
|
permissionError = true
|
|
|
|
}
|
2021-05-20 15:47:17 +02:00
|
|
|
} else {
|
2021-07-07 12:29:35 +02:00
|
|
|
// The user is not logged in, redirect them to login
|
2021-05-20 15:47:17 +02:00
|
|
|
const returnUrl = `${window.location.pathname}${window.location.hash}`
|
|
|
|
const encodedUrl = encodeURIComponent(returnUrl)
|
|
|
|
window.location = `/builder/auth/login?returnUrl=${encodedUrl}`
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-06-28 13:55:11 +02:00
|
|
|
|
2021-06-30 21:35:02 +02:00
|
|
|
$: themeClass =
|
|
|
|
$builderStore.theme || $appStore.application?.theme || "spectrum--light"
|
2020-11-13 16:42:32 +01:00
|
|
|
</script>
|
|
|
|
|
2021-07-07 12:29:35 +02:00
|
|
|
{#if dataLoaded}
|
2021-06-08 09:00:54 +02:00
|
|
|
<div
|
|
|
|
id="spectrum-root"
|
|
|
|
lang="en"
|
|
|
|
dir="ltr"
|
2021-06-28 13:55:11 +02:00
|
|
|
class="spectrum spectrum--medium {themeClass}"
|
2021-06-08 09:00:54 +02:00
|
|
|
>
|
2021-07-07 12:29:35 +02:00
|
|
|
{#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>
|
2021-06-08 16:16:37 +02:00
|
|
|
</div>
|
2021-07-07 12:29:35 +02:00
|
|
|
{:else if $screenStore.activeLayout}
|
|
|
|
<Provider key="user" data={$authStore} {actions}>
|
2021-07-30 11:06:16 +02:00
|
|
|
<div id="app-root" class:preview={$builderStore.inBuilder}>
|
2021-07-07 12:29:35 +02:00
|
|
|
{#key $screenStore.activeLayout._id}
|
|
|
|
<Component instance={$screenStore.activeLayout.props} />
|
|
|
|
{/key}
|
|
|
|
</div>
|
|
|
|
<NotificationDisplay />
|
|
|
|
<ConfirmationDisplay />
|
2021-07-30 15:01:01 +02:00
|
|
|
<PeekScreenDisplay />
|
2021-07-07 12:29:35 +02:00
|
|
|
<!-- Key block needs to be outside the if statement or it breaks -->
|
|
|
|
{#key $builderStore.selectedComponentId}
|
|
|
|
{#if $builderStore.inBuilder}
|
|
|
|
<SettingsBar />
|
|
|
|
{/if}
|
|
|
|
{/key}
|
|
|
|
<!--
|
|
|
|
We don't want to key these by componentID as they control their own
|
|
|
|
re-mounting to avoid flashes.
|
|
|
|
-->
|
2021-06-10 16:13:51 +02:00
|
|
|
{#if $builderStore.inBuilder}
|
2021-07-07 12:29:35 +02:00
|
|
|
<SelectionIndicator />
|
|
|
|
<HoverIndicator />
|
2021-06-08 15:19:03 +02:00
|
|
|
{/if}
|
2021-07-07 12:29:35 +02:00
|
|
|
</Provider>
|
|
|
|
{/if}
|
2021-05-13 17:32:52 +02:00
|
|
|
</div>
|
2021-01-22 12:31:56 +01:00
|
|
|
{/if}
|
2021-05-13 17:32:52 +02:00
|
|
|
|
|
|
|
<style>
|
2021-06-24 13:14:19 +02:00
|
|
|
#spectrum-root,
|
|
|
|
#app-root {
|
2021-05-13 17:32:52 +02:00
|
|
|
height: 100%;
|
2021-06-08 16:16:37 +02:00
|
|
|
width: 100%;
|
2021-06-24 13:14:19 +02:00
|
|
|
padding: 0;
|
|
|
|
margin: 0;
|
2021-06-08 16:16:37 +02:00
|
|
|
overflow: hidden;
|
|
|
|
}
|
|
|
|
#app-root {
|
2021-05-13 17:32:52 +02:00
|
|
|
position: relative;
|
|
|
|
}
|
2021-07-30 11:06:16 +02:00
|
|
|
#app-root.preview {
|
|
|
|
border: 1px solid var(--spectrum-global-color-gray-300);
|
|
|
|
}
|
2021-06-30 20:57:31 +02:00
|
|
|
|
|
|
|
/* Custom scrollbars */
|
|
|
|
:global(::-webkit-scrollbar) {
|
|
|
|
width: 8px;
|
|
|
|
height: 8px;
|
|
|
|
}
|
|
|
|
:global(::-webkit-scrollbar-track) {
|
|
|
|
background: var(--spectrum-alias-background-color-default);
|
|
|
|
}
|
|
|
|
:global(::-webkit-scrollbar-thumb) {
|
|
|
|
background-color: var(--spectrum-global-color-gray-400);
|
|
|
|
border-radius: 4px;
|
|
|
|
}
|
|
|
|
:global(::-webkit-scrollbar-corner) {
|
|
|
|
background: var(--spectrum-alias-background-color-default);
|
|
|
|
}
|
|
|
|
:global(*) {
|
|
|
|
scrollbar-width: thin;
|
|
|
|
scrollbar-color: var(--spectrum-global-color-gray-400)
|
|
|
|
var(--spectrum-alias-background-color-default);
|
|
|
|
}
|
2021-07-07 12:29:35 +02:00
|
|
|
|
|
|
|
.error {
|
|
|
|
position: absolute;
|
|
|
|
width: 100%;
|
|
|
|
height: 100%;
|
|
|
|
display: grid;
|
|
|
|
place-items: center;
|
|
|
|
z-index: 1;
|
|
|
|
text-align: center;
|
|
|
|
padding: 20px;
|
|
|
|
}
|
|
|
|
.error :global(svg) {
|
|
|
|
fill: var(--spectrum-global-color-gray-500);
|
|
|
|
width: 80px;
|
|
|
|
height: 80px;
|
|
|
|
}
|
|
|
|
.error :global(h1),
|
|
|
|
.error :global(p) {
|
|
|
|
color: var(--spectrum-global-color-gray-800);
|
|
|
|
}
|
|
|
|
.error :global(p) {
|
|
|
|
font-style: italic;
|
|
|
|
margin-top: -0.5em;
|
|
|
|
}
|
|
|
|
.error :global(h1) {
|
|
|
|
font-weight: 400;
|
|
|
|
}
|
2021-05-13 17:32:52 +02:00
|
|
|
</style>
|