budibase/packages/builder/src/pages/builder/_layout.svelte

185 lines
5.0 KiB
Svelte

<script>
import { isActive, redirect, params } from "@roxi/routify"
import { admin, auth, licensing, navigation } from "@/stores/portal"
import { onMount } from "svelte"
import { CookieUtils, Constants } from "@budibase/frontend-core"
import { API } from "@/api"
import Branding from "./Branding.svelte"
import ContextMenu from "@/components/ContextMenu.svelte"
import CommandPalette from "@/components/commandPalette/CommandPalette.svelte"
import { Modal } from "@budibase/bbui"
let loaded = false
let commandPaletteModal
$: multiTenancyEnabled = $admin.multiTenancy
$: hasAdminUser = $admin?.checklist?.adminUser?.checked
$: baseUrl = $admin?.baseUrl
$: tenantSet = $auth.tenantSet
$: cloud = $admin?.cloud
$: user = $auth.user
$: useAccountPortal = cloud && !$admin.disableAccountPortal
navigation.init($redirect)
const validateTenantId = async () => {
const host = window.location.host
if (host.includes("localhost:") || !baseUrl) {
// ignore local dev
return
}
const mainHost = new URL(baseUrl).host
let urlTenantId
// remove the main host part
const hostParts = host.split(mainHost).filter(part => part !== "")
// if there is a part left, it has to be the tenant ID subdomain
if (hostParts.length === 1) {
urlTenantId = hostParts[0].replace(/\./g, "")
}
if (user && user.tenantId) {
if (!urlTenantId) {
// redirect to correct tenantId subdomain
if (!window.location.host.includes("localhost")) {
let redirectUrl = window.location.href
redirectUrl = redirectUrl.replace("://", `://${user.tenantId}.`)
window.location.href = redirectUrl
}
return
}
if (urlTenantId && user.tenantId !== urlTenantId) {
// user should not be here - play it safe and log them out
try {
await auth.logout()
await auth.setOrganisation(null)
} catch (error) {
console.error(
`Tenant mis-match - "${urlTenantId}" and "${user.tenantId}" - logout`
)
}
}
} else {
// no user - set the org according to the url
await auth.setOrganisation(urlTenantId)
}
}
async function analyticsPing() {
await API.analyticsPing({ source: "builder" })
}
onMount(async () => {
try {
await auth.getSelf()
await admin.init()
if ($admin.maintenance.length > 0) {
$redirect("./maintenance")
}
if ($auth.user) {
await licensing.init()
}
// Set init info if present
if ($params["?template"]) {
await auth.setInitInfo({ init_template: $params["?template"] })
}
// Validate tenant if in a multi-tenant env
if (multiTenancyEnabled) {
await validateTenantId()
}
} catch (error) {
// Don't show a notification here, as we might 403 initially due to not
// being logged in
}
loaded = true
// lastly
await analyticsPing()
})
$: {
const apiReady = $admin.loaded && $auth.loaded
// firstly, set the return url
if (
loaded &&
apiReady &&
!$auth.user &&
!CookieUtils.getCookie(Constants.Cookies.ReturnUrl) &&
// logout triggers a page refresh, so we don't want to set the return url
!$auth.postLogout &&
// don't set the return url on pre-login pages
!$isActive("./auth") &&
!$isActive("./invite") &&
!$isActive("./admin")
) {
const url = window.location.pathname
CookieUtils.setCookie(Constants.Cookies.ReturnUrl, url)
}
// if tenant is not set go to it
if (
loaded &&
!useAccountPortal &&
apiReady &&
multiTenancyEnabled &&
!tenantSet
) {
$redirect("./auth/org")
}
// Force creation of an admin user if one doesn't exist
else if (loaded && !useAccountPortal && apiReady && !hasAdminUser) {
$redirect("./admin")
}
// Redirect to log in at any time if the user isn't authenticated
else if (
loaded &&
(hasAdminUser || cloud) &&
!$auth.user &&
!$isActive("./auth") &&
!$isActive("./invite") &&
!$isActive("./admin")
) {
$redirect("./auth")
}
// check if password reset required for user
else if ($auth.user?.forceResetPassword) {
$redirect("./auth/reset")
}
// lastly, redirect to the return url if it has been set
else if (loaded && apiReady && $auth.user) {
const returnUrl = CookieUtils.getCookie(Constants.Cookies.ReturnUrl)
if (returnUrl) {
CookieUtils.removeCookie(Constants.Cookies.ReturnUrl)
window.location.href = returnUrl
}
}
}
// Event handler for the command palette
const handleKeyDown = e => {
if (e.key === "k" && (e.ctrlKey || e.metaKey)) {
e.preventDefault()
commandPaletteModal.toggle()
}
}
</script>
<!--Portal branding overrides -->
<Branding />
<ContextMenu />
<svelte:window on:keydown={handleKeyDown} />
<Modal bind:this={commandPaletteModal} zIndex={999999}>
<CommandPalette />
</Modal>
{#if loaded}
<slot />
{/if}