diff --git a/packages/backend-core/src/constants.js b/packages/backend-core/src/constants.js index 559dc0e6b2..42450190e5 100644 --- a/packages/backend-core/src/constants.js +++ b/packages/backend-core/src/constants.js @@ -16,6 +16,7 @@ exports.Headers = { API_VER: "x-budibase-api-version", APP_ID: "x-budibase-app-id", TYPE: "x-budibase-type", + PREVIEW_ROLE: "x-budibase-role", TENANT_ID: "x-budibase-tenant-id", TOKEN: "x-budibase-token", CSRF_TOKEN: "x-csrf-token", diff --git a/packages/bbui/src/Layout/Layout.svelte b/packages/bbui/src/Layout/Layout.svelte index 0dcb1f46ee..c66a409242 100644 --- a/packages/bbui/src/Layout/Layout.svelte +++ b/packages/bbui/src/Layout/Layout.svelte @@ -36,6 +36,10 @@ padding-left: var(--spacing-l); padding-right: var(--spacing-l); } + .paddingX-XL { + padding-left: var(--spacing-xl); + padding-right: var(--spacing-xl); + } .paddingY-S { padding-top: var(--spacing-s); padding-bottom: var(--spacing-s); @@ -48,6 +52,10 @@ padding-top: var(--spacing-l); padding-bottom: var(--spacing-l); } + .paddingY-XL { + padding-top: var(--spacing-xl); + padding-bottom: var(--spacing-xl); + } .gap-XXS { grid-gap: var(--spacing-xs); } diff --git a/packages/bbui/src/Table/InternalRenderer.svelte b/packages/bbui/src/Table/InternalRenderer.svelte index 7e2dd0b2aa..d38fb9f691 100644 --- a/packages/bbui/src/Table/InternalRenderer.svelte +++ b/packages/bbui/src/Table/InternalRenderer.svelte @@ -1,42 +1,21 @@ diff --git a/packages/bbui/src/Tabs/Tabs.svelte b/packages/bbui/src/Tabs/Tabs.svelte index 6930a6cdb5..579c61e28d 100644 --- a/packages/bbui/src/Tabs/Tabs.svelte +++ b/packages/bbui/src/Tabs/Tabs.svelte @@ -108,7 +108,7 @@ padding-left: var(--spacing-xl); padding-right: var(--spacing-xl); position: relative; - border-bottom: var(--border-light); + border-bottom: 1px solid var(--spectrum-global-color-gray-300); } .spectrum-Tabs-content { margin-top: var(--spectrum-global-dimension-static-size-150); diff --git a/packages/bbui/src/helpers.js b/packages/bbui/src/helpers.js index cf40e12d74..b02783e0bd 100644 --- a/packages/bbui/src/helpers.js +++ b/packages/bbui/src/helpers.js @@ -106,3 +106,29 @@ export const deepSet = (obj, key, value) => { export const cloneDeep = obj => { return JSON.parse(JSON.stringify(obj)) } + +/** + * Copies a value to the clipboard + * @param value the value to copy + */ +export const copyToClipboard = value => { + return new Promise(res => { + if (navigator.clipboard && window.isSecureContext) { + // Try using the clipboard API first + navigator.clipboard.writeText(value).then(res) + } else { + // Fall back to the textarea hack + let textArea = document.createElement("textarea") + textArea.value = value + textArea.style.position = "fixed" + textArea.style.left = "-9999px" + textArea.style.top = "-9999px" + document.body.appendChild(textArea) + textArea.focus() + textArea.select() + document.execCommand("copy") + textArea.remove() + res() + } + }) +} diff --git a/packages/bbui/yarn.lock b/packages/bbui/yarn.lock index 2b6b15dd15..0b20a580ba 100644 --- a/packages/bbui/yarn.lock +++ b/packages/bbui/yarn.lock @@ -53,10 +53,10 @@ to-gfm-code-block "^0.1.1" year "^0.2.1" -"@budibase/string-templates@^1.0.104": - version "1.0.104" - resolved "https://registry.yarnpkg.com/@budibase/string-templates/-/string-templates-1.0.104.tgz#f812700f2b21f638fd1e48dde065ae693fae2897" - integrity sha512-3caq3qwpIieyb9m8eSl8OhcE0ppzuyJ/0ubDlWmtpbmwmG2v3ynI+DwxpbG4CcVQFuebD2yxU0CZfioU76vKCQ== +"@budibase/string-templates@^1.0.105-alpha.4": + version "1.0.108" + resolved "https://registry.yarnpkg.com/@budibase/string-templates/-/string-templates-1.0.108.tgz#14949560148ef11b6b385952ed5787c12b890f2c" + integrity sha512-7Tts91Dzy+A7OdObTIaBNAdaixC7wmabnNTWYqk1d6TM6H5yv++bd/a9gVdUM7ptsuMy7uoP/ZoTZZRhp3ozfA== dependencies: "@budibase/handlebars-helpers" "^0.11.8" dayjs "^1.10.4" diff --git a/packages/client/src/api/api.js b/packages/client/src/api/api.js index 591d4a6782..1d575d9d27 100644 --- a/packages/client/src/api/api.js +++ b/packages/client/src/api/api.js @@ -1,5 +1,5 @@ import { createAPIClient } from "@budibase/frontend-core" -import { notificationStore, authStore } from "../stores" +import { notificationStore, authStore, devToolsStore } from "../stores" import { get } from "svelte/store" export const API = createAPIClient({ @@ -21,6 +21,12 @@ export const API = createAPIClient({ if (auth?.csrfToken) { headers["x-csrf-token"] = auth.csrfToken } + + // Add role header + const role = get(devToolsStore).role + if (role) { + headers["x-budibase-role"] = role + } }, // Show an error notification for all API failures. diff --git a/packages/client/src/components/ClientApp.svelte b/packages/client/src/components/ClientApp.svelte index 27767862ab..6bd0313c75 100644 --- a/packages/client/src/components/ClientApp.svelte +++ b/packages/client/src/components/ClientApp.svelte @@ -14,6 +14,8 @@ routeStore, builderStore, themeStore, + appStore, + devToolsStore, } from "stores" import NotificationDisplay from "components/overlay/NotificationDisplay.svelte" import ConfirmationDisplay from "components/overlay/ConfirmationDisplay.svelte" @@ -28,6 +30,8 @@ import CustomThemeWrapper from "./CustomThemeWrapper.svelte" import DNDHandler from "components/preview/DNDHandler.svelte" import KeyboardManager from "components/preview/KeyboardManager.svelte" + import DevToolsHeader from "components/devtools/DevToolsHeader.svelte" + import DevTools from "components/devtools/DevTools.svelte" // Provide contexts setContext("sdk", SDK) @@ -55,8 +59,22 @@ if ($authStore) { // There is a logged in user, so handle them if ($screenStore.screens.length) { + let firstRoute + + // If using devtools, find the first screen matching our role + if ($devToolsStore.role) { + const roleRoutes = $screenStore.screens.filter( + screen => screen.routing?.roleId === $devToolsStore.role + ) + firstRoute = roleRoutes[0]?.routing?.route || "/" + } + + // Otherwise just use the first route + else { + firstRoute = $screenStore.screens[0]?.routing?.route ?? "/" + } + // 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 @@ -70,6 +88,8 @@ } } } + + $: isDevPreview = $appStore.isDevApp && !$builderStore.inBuilder {#if dataLoaded} @@ -109,39 +129,49 @@ >