diff --git a/hosting/nginx.dev.conf b/hosting/nginx.dev.conf index 1ecee422cd..915125cbce 100644 --- a/hosting/nginx.dev.conf +++ b/hosting/nginx.dev.conf @@ -126,6 +126,16 @@ http { proxy_pass http://app-service; } + location /embed { + rewrite /embed/(.*) /app/$1 break; + proxy_pass http://app-service; + proxy_redirect off; + proxy_set_header Host $host; + proxy_set_header x-budibase-embed "true"; + add_header x-budibase-embed "true"; + add_header Content-Security-Policy "frame-ancestors *"; + } + location /builder { proxy_read_timeout 120s; proxy_connect_timeout 120s; diff --git a/hosting/proxy/nginx.prod.conf b/hosting/proxy/nginx.prod.conf index 001a08a9a6..9ce6b54053 100644 --- a/hosting/proxy/nginx.prod.conf +++ b/hosting/proxy/nginx.prod.conf @@ -92,6 +92,16 @@ http { proxy_pass $apps; } + location /embed { + rewrite /embed/(.*) /app/$1 break; + proxy_pass $apps; + proxy_redirect off; + proxy_set_header Host $host; + proxy_set_header x-budibase-embed "true"; + add_header x-budibase-embed "true"; + add_header Content-Security-Policy "frame-ancestors *"; + } + location = / { proxy_pass $apps; } diff --git a/packages/backend-core/src/events/publishers/serve.ts b/packages/backend-core/src/events/publishers/serve.ts index 64e24e20a7..ac6a23dfdb 100644 --- a/packages/backend-core/src/events/publishers/serve.ts +++ b/packages/backend-core/src/events/publishers/serve.ts @@ -14,10 +14,15 @@ async function servedBuilder(timezone: string) { await publishEvent(Event.SERVED_BUILDER, properties) } -async function servedApp(app: App, timezone: string) { +async function servedApp( + app: App, + timezone: string, + embed?: boolean | undefined +) { const properties: AppServedEvent = { appVersion: app.version, timezone, + embed: embed === true, } await publishEvent(Event.SERVED_APP, properties) } diff --git a/packages/builder/src/builderStore/store/frontend.js b/packages/builder/src/builderStore/store/frontend.js index d0414b5733..8160939df9 100644 --- a/packages/builder/src/builderStore/store/frontend.js +++ b/packages/builder/src/builderStore/store/frontend.js @@ -117,10 +117,13 @@ export const getFrontendStore = () => { reset: () => { store.set({ ...INITIAL_FRONTEND_STATE }) websocket?.disconnect() + websocket = null }, initialise: async pkg => { const { layouts, screens, application, clientLibPath, hasLock } = pkg - websocket = createBuilderWebsocket(application.appId) + if (!websocket) { + websocket = createBuilderWebsocket(application.appId) + } await store.actions.components.refreshDefinitions(application.appId) // Reset store state diff --git a/packages/builder/src/components/automation/SetupPanel/AutomationBlockSetup.svelte b/packages/builder/src/components/automation/SetupPanel/AutomationBlockSetup.svelte index d2e34319da..823dcc432b 100644 --- a/packages/builder/src/components/automation/SetupPanel/AutomationBlockSetup.svelte +++ b/packages/builder/src/components/automation/SetupPanel/AutomationBlockSetup.svelte @@ -333,7 +333,7 @@ : null}>{value.title || (key === "row" ? "Table" : key)} {/if} - {#if value.type === "string" && value.enum && canShowField(key)} + {#if value.type === "string" && value.enum && canShowField(key, value)} + diff --git a/packages/builder/src/components/deploy/RevertModal.svelte b/packages/builder/src/components/deploy/RevertModal.svelte index 364add9053..79b1f5300f 100644 --- a/packages/builder/src/components/deploy/RevertModal.svelte +++ b/packages/builder/src/components/deploy/RevertModal.svelte @@ -1,15 +1,9 @@ - + export const hide = () => { + revertModal.hide() + } + + export const show = () => { + revertModal.show() + } + {} export let hideIcon = false let updateModal @@ -47,6 +48,7 @@ notifications.success( `App updated successfully to version ${$store.upgradableVersion}` ) + onComplete() } catch (err) { notifications.error(`Error updating app: ${err}`) } @@ -70,9 +72,7 @@ {#if !hideIcon && updateAvailable} - - Update available - + Update {/if} { title: "Data", route: "/builder/app/:application/data", layout: OnboardingData, - query: ".topcenternav .spectrum-Tabs-item#builder-data-tab", + query: ".topleftnav .spectrum-Tabs-item#builder-data-tab", onLoad: async () => { tourEvent(TOUR_STEP_KEYS.BUILDER_DATA_SECTION) }, @@ -45,20 +45,20 @@ const getTours = () => { title: "Design", route: "/builder/app/:application/design", layout: OnboardingDesign, - query: ".topcenternav .spectrum-Tabs-item#builder-design-tab", + query: ".topleftnav .spectrum-Tabs-item#builder-design-tab", onLoad: () => { tourEvent(TOUR_STEP_KEYS.BUILDER_DESIGN_SECTION) }, align: "left", }, { - id: TOUR_STEP_KEYS.BUILDER_AUTOMATE_SECTION, + id: TOUR_STEP_KEYS.BUILDER_AUTOMATION_SECTION, title: "Automations", - route: "/builder/app/:application/automate", - query: ".topcenternav .spectrum-Tabs-item#builder-automate-tab", + route: "/builder/app/:application/automation", + query: ".topleftnav .spectrum-Tabs-item#builder-automation-tab", body: "Once you have your app screens made, you can set up automations to fit in with your current workflow", onLoad: () => { - tourEvent(TOUR_STEP_KEYS.BUILDER_AUTOMATE_SECTION) + tourEvent(TOUR_STEP_KEYS.BUILDER_AUTOMATION_SECTION) }, align: "left", }, diff --git a/packages/builder/src/components/portal/page/SideNavItem.svelte b/packages/builder/src/components/portal/page/SideNavItem.svelte index c22b8b6113..ff627acfc5 100644 --- a/packages/builder/src/components/portal/page/SideNavItem.svelte +++ b/packages/builder/src/components/portal/page/SideNavItem.svelte @@ -4,18 +4,27 @@ export let active = false - - {text || ""} - +{#if url} + + {text || ""} + +{:else} + + + {text || ""} + +{/if} diff --git a/packages/builder/src/pages/builder/portal/overview/[appId]/automation-history/_components/HistoryDetailsPanel.svelte b/packages/builder/src/pages/builder/app/[application]/settings/automation-history/_components/HistoryDetailsPanel.svelte similarity index 95% rename from packages/builder/src/pages/builder/portal/overview/[appId]/automation-history/_components/HistoryDetailsPanel.svelte rename to packages/builder/src/pages/builder/app/[application]/settings/automation-history/_components/HistoryDetailsPanel.svelte index 565c0d1f2f..5b9c925130 100644 --- a/packages/builder/src/pages/builder/portal/overview/[appId]/automation-history/_components/HistoryDetailsPanel.svelte +++ b/packages/builder/src/pages/builder/app/[application]/settings/automation-history/_components/HistoryDetailsPanel.svelte @@ -47,7 +47,7 @@ @@ -227,7 +227,7 @@ {#if selectedHistory} diff --git a/packages/builder/src/pages/builder/portal/overview/[appId]/backups/_components/ActionsRenderer.svelte b/packages/builder/src/pages/builder/app/[application]/settings/backups/_components/ActionsRenderer.svelte similarity index 100% rename from packages/builder/src/pages/builder/portal/overview/[appId]/backups/_components/ActionsRenderer.svelte rename to packages/builder/src/pages/builder/app/[application]/settings/backups/_components/ActionsRenderer.svelte diff --git a/packages/builder/src/pages/builder/portal/overview/[appId]/backups/_components/AppSizeRenderer.svelte b/packages/builder/src/pages/builder/app/[application]/settings/backups/_components/AppSizeRenderer.svelte similarity index 100% rename from packages/builder/src/pages/builder/portal/overview/[appId]/backups/_components/AppSizeRenderer.svelte rename to packages/builder/src/pages/builder/app/[application]/settings/backups/_components/AppSizeRenderer.svelte diff --git a/packages/builder/src/pages/builder/portal/overview/[appId]/backups/_components/CreateRestoreModal.svelte b/packages/builder/src/pages/builder/app/[application]/settings/backups/_components/CreateRestoreModal.svelte similarity index 100% rename from packages/builder/src/pages/builder/portal/overview/[appId]/backups/_components/CreateRestoreModal.svelte rename to packages/builder/src/pages/builder/app/[application]/settings/backups/_components/CreateRestoreModal.svelte diff --git a/packages/builder/src/pages/builder/portal/overview/[appId]/backups/_components/DatasourceRenderer.svelte b/packages/builder/src/pages/builder/app/[application]/settings/backups/_components/DatasourceRenderer.svelte similarity index 100% rename from packages/builder/src/pages/builder/portal/overview/[appId]/backups/_components/DatasourceRenderer.svelte rename to packages/builder/src/pages/builder/app/[application]/settings/backups/_components/DatasourceRenderer.svelte diff --git a/packages/builder/src/pages/builder/portal/overview/[appId]/backups/_components/StatusRenderer.svelte b/packages/builder/src/pages/builder/app/[application]/settings/backups/_components/StatusRenderer.svelte similarity index 100% rename from packages/builder/src/pages/builder/portal/overview/[appId]/backups/_components/StatusRenderer.svelte rename to packages/builder/src/pages/builder/app/[application]/settings/backups/_components/StatusRenderer.svelte diff --git a/packages/builder/src/pages/builder/portal/overview/[appId]/backups/_components/TimeAgoRenderer.svelte b/packages/builder/src/pages/builder/app/[application]/settings/backups/_components/TimeAgoRenderer.svelte similarity index 100% rename from packages/builder/src/pages/builder/portal/overview/[appId]/backups/_components/TimeAgoRenderer.svelte rename to packages/builder/src/pages/builder/app/[application]/settings/backups/_components/TimeAgoRenderer.svelte diff --git a/packages/builder/src/pages/builder/portal/overview/[appId]/backups/_components/TypeRenderer.svelte b/packages/builder/src/pages/builder/app/[application]/settings/backups/_components/TypeRenderer.svelte similarity index 100% rename from packages/builder/src/pages/builder/portal/overview/[appId]/backups/_components/TypeRenderer.svelte rename to packages/builder/src/pages/builder/app/[application]/settings/backups/_components/TypeRenderer.svelte diff --git a/packages/builder/src/pages/builder/portal/overview/[appId]/backups/_components/UserRenderer.svelte b/packages/builder/src/pages/builder/app/[application]/settings/backups/_components/UserRenderer.svelte similarity index 100% rename from packages/builder/src/pages/builder/portal/overview/[appId]/backups/_components/UserRenderer.svelte rename to packages/builder/src/pages/builder/app/[application]/settings/backups/_components/UserRenderer.svelte diff --git a/packages/builder/src/pages/builder/portal/overview/[appId]/backups/index.svelte b/packages/builder/src/pages/builder/app/[application]/settings/backups/index.svelte similarity index 96% rename from packages/builder/src/pages/builder/portal/overview/[appId]/backups/index.svelte rename to packages/builder/src/pages/builder/app/[application]/settings/backups/index.svelte index 77d76c9609..1d612117e2 100644 --- a/packages/builder/src/pages/builder/portal/overview/[appId]/backups/index.svelte +++ b/packages/builder/src/pages/builder/app/[application]/settings/backups/index.svelte @@ -13,7 +13,8 @@ Tag, Table, } from "@budibase/bbui" - import { backups, licensing, auth, admin, overview } from "stores/portal" + import { backups, licensing, auth, admin } from "stores/portal" + import { store } from "builderStore" import { createPaginationStore } from "helpers/pagination" import TimeAgoRenderer from "./_components/TimeAgoRenderer.svelte" import AppSizeRenderer from "./_components/AppSizeRenderer.svelte" @@ -50,7 +51,6 @@ }, ] - $: app = $overview.selectedApp $: page = $pageInfo.page $: fetchBackups(filterOpt, page, startDate, endDate) @@ -101,7 +101,7 @@ async function fetchBackups(filters, page, startDate, endDate) { const response = await backups.searchBackups({ - appId: app.instance._id, + appId: $store.appId, ...filters, page, startDate, @@ -117,7 +117,7 @@ try { loading = true let response = await backups.createManualBackup({ - appId: app.instance._id, + appId: $store.appId, }) await fetchBackups(filterOpt, page) notifications.success(response.message) @@ -143,20 +143,20 @@ async function handleButtonClick({ detail }) { if (detail.type === "backupDelete") { await backups.deleteBackup({ - appId: app.instance._id, + appId: $store.appId, backupId: detail.backupId, }) await fetchBackups(filterOpt, page) } else if (detail.type === "backupRestore") { await backups.restoreBackup({ - appId: app.instance._id, + appId: $store.appId, backupId: detail.backupId, name: detail.restoreBackupName, }) await fetchBackups(filterOpt, page) } else if (detail.type === "backupUpdate") { await backups.updateBackup({ - appId: app.instance._id, + appId: $store.appId, backupId: detail.backupId, name: detail.name, }) @@ -333,10 +333,6 @@ gap: var(--spacing-m); } - .table { - overflow-x: scroll; - } - .center { text-align: center; display: contents; diff --git a/packages/builder/src/pages/builder/app/[application]/settings/embed.svelte b/packages/builder/src/pages/builder/app/[application]/settings/embed.svelte new file mode 100644 index 0000000000..827c298316 --- /dev/null +++ b/packages/builder/src/pages/builder/app/[application]/settings/embed.svelte @@ -0,0 +1,75 @@ + + + + + Embed + Embed your app into your other tools of choice + + +
+
{embed}
+ {#if appDeployed} +
+ +
+ {:else} +
+ Embeds will only work with a published app +
+ {/if} +
+
+ + diff --git a/packages/builder/src/pages/builder/app/[application]/settings/export.svelte b/packages/builder/src/pages/builder/app/[application]/settings/export.svelte new file mode 100644 index 0000000000..365f3c1f9e --- /dev/null +++ b/packages/builder/src/pages/builder/app/[application]/settings/export.svelte @@ -0,0 +1,57 @@ + + + + + + + + + Export your app + Export your latest edited or published app + + +
+ exportApp({ published: false })}> + Export latest edited app + + exportApp({ published: true })} + > + Export latest published app + +
+
+ + diff --git a/packages/builder/src/pages/builder/portal/overview/index.svelte b/packages/builder/src/pages/builder/app/[application]/settings/index.svelte similarity index 56% rename from packages/builder/src/pages/builder/portal/overview/index.svelte rename to packages/builder/src/pages/builder/app/[application]/settings/index.svelte index 6881a9ca67..501d34b12e 100644 --- a/packages/builder/src/pages/builder/portal/overview/index.svelte +++ b/packages/builder/src/pages/builder/app/[application]/settings/index.svelte @@ -1,4 +1,5 @@ diff --git a/packages/builder/src/pages/builder/portal/overview/[appId]/name-and-url.svelte b/packages/builder/src/pages/builder/app/[application]/settings/name-and-url.svelte similarity index 74% rename from packages/builder/src/pages/builder/portal/overview/[appId]/name-and-url.svelte rename to packages/builder/src/pages/builder/app/[application]/settings/name-and-url.svelte index e6e437859b..56a10553dc 100644 --- a/packages/builder/src/pages/builder/portal/overview/[appId]/name-and-url.svelte +++ b/packages/builder/src/pages/builder/app/[application]/settings/name-and-url.svelte @@ -10,14 +10,22 @@ Icon, } from "@budibase/bbui" import { AppStatus } from "constants" - import { overview } from "stores/portal" + import { store } from "builderStore" + import { apps } from "stores/portal" import UpdateAppModal from "components/start/UpdateAppModal.svelte" + import { API } from "api" let updatingModal - $: app = $overview.selectedApp + $: filteredApps = $apps.filter(app => app.devId == $store.appId) + $: app = filteredApps.length ? filteredApps[0] : {} $: appUrl = `${window.origin}/app${app?.url}` $: appDeployed = app?.status === AppStatus.DEPLOYED + + const initialiseApp = async () => { + const applicationPkg = await API.fetchAppPackage(app.devId) + await store.actions.initialise(applicationPkg) + } @@ -66,7 +74,12 @@ - + { + await initialiseApp() + }} + /> diff --git a/packages/builder/src/pages/builder/portal/overview/[appId]/access/_components/AssignmentModal.svelte b/packages/builder/src/pages/builder/portal/overview/[appId]/access/_components/AssignmentModal.svelte deleted file mode 100644 index b3aed56a48..0000000000 --- a/packages/builder/src/pages/builder/portal/overview/[appId]/access/_components/AssignmentModal.svelte +++ /dev/null @@ -1,211 +0,0 @@ - - - addData(data)} - showCloseIcon={false} - disabled={!valid} -> - {#if data.length} - - {#each data as input, index} -
-
- x._id !== Constants.Roles.PUBLIC - )} - secondaryPlaceholder="Access" - bind:primaryValue={input.id} - bind:secondaryValue={input.role} - bind:searchTerm={search} - getPrimaryOptionLabel={group => group.name} - getPrimaryOptionValue={group => group.name} - getPrimaryOptionIcon={group => group.icon} - getPrimaryOptionColour={group => group.colour} - getSecondaryOptionLabel={role => role.name} - getSecondaryOptionValue={role => role._id} - getSecondaryOptionColour={role => - RoleUtils.getRoleColour(role._id)} - /> -
-
- removeItem(index)} - /> -
-
- {/each} -
- {/if} -
- Add more -
-
- - diff --git a/packages/builder/src/pages/builder/portal/overview/[appId]/access/_components/EditableRoleRenderer.svelte b/packages/builder/src/pages/builder/portal/overview/[appId]/access/_components/EditableRoleRenderer.svelte deleted file mode 100644 index d92a522602..0000000000 --- a/packages/builder/src/pages/builder/portal/overview/[appId]/access/_components/EditableRoleRenderer.svelte +++ /dev/null @@ -1,26 +0,0 @@ - - -
- rolesContext.updateRole(e.detail, row._id)} - on:remove={() => rolesContext.removeRole(row._id)} - /> -
- - diff --git a/packages/builder/src/pages/builder/portal/overview/[appId]/access/index.svelte b/packages/builder/src/pages/builder/portal/overview/[appId]/access/index.svelte deleted file mode 100644 index 62c5da12ec..0000000000 --- a/packages/builder/src/pages/builder/portal/overview/[appId]/access/index.svelte +++ /dev/null @@ -1,271 +0,0 @@ - - - - - Access - Assign users to your app and set their access - - - - {#if $usersFetch.loaded} - -
- Users - -
- -
- You have no users assigned yet -
-
- -
- {/if} - - {#if $usersFetch.loaded && $licensing.groupsEnabled} - -
- Groups - -
- -
- You have no groups assigned yet -
-
-
- {/if} -
-
- - - - - - diff --git a/packages/builder/src/pages/builder/portal/overview/[appId]/index.svelte b/packages/builder/src/pages/builder/portal/overview/[appId]/index.svelte deleted file mode 100644 index 437a0663c0..0000000000 --- a/packages/builder/src/pages/builder/portal/overview/[appId]/index.svelte +++ /dev/null @@ -1,4 +0,0 @@ - diff --git a/packages/builder/src/pages/builder/portal/overview/[appId]/overview.svelte b/packages/builder/src/pages/builder/portal/overview/[appId]/overview.svelte deleted file mode 100644 index 0932d2d79a..0000000000 --- a/packages/builder/src/pages/builder/portal/overview/[appId]/overview.svelte +++ /dev/null @@ -1,368 +0,0 @@ - - -
- -
- -
-
- {#if isPublished} - - Published - {:else} - - Unpublished - {/if} -
- -
- {#if isPublished} - {deploymentString} - - Unpublish - {/if} - - {#if !deployments?.length} - - - {/if} -
-
-
- {#if appEditor} - -
-
- {#if appEditor} - -
- {appEditor._id === $auth.user._id ? "You" : appEditorText} -
- {/if} -
-
- {#if app} - {processStringSync( - "Last edited {{ duration time 'millisecond' }} ago", - { - time: - new Date().getTime() - new Date(app?.updatedAt).getTime(), - } - )} - {/if} -
-
-
- {/if} - { - $goto("./version") - }} - > -
- {$store.version} - {#if updateAvailable} -
- New version {$store.upgradableVersion} is - available - - { - $goto("./version") - }} - > - Update - -
- {:else} -
You're running the latest!
- {/if} -
-
- {#if $appUsersFetch.loaded} - { - $goto("./access") - }} - > - {#if appUsers.length || appGroups.length} - -
- {#if appUsers.length} -
-
- {#each appUsers.slice(0, 4) as user} - - {/each} -
-
- {appUsers.length} - {appUsers.length > 1 ? "users" : "user"} assigned -
-
- {/if} - {#if appGroups.length} -
-
- {#each appGroups.slice(0, 4) as group} - - {/each} -
-
- {appGroups.length} user - {appGroups.length > 1 ? "groups" : "group"} assigned -
-
- {/if} -
-
- {:else} - - No users -
- No users have been assigned to this app -
-
- {/if} -
- {/if} -
- {#if false} -
- { - $goto("../automation-history") - }} - > -
-
-
- 0 -
- - Success -
-
-
- 0 -
- - Error -
-
-
-
-
- { - $goto("../backups") - }} - > -
test
-
-
- {/if} -
-
- - - Are you sure you want to unpublish the app {app?.name}? - - - diff --git a/packages/builder/src/pages/builder/portal/overview/_layout.svelte b/packages/builder/src/pages/builder/portal/overview/_layout.svelte deleted file mode 100644 index 2157840bbc..0000000000 --- a/packages/builder/src/pages/builder/portal/overview/_layout.svelte +++ /dev/null @@ -1,15 +0,0 @@ - - -{#if loaded} - -{/if} diff --git a/packages/builder/src/pages/builder/portal/users/groups/[groupId].svelte b/packages/builder/src/pages/builder/portal/users/groups/[groupId].svelte index 4b0c6974e5..3482b9a88f 100644 --- a/packages/builder/src/pages/builder/portal/users/groups/[groupId].svelte +++ b/packages/builder/src/pages/builder/portal/users/groups/[groupId].svelte @@ -141,7 +141,7 @@ customPlaceholder allowEditRows={false} customRenderers={customAppTableRenderers} - on:click={e => $goto(`../../overview/${e.detail.devId}`)} + on:click={e => $goto(`/builder/app/${e.detail.devId}`)} >
This group doesn't have access to any apps diff --git a/packages/builder/src/pages/builder/portal/users/users/[userId].svelte b/packages/builder/src/pages/builder/portal/users/users/[userId].svelte index e2ac6c40b8..ec556abf72 100644 --- a/packages/builder/src/pages/builder/portal/users/users/[userId].svelte +++ b/packages/builder/src/pages/builder/portal/users/users/[userId].svelte @@ -346,7 +346,7 @@ customPlaceholder allowEditRows={false} customRenderers={customAppTableRenderers} - on:click={e => $goto(`../../overview/${e.detail.devId}`)} + on:click={e => $goto(`/builder/app/${e.detail.devId}`)} >
diff --git a/packages/builder/src/stores/portal/index.js b/packages/builder/src/stores/portal/index.js index 7f5ce980fa..a7c430e621 100644 --- a/packages/builder/src/stores/portal/index.js +++ b/packages/builder/src/stores/portal/index.js @@ -10,7 +10,6 @@ export { licensing } from "./licensing" export { groups } from "./groups" export { plugins } from "./plugins" export { backups } from "./backups" -export { overview } from "./overview" export { environment } from "./environment" export { menu } from "./menu" export { auditLogs } from "./auditLogs" diff --git a/packages/builder/src/stores/portal/licensing.js b/packages/builder/src/stores/portal/licensing.js index ded77894f9..4a59f29f52 100644 --- a/packages/builder/src/stores/portal/licensing.js +++ b/packages/builder/src/stores/portal/licensing.js @@ -76,7 +76,13 @@ export const createLicensingStore = () => { await actions.setQuotaUsage() }, setNavigation: () => { - const upgradeUrl = `${get(admin).accountPortalUrl}/portal/upgrade` + const adminStore = get(admin) + const authStore = get(auth) + + const upgradeUrl = authStore?.user?.accountPortalAccess + ? `${adminStore.accountPortalUrl}/portal/upgrade` + : "/builder/portal/account/upgrade" + const goToUpgradePage = () => { window.location.href = upgradeUrl } diff --git a/packages/client/src/components/ClientApp.svelte b/packages/client/src/components/ClientApp.svelte index f9ecb495d1..06c4681b95 100644 --- a/packages/client/src/components/ClientApp.svelte +++ b/packages/client/src/components/ClientApp.svelte @@ -46,6 +46,7 @@ let dataLoaded = false let permissionError = false + let embedNoScreens = false // Determine if we should show devtools or not $: showDevTools = $devToolsEnabled && !$routeStore.queryParams?.peek @@ -68,6 +69,8 @@ // If the user is logged in but has no screens, they don't have // permission to use the app permissionError = true + } else if ($appStore.embedded) { + embedNoScreens = true } else { // If they have no screens and are not logged in, it probably means // they should log in to gain access @@ -86,7 +89,9 @@ if (get(builderStore).inBuilder) { builderStore.actions.notifyLoaded() } else { - builderStore.actions.analyticsPing({ source: "app" }) + builderStore.actions.analyticsPing({ + embedded: !!$appStore.embedded, + }) } }) @@ -158,6 +163,15 @@
+ {:else if embedNoScreens} +
+ + {@html ErrorSVG} + + This Budibase app is not publicly accessible + + +
{:else} {#key $screenStore.activeLayout._id} diff --git a/packages/client/src/components/app/Layout.svelte b/packages/client/src/components/app/Layout.svelte index ba5bbedd2f..c1dec0b119 100644 --- a/packages/client/src/components/app/Layout.svelte +++ b/packages/client/src/components/app/Layout.svelte @@ -34,6 +34,8 @@ export let navWidth export let pageWidth + export let embedded = false + const NavigationClasses = { Top: "top", Left: "left", @@ -186,9 +188,11 @@ {title} {/if}
-
- -
+ {#if !embedded} +
+ +
+ {/if}
{ // server rendered app HTML appStore.actions.setAppId(window["##BUDIBASE_APP_ID##"]) + // Set the flag used to determine if the app is being loaded via an iframe + appStore.actions.setAppEmbedded( + window["##BUDIBASE_APP_EMBEDDED##"] === "true" + ) + // Fetch environment info if (!get(environmentStore)?.loaded) { await environmentStore.actions.fetchEnvironment() diff --git a/packages/client/src/stores/app.js b/packages/client/src/stores/app.js index f3fd271639..ea20b23131 100644 --- a/packages/client/src/stores/app.js +++ b/packages/client/src/stores/app.js @@ -5,6 +5,7 @@ const initialState = { appId: null, isDevApp: false, clientLoadTime: window.INIT_TIME ? Date.now() - window.INIT_TIME : null, + embedded: false, } const createAppStore = () => { @@ -46,9 +47,20 @@ const createAppStore = () => { }) } + const setAppEmbedded = embeddded => { + store.update(state => { + if (state) { + state.embedded = embeddded + } else { + state = { embeddded } + } + return state + }) + } + return { subscribe: derivedStore.subscribe, - actions: { setAppId, fetchAppDefinition }, + actions: { setAppId, setAppEmbedded, fetchAppDefinition }, } } diff --git a/packages/client/src/stores/builder.js b/packages/client/src/stores/builder.js index b82b032617..23d789dc2c 100644 --- a/packages/client/src/stores/builder.js +++ b/packages/client/src/stores/builder.js @@ -53,9 +53,9 @@ const createBuilderStore = () => { notifyLoaded: () => { eventStore.actions.dispatchEvent("preview-loaded") }, - analyticsPing: async () => { + analyticsPing: async ({ embedded }) => { try { - await API.analyticsPing({ source: "app" }) + await API.analyticsPing({ source: "app", embedded }) } catch (error) { // Do nothing } diff --git a/packages/client/src/stores/screens.js b/packages/client/src/stores/screens.js index ba373ad8e0..9cb0d536de 100644 --- a/packages/client/src/stores/screens.js +++ b/packages/client/src/stores/screens.js @@ -33,7 +33,6 @@ const createScreenStore = () => { ]) => { let activeLayout, activeScreen let screens - if ($builderStore.inBuilder) { // Use builder defined definitions if inside the builder preview activeScreen = Helpers.cloneDeep($builderStore.screen) @@ -175,10 +174,10 @@ const createScreenStore = () => { }, ], ...navigationSettings, + embedded: $appStore.embedded, }, } } - return { screens, activeLayout, activeScreen } } ) diff --git a/packages/frontend-core/src/api/analytics.js b/packages/frontend-core/src/api/analytics.js index 653943c6ab..df56bc938e 100644 --- a/packages/frontend-core/src/api/analytics.js +++ b/packages/frontend-core/src/api/analytics.js @@ -7,11 +7,11 @@ export const buildAnalyticsEndpoints = API => ({ url: "/api/bbtel", }) }, - analyticsPing: async ({ source }) => { + analyticsPing: async ({ source, embedded }) => { const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone return await API.post({ url: "/api/bbtel/ping", - body: { source, timezone }, + body: { source, timezone, embedded }, }) }, }) diff --git a/packages/server/src/api/controllers/analytics.ts b/packages/server/src/api/controllers/analytics.ts index 6c80593d5d..dc7c4185bb 100644 --- a/packages/server/src/api/controllers/analytics.ts +++ b/packages/server/src/api/controllers/analytics.ts @@ -12,6 +12,7 @@ export const isEnabled = async (ctx: any) => { export const ping = async (ctx: any) => { const body = ctx.request.body as AnalyticsPingRequest + switch (body.source) { case PingSource.APP: { const db = context.getAppDB({ skip_setup: true }) @@ -21,7 +22,7 @@ export const ping = async (ctx: any) => { if (isDevAppID(appId)) { await events.serve.servedAppPreview(appInfo, body.timezone) } else { - await events.serve.servedApp(appInfo, body.timezone) + await events.serve.servedApp(appInfo, body.timezone, body.embedded) } break } diff --git a/packages/server/src/api/controllers/static/index.ts b/packages/server/src/api/controllers/static/index.ts index 49d2abfc79..fc17cd46e0 100644 --- a/packages/server/src/api/controllers/static/index.ts +++ b/packages/server/src/api/controllers/static/index.ts @@ -100,6 +100,9 @@ export const deleteObjects = async function (ctx: any) { } export const serveApp = async function (ctx: any) { + const bbHeaderEmbed = + ctx.request.get("x-budibase-embed")?.toLowerCase() === "true" + //Public Settings const { config } = await configs.getSettingsConfigDoc() const branding = await pro.branding.getBrandingConfig(config) @@ -140,6 +143,7 @@ export const serveApp = async function (ctx: any) { body: html, style: css.code, appId, + embedded: bbHeaderEmbed, }) } else { // just return the app info for jest to assert on diff --git a/packages/server/src/api/controllers/static/templates/app.hbs b/packages/server/src/api/controllers/static/templates/app.hbs index 1109b76cea..e55ab08e84 100644 --- a/packages/server/src/api/controllers/static/templates/app.hbs +++ b/packages/server/src/api/controllers/static/templates/app.hbs @@ -1,4 +1,3 @@ - @@ -7,6 +6,7 @@ {{{body}}} diff --git a/packages/server/src/api/routes/tests/analytics.spec.js b/packages/server/src/api/routes/tests/analytics.spec.js index ac7cd978c8..5dfe2ce3e6 100644 --- a/packages/server/src/api/routes/tests/analytics.spec.js +++ b/packages/server/src/api/routes/tests/analytics.spec.js @@ -55,7 +55,22 @@ describe("/static", () => { .expect(200) expect(events.serve.servedApp).toBeCalledTimes(1) - expect(events.serve.servedApp).toBeCalledWith(config.getProdApp(), timezone) + expect(events.serve.servedApp).toBeCalledWith(config.getProdApp(), timezone, undefined) + expect(events.serve.servedAppPreview).not.toBeCalled() + }) + + it("should ping from an embedded app", async () => { + const headers = config.defaultHeaders() + headers[constants.Header.APP_ID] = config.prodAppId + + await request + .post("/api/bbtel/ping") + .send({source: "app", timezone, embedded: true}) + .set(headers) + .expect(200) + + expect(events.serve.servedApp).toBeCalledTimes(1) + expect(events.serve.servedApp).toBeCalledWith(config.getProdApp(), timezone, true) expect(events.serve.servedAppPreview).not.toBeCalled() }) }) diff --git a/packages/server/src/middleware/builder.ts b/packages/server/src/middleware/builder.ts index 31c4da127c..b9481e60e2 100644 --- a/packages/server/src/middleware/builder.ts +++ b/packages/server/src/middleware/builder.ts @@ -86,12 +86,6 @@ export default async function builder(ctx: UserCtx) { const referer = ctx.headers["referer"] - const overviewPath = "/builder/portal/overview/" - const overviewContext = !referer ? false : referer.includes(overviewPath) - if (overviewContext) { - return - } - const hasAppId = !referer ? false : referer.includes(appId) const editingApp = referer ? hasAppId : false // check this is a builder call and editing diff --git a/packages/types/src/api/web/analytics.ts b/packages/types/src/api/web/analytics.ts index 018c85ded2..172aeb8dd4 100644 --- a/packages/types/src/api/web/analytics.ts +++ b/packages/types/src/api/web/analytics.ts @@ -6,4 +6,5 @@ export enum PingSource { export interface AnalyticsPingRequest { source: PingSource timezone: string + embedded?: boolean } diff --git a/packages/types/src/sdk/events/serve.ts b/packages/types/src/sdk/events/serve.ts index cb03c47e05..7b81a0e195 100644 --- a/packages/types/src/sdk/events/serve.ts +++ b/packages/types/src/sdk/events/serve.ts @@ -7,6 +7,7 @@ export interface BuilderServedEvent extends BaseEvent { export interface AppServedEvent extends BaseEvent { appVersion: string timezone: string + embed?: boolean } export interface AppPreviewServedEvent extends BaseEvent {