diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md
new file mode 100644
index 0000000000..b89ca2f78c
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/feature_request.md
@@ -0,0 +1,14 @@
+---
+name: Feature Request
+about: Request a new budibase feature or enhancement
+title: ''
+labels: enhancement
+assignees: ''
+
+---
+
+**Describe the feature request**
+A clear and concise description of what the feature request.
+
+**Screenshots**
+If applicable, add screenshots to help explain your problem.
diff --git a/README.md b/README.md
index c57b319ec5..9f9092b399 100644
--- a/README.md
+++ b/README.md
@@ -57,7 +57,7 @@
 
 - **Open source and extensible.** Budibase is open-source - licensed as GPL v3. This should fill you with confidence that Budibase will always be around. You can also code against Budibase or fork it and make changes as you please, providing a developer-friendly experience.
 
-- **Load data or start from scratch.** Budibase pulls in data from multiple sources, including MongoDB, CouchDB, PostgreSQL, mySQL, Airtable, S3, DyanmoDB, or a REST API. And unlike other platforms, with Budibase you can start from scratch and create business apps with no data sources. [Request new data sources](https://github.com/Budibase/budibase/discussions?discussions_q=category%3AIdeas).
+- **Load data or start from scratch.** Budibase pulls in data from multiple sources, including MongoDB, CouchDB, PostgreSQL, MySQL, Airtable, S3, DynamoDB, or a REST API. And unlike other platforms, with Budibase you can start from scratch and create business apps with no data sources. [Request new data sources](https://github.com/Budibase/budibase/discussions?discussions_q=category%3AIdeas).
 
 - **Design and build apps with powerful pre-made components.** Budibase comes out of the box with beautifully designed, powerful components which you can use like building blocks to build your UI. We also expose a lot of your favourite CSS styling options so you can go that extra creative mile. [Request new component](https://github.com/Budibase/budibase/discussions?discussions_q=category%3AIdeas).
 
diff --git a/lerna.json b/lerna.json
index 5544fba007..b53d8a28b4 100644
--- a/lerna.json
+++ b/lerna.json
@@ -1,5 +1,5 @@
 {
-  "version": "0.9.87-alpha.7",
+  "version": "0.9.96",
   "npmClient": "yarn",
   "packages": [
     "packages/*"
diff --git a/packages/auth/package.json b/packages/auth/package.json
index 010f6a60fc..05687014d3 100644
--- a/packages/auth/package.json
+++ b/packages/auth/package.json
@@ -1,6 +1,6 @@
 {
   "name": "@budibase/auth",
-  "version": "0.9.87-alpha.7",
+  "version": "0.9.96",
   "description": "Authentication middlewares for budibase builder and apps",
   "main": "src/index.js",
   "author": "Budibase",
diff --git a/packages/auth/src/middleware/authenticated.js b/packages/auth/src/middleware/authenticated.js
index 647ec659f5..b58e1917fd 100644
--- a/packages/auth/src/middleware/authenticated.js
+++ b/packages/auth/src/middleware/authenticated.js
@@ -66,6 +66,7 @@ module.exports = (noAuthPatterns = [], opts) => {
           }
         }
         if (error) {
+          console.error("Auth Error", error)
           // remove the cookie as the user does not exist anymore
           clearCookie(ctx, Cookies.Auth)
         } else {
diff --git a/packages/auth/src/middleware/passport/third-party-common.js b/packages/auth/src/middleware/passport/third-party-common.js
index 54252b329d..6c71614679 100644
--- a/packages/auth/src/middleware/passport/third-party-common.js
+++ b/packages/auth/src/middleware/passport/third-party-common.js
@@ -6,7 +6,6 @@ const { authError } = require("./utils")
 const { newid } = require("../../hashing")
 const { createASession } = require("../../security/sessions")
 const { getGlobalUserByEmail } = require("../../utils")
-const fetch = require("node-fetch")
 
 /**
  * Common authentication logic for third parties. e.g. OAuth, OIDC.
diff --git a/packages/bbui/package.json b/packages/bbui/package.json
index c3c01e6cbb..2d5a4054c6 100644
--- a/packages/bbui/package.json
+++ b/packages/bbui/package.json
@@ -1,7 +1,7 @@
 {
   "name": "@budibase/bbui",
   "description": "A UI solution used in the different Budibase projects.",
-  "version": "0.9.87-alpha.7",
+  "version": "0.9.96",
   "license": "AGPL-3.0",
   "svelte": "src/index.js",
   "module": "dist/bbui.es.js",
diff --git a/packages/bbui/src/Modal/Modal.svelte b/packages/bbui/src/Modal/Modal.svelte
index c93467bc75..f805dec0ad 100644
--- a/packages/bbui/src/Modal/Modal.svelte
+++ b/packages/bbui/src/Modal/Modal.svelte
@@ -70,6 +70,7 @@
     >
       <div class="modal-wrapper" on:mousedown|self={cancel}>
         <div class="modal-inner-wrapper" on:mousedown|self={cancel}>
+          <slot name="outside" />
           <div
             use:focusFirstInput
             class="spectrum-Modal is-open"
@@ -93,6 +94,7 @@
     z-index: 999;
     overflow: auto;
     overflow-x: hidden;
+    background: rgba(0, 0, 0, 0.75);
   }
 
   .modal-wrapper {
@@ -112,6 +114,7 @@
     justify-content: center;
     align-items: flex-start;
     width: 0;
+    position: relative;
   }
 
   .spectrum-Modal {
@@ -122,6 +125,7 @@
     --spectrum-dialog-confirm-border-radius: var(
       --spectrum-global-dimension-size-100
     );
+    max-width: 100%;
   }
   :global(.spectrum--lightest .spectrum-Modal.inline) {
     border: var(--border-light);
diff --git a/packages/bbui/src/Modal/ModalContent.svelte b/packages/bbui/src/Modal/ModalContent.svelte
index e6d4ab5f0f..bba72e6093 100644
--- a/packages/bbui/src/Modal/ModalContent.svelte
+++ b/packages/bbui/src/Modal/ModalContent.svelte
@@ -15,6 +15,7 @@
   export let showCloseIcon = true
   export let onConfirm = undefined
   export let disabled = false
+  export let showDivider = true
 
   const { hide, cancel } = getContext(Context.Modal)
   let loading = false
@@ -41,11 +42,17 @@
   aria-modal="true"
 >
   <div class="spectrum-Dialog-grid">
-    <h1 class="spectrum-Dialog-heading spectrum-Dialog-heading--noHeader">
-      {title}
-    </h1>
-
-    <Divider size="M" />
+    {#if title}
+      <h1
+        class="spectrum-Dialog-heading spectrum-Dialog-heading--noHeader"
+        class:noDivider={!showDivider}
+      >
+        {title}
+      </h1>
+      {#if showDivider}
+        <Divider size="M" />
+      {/if}
+    {/if}
     <!-- TODO: Remove content-grid class once Layout components are in bbui -->
     <section class="spectrum-Dialog-content content-grid">
       <slot />
@@ -72,8 +79,8 @@
       </div>
     {/if}
     {#if showCloseIcon}
-      <div class="close-icon" on:click={hide}>
-        <Icon hoverable name="Close" />
+      <div class="close-icon">
+        <Icon hoverable name="Close" on:click={cancel} />
       </div>
     {/if}
   </div>
@@ -96,6 +103,9 @@
   .spectrum-Dialog-heading {
     font-family: var(--font-sans);
   }
+  .spectrum-Dialog-heading.noDivider {
+    margin-bottom: 12px;
+  }
 
   .spectrum-Dialog-buttonGroup {
     gap: var(--spectrum-global-dimension-static-size-200);
diff --git a/packages/bbui/src/Notification/Notification.svelte b/packages/bbui/src/Notification/Notification.svelte
new file mode 100644
index 0000000000..cebc859bda
--- /dev/null
+++ b/packages/bbui/src/Notification/Notification.svelte
@@ -0,0 +1,20 @@
+<script>
+  export let type = "info"
+  export let icon = "Info"
+  export let message = ""
+</script>
+
+<div class="spectrum-Toast spectrum-Toast--{type}">
+  {#if icon}
+    <svg
+      class="spectrum-Icon spectrum-Icon--sizeM spectrum-Toast-typeIcon"
+      focusable="false"
+      aria-hidden="true"
+    >
+      <use xlink:href="#spectrum-icon-18-{icon}" />
+    </svg>
+  {/if}
+  <div class="spectrum-Toast-body">
+    <div class="spectrum-Toast-content">{message || ""}</div>
+  </div>
+</div>
diff --git a/packages/bbui/src/Notification/NotificationDisplay.svelte b/packages/bbui/src/Notification/NotificationDisplay.svelte
index 89e7666cc7..9d96bf7e70 100644
--- a/packages/bbui/src/Notification/NotificationDisplay.svelte
+++ b/packages/bbui/src/Notification/NotificationDisplay.svelte
@@ -2,30 +2,16 @@
   import "@spectrum-css/toast/dist/index-vars.css"
   import Portal from "svelte-portal"
   import { flip } from "svelte/animate"
-  import { fly } from "svelte/transition"
   import { notifications } from "../Stores/notifications"
+  import Notification from "./Notification.svelte"
+  import { fly } from "svelte/transition"
 </script>
 
 <Portal target=".modal-container">
   <div class="notifications">
     {#each $notifications as { type, icon, message, id } (id)}
-      <div
-        animate:flip
-        transition:fly={{ y: -30 }}
-        class="spectrum-Toast spectrum-Toast--{type} notification-offset"
-      >
-        {#if icon}
-          <svg
-            class="spectrum-Icon spectrum-Icon--sizeM spectrum-Toast-typeIcon"
-            focusable="false"
-            aria-hidden="true"
-          >
-            <use xlink:href="#spectrum-icon-18-{icon}" />
-          </svg>
-        {/if}
-        <div class="spectrum-Toast-body">
-          <div class="spectrum-Toast-content">{message}</div>
-        </div>
+      <div animate:flip transition:fly={{ y: -30 }}>
+        <Notification {type} {icon} {message} />
       </div>
     {/each}
   </div>
@@ -34,7 +20,7 @@
 <style>
   .notifications {
     position: fixed;
-    top: 10px;
+    top: 20px;
     left: 0;
     right: 0;
     margin: 0 auto;
@@ -45,8 +31,6 @@
     justify-content: flex-start;
     align-items: center;
     pointer-events: none;
-  }
-  .notification-offset {
-    margin-bottom: 10px;
+    gap: 10px;
   }
 </style>
diff --git a/packages/bbui/src/index.js b/packages/bbui/src/index.js
index 4d045e504b..3a491bfb54 100644
--- a/packages/bbui/src/index.js
+++ b/packages/bbui/src/index.js
@@ -38,6 +38,7 @@ export { default as MenuItem } from "./Menu/Item.svelte"
 export { default as Modal } from "./Modal/Modal.svelte"
 export { default as ModalContent } from "./Modal/ModalContent.svelte"
 export { default as NotificationDisplay } from "./Notification/NotificationDisplay.svelte"
+export { default as Notification } from "./Notification/Notification.svelte"
 export { default as SideNavigation } from "./SideNavigation/Navigation.svelte"
 export { default as SideNavigationItem } from "./SideNavigation/Item.svelte"
 export { default as DatePicker } from "./Form/DatePicker.svelte"
diff --git a/packages/builder/package.json b/packages/builder/package.json
index b5d93beb9d..5fa5b41e0b 100644
--- a/packages/builder/package.json
+++ b/packages/builder/package.json
@@ -1,6 +1,6 @@
 {
   "name": "@budibase/builder",
-  "version": "0.9.87-alpha.7",
+  "version": "0.9.96",
   "license": "AGPL-3.0",
   "private": true,
   "scripts": {
@@ -65,10 +65,10 @@
     }
   },
   "dependencies": {
-    "@budibase/bbui": "^0.9.87-alpha.7",
-    "@budibase/client": "^0.9.87-alpha.7",
+    "@budibase/bbui": "^0.9.96",
+    "@budibase/client": "^0.9.96",
     "@budibase/colorpicker": "1.1.2",
-    "@budibase/string-templates": "^0.9.87-alpha.7",
+    "@budibase/string-templates": "^0.9.96",
     "@sentry/browser": "5.19.1",
     "@spectrum-css/page": "^3.0.1",
     "@spectrum-css/vars": "^3.0.1",
diff --git a/packages/builder/src/builderStore/store/frontend.js b/packages/builder/src/builderStore/store/frontend.js
index f84e1c8735..3339ea07d6 100644
--- a/packages/builder/src/builderStore/store/frontend.js
+++ b/packages/builder/src/builderStore/store/frontend.js
@@ -70,7 +70,7 @@ export const getFrontendStore = () => {
         url: application.url,
         layouts,
         screens,
-        theme: application.theme,
+        theme: application.theme || "spectrum--light",
         hasAppPackage: true,
         appInstance: application.instance,
         clientLibPath,
diff --git a/packages/builder/src/components/common/bindings/DrawerBindableCombobox.svelte b/packages/builder/src/components/common/bindings/DrawerBindableCombobox.svelte
index 38f8693f51..a48a91a44f 100644
--- a/packages/builder/src/components/common/bindings/DrawerBindableCombobox.svelte
+++ b/packages/builder/src/components/common/bindings/DrawerBindableCombobox.svelte
@@ -18,8 +18,8 @@
 
   const dispatch = createEventDispatcher()
   let bindingDrawer
-  $: tempValue = Array.isArray(value) ? value : []
   $: readableValue = runtimeToReadableBinding(bindings, value)
+  $: tempValue = readableValue
 
   const handleClose = () => {
     onChange(tempValue)
@@ -56,7 +56,7 @@
     slot="body"
     value={readableValue}
     close={handleClose}
-    on:update={event => (tempValue = event.detail)}
+    on:change={event => (tempValue = event.detail)}
     bindableProperties={bindings}
   />
 </Drawer>
diff --git a/packages/builder/src/components/design/AppPreview/AppThemeSelect.svelte b/packages/builder/src/components/design/AppPreview/AppThemeSelect.svelte
index c9d937593b..21dae25708 100644
--- a/packages/builder/src/components/design/AppPreview/AppThemeSelect.svelte
+++ b/packages/builder/src/components/design/AppPreview/AppThemeSelect.svelte
@@ -24,7 +24,7 @@
 
 <div>
   <Select
-    value={$store.theme || "spectrum--light"}
+    value={$store.theme}
     options={themeOptions}
     placeholder={null}
     on:change={e => store.actions.theme.save(e.detail)}
diff --git a/packages/builder/src/components/design/AppPreview/iframeTemplate.js b/packages/builder/src/components/design/AppPreview/iframeTemplate.js
index 9ae26bdaaf..1e3ff7c856 100644
--- a/packages/builder/src/components/design/AppPreview/iframeTemplate.js
+++ b/packages/builder/src/components/design/AppPreview/iframeTemplate.js
@@ -47,6 +47,18 @@ export default `
           return
         }
 
+        // Parse received message
+        // If parsing fails, just ignore and wait for the next message
+        let parsed
+        try {
+          parsed = JSON.parse(event.data)
+        } catch (error) {
+          // Ignore
+        }
+        if (!parsed) {
+          return
+        }
+        
         // Extract data from message
         const {
           selectedComponentId,
@@ -55,7 +67,7 @@ export default `
           previewType,
           appId,
           theme
-        } = JSON.parse(event.data)
+        } = parsed
 
         // Set some flags so the app knows we're in the builder
         window["##BUDIBASE_IN_BUILDER##"] = true
diff --git a/packages/builder/src/components/design/PropertiesPanel/ComponentSettingsSection.svelte b/packages/builder/src/components/design/PropertiesPanel/ComponentSettingsSection.svelte
index 0900bae1a7..972a2bb7fe 100644
--- a/packages/builder/src/components/design/PropertiesPanel/ComponentSettingsSection.svelte
+++ b/packages/builder/src/components/design/PropertiesPanel/ComponentSettingsSection.svelte
@@ -11,6 +11,7 @@
   export let componentDefinition
   export let componentInstance
   export let assetInstance
+  export let bindings
 
   const layoutDefinition = []
   const screenDefinition = [
@@ -65,6 +66,7 @@
             options: setting.options,
             placeholder: setting.placeholder,
           }}
+          {bindings}
         />
       {/if}
     {/each}
diff --git a/packages/builder/src/components/design/PropertiesPanel/ConditionalUISection.svelte b/packages/builder/src/components/design/PropertiesPanel/ConditionalUISection.svelte
index b1f65f3593..2802f38c2b 100644
--- a/packages/builder/src/components/design/PropertiesPanel/ConditionalUISection.svelte
+++ b/packages/builder/src/components/design/PropertiesPanel/ConditionalUISection.svelte
@@ -4,6 +4,7 @@
   import ConditionalUIDrawer from "./PropertyControls/ConditionalUIDrawer.svelte"
 
   export let componentInstance
+  export let bindings
 
   let tempValue
   let drawer
@@ -32,5 +33,5 @@
     Show, hide and update components in response to conditions being met.
   </svelte:fragment>
   <Button cta slot="buttons" on:click={() => save()}>Save</Button>
-  <ConditionalUIDrawer slot="body" bind:conditions={tempValue} />
+  <ConditionalUIDrawer slot="body" bind:conditions={tempValue} {bindings} />
 </Drawer>
diff --git a/packages/builder/src/components/design/PropertiesPanel/DesignSection.svelte b/packages/builder/src/components/design/PropertiesPanel/DesignSection.svelte
index 639ac90586..fa1a357f38 100644
--- a/packages/builder/src/components/design/PropertiesPanel/DesignSection.svelte
+++ b/packages/builder/src/components/design/PropertiesPanel/DesignSection.svelte
@@ -4,6 +4,7 @@
 
   export let componentDefinition
   export let componentInstance
+  export let bindings
 
   const getStyles = def => {
     if (!def?.styles?.length) {
@@ -29,6 +30,7 @@
       columns={style.columns}
       properties={style.settings}
       {componentInstance}
+      {bindings}
     />
   {/each}
 {/if}
diff --git a/packages/builder/src/components/design/PropertiesPanel/PropertiesPanel.svelte b/packages/builder/src/components/design/PropertiesPanel/PropertiesPanel.svelte
index e85c30a171..27f6650cde 100644
--- a/packages/builder/src/components/design/PropertiesPanel/PropertiesPanel.svelte
+++ b/packages/builder/src/components/design/PropertiesPanel/PropertiesPanel.svelte
@@ -1,27 +1,45 @@
 <script>
-  import { store, selectedComponent } from "builderStore"
+  import { store, selectedComponent, currentAsset } from "builderStore"
   import { Tabs, Tab } from "@budibase/bbui"
   import ScreenSettingsSection from "./ScreenSettingsSection.svelte"
   import ComponentSettingsSection from "./ComponentSettingsSection.svelte"
   import DesignSection from "./DesignSection.svelte"
   import CustomStylesSection from "./CustomStylesSection.svelte"
   import ConditionalUISection from "./ConditionalUISection.svelte"
+  import { getBindableProperties } from "builderStore/dataBinding"
 
   $: componentInstance = $selectedComponent
   $: componentDefinition = store.actions.components.getDefinition(
     $selectedComponent?._component
   )
+  $: bindings = getBindableProperties($currentAsset, $store.selectedComponentId)
 </script>
 
 <Tabs selected="Settings" noPadding>
   <Tab title="Settings">
     <div class="container">
       {#key componentInstance?._id}
-        <ScreenSettingsSection {componentInstance} {componentDefinition} />
-        <ComponentSettingsSection {componentInstance} {componentDefinition} />
-        <DesignSection {componentInstance} {componentDefinition} />
-        <CustomStylesSection {componentInstance} {componentDefinition} />
-        <ConditionalUISection {componentInstance} {componentDefinition} />
+        <ScreenSettingsSection
+          {componentInstance}
+          {componentDefinition}
+          {bindings}
+        />
+        <ComponentSettingsSection
+          {componentInstance}
+          {componentDefinition}
+          {bindings}
+        />
+        <DesignSection {componentInstance} {componentDefinition} {bindings} />
+        <CustomStylesSection
+          {componentInstance}
+          {componentDefinition}
+          {bindings}
+        />
+        <ConditionalUISection
+          {componentInstance}
+          {componentDefinition}
+          {bindings}
+        />
       {/key}
     </div>
   </Tab>
diff --git a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/ConditionalUIDrawer.svelte b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/ConditionalUIDrawer.svelte
index 8b9cad1b7c..006039edda 100644
--- a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/ConditionalUIDrawer.svelte
+++ b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/ConditionalUIDrawer.svelte
@@ -13,12 +13,12 @@
   import { generate } from "shortid"
   import DrawerBindableInput from "components/common/bindings/DrawerBindableInput.svelte"
   import { OperatorOptions, getValidOperatorsForType } from "helpers/lucene"
-  import { getBindableProperties } from "builderStore/dataBinding"
-  import { currentAsset, selectedComponent, store } from "builderStore"
+  import { selectedComponent, store } from "builderStore"
   import { getComponentForSettingType } from "./componentSettings"
   import PropertyControl from "./PropertyControl.svelte"
 
   export let conditions = []
+  export let bindings = []
 
   const flipDurationMs = 150
   const actionOptions = [
@@ -64,10 +64,6 @@
       value: setting.key,
     }
   })
-  $: bindableProperties = getBindableProperties(
-    $currentAsset,
-    $store.selectedComponentId
-  )
   $: conditions.forEach(link => {
     if (!link.id) {
       link.id = generate()
@@ -194,6 +190,7 @@
                       placeholder: getSettingDefinition(condition.setting)
                         .placeholder,
                     }}
+                    {bindings}
                   />
                 {:else}
                   <Select disabled placeholder=" " />
@@ -201,7 +198,7 @@
               {/if}
               <div>IF</div>
               <DrawerBindableInput
-                bindings={bindableProperties}
+                {bindings}
                 placeholder="Value"
                 value={condition.newValue}
                 on:change={e => (condition.newValue = e.detail)}
@@ -222,7 +219,7 @@
               {#if ["string", "number"].includes(condition.valueType)}
                 <DrawerBindableInput
                   disabled={condition.noValue}
-                  bindings={bindableProperties}
+                  {bindings}
                   placeholder="Value"
                   value={condition.referenceValue}
                   on:change={e => (condition.referenceValue = e.detail)}
diff --git a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/DataSourceSelect.svelte b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/DataSourceSelect.svelte
index c8ce846192..d86f13e100 100644
--- a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/DataSourceSelect.svelte
+++ b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/DataSourceSelect.svelte
@@ -1,8 +1,5 @@
 <script>
-  import {
-    getBindableProperties,
-    getDataProviderComponents,
-  } from "builderStore/dataBinding"
+  import { getDataProviderComponents } from "builderStore/dataBinding"
   import {
     Button,
     Popover,
@@ -31,6 +28,7 @@
   export let value = {}
   export let otherSources
   export let showAllQueries
+  export let bindings = []
 
   $: text = value?.label ?? "Choose an option"
   $: tables = $tablesStore.list.map(m => ({
@@ -60,10 +58,6 @@
       parameters: query.parameters,
       type: "query",
     }))
-  $: bindableProperties = getBindableProperties(
-    $currentAsset,
-    $store.selectedComponentId
-  )
   $: dataProviders = getDataProviderComponents(
     $currentAsset,
     $store.selectedComponentId
@@ -75,13 +69,13 @@
     type: "provider",
     schema: provider.schema,
   }))
-  $: queryBindableProperties = bindableProperties.map(property => ({
+  $: queryBindableProperties = bindings.map(property => ({
     ...property,
     category: property.type === "instance" ? "Component" : "Table",
     label: property.readableBinding,
     path: property.readableBinding,
   }))
-  $: links = bindableProperties
+  $: links = bindings
     .filter(x => x.fieldSchema?.type === "link")
     .map(property => {
       return {
@@ -138,7 +132,7 @@
               bind:customParams={value.queryParams}
               parameters={queries.find(query => query._id === value._id)
                 .parameters}
-              bindings={queryBindableProperties}
+              {bindings}
             />
           {/if}
           <IntegrationQueryEditor
diff --git a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/EventsEditor/EventEditor.svelte b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/EventsEditor/EventEditor.svelte
index 444aab5fe9..2e2a318610 100644
--- a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/EventsEditor/EventEditor.svelte
+++ b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/EventsEditor/EventEditor.svelte
@@ -13,10 +13,10 @@
   import { generate } from "shortid"
 
   const flipDurationMs = 150
-
   const EVENT_TYPE_KEY = "##eventHandlerType"
 
   export let actions
+  export let bindings = []
 
   // dndzone needs an id on the array items, so this adds some temporary ones.
   $: {
@@ -121,6 +121,7 @@
         <svelte:component
           this={selectedActionComponent}
           parameters={selectedAction.parameters}
+          {bindings}
         />
       </div>
     {/if}
diff --git a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/EventsEditor/EventPropertyControl.svelte b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/EventsEditor/EventPropertyControl.svelte
index 0fea9a0505..9e39fd48e9 100644
--- a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/EventsEditor/EventPropertyControl.svelte
+++ b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/EventsEditor/EventPropertyControl.svelte
@@ -9,6 +9,7 @@
 
   export let value = []
   export let name
+  export let bindings
 
   let drawer
 
@@ -57,5 +58,5 @@
     Define what actions to run.
   </svelte:fragment>
   <Button cta slot="buttons" on:click={saveEventData}>Save</Button>
-  <EventEditor slot="body" bind:actions={value} eventType={name} />
+  <EventEditor slot="body" bind:actions={value} eventType={name} {bindings} />
 </Drawer>
diff --git a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/EventsEditor/actions/CloseScreenModal.svelte b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/EventsEditor/actions/CloseScreenModal.svelte
new file mode 100644
index 0000000000..0afb8dd46e
--- /dev/null
+++ b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/EventsEditor/actions/CloseScreenModal.svelte
@@ -0,0 +1,17 @@
+<script>
+  import { Body } from "@budibase/bbui"
+</script>
+
+<div class="root">
+  <Body size="S">This action doesn't require any additional settings.</Body>
+  <Body size="S">
+    This action won't do anything if there isn't a screen modal open.
+  </Body>
+</div>
+
+<style>
+  .root {
+    max-width: 800px;
+    margin: 0 auto;
+  }
+</style>
diff --git a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/EventsEditor/actions/DeleteRow.svelte b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/EventsEditor/actions/DeleteRow.svelte
index aa657beea5..35a1a6ec86 100644
--- a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/EventsEditor/actions/DeleteRow.svelte
+++ b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/EventsEditor/actions/DeleteRow.svelte
@@ -1,14 +1,12 @@
 <script>
   import { Select, Label, Checkbox, Input } from "@budibase/bbui"
-  import { store, currentAsset } from "builderStore"
   import { tables } from "stores/backend"
-  import { getBindableProperties } from "builderStore/dataBinding"
   import DrawerBindableInput from "components/common/bindings/DrawerBindableInput.svelte"
 
   export let parameters
+  export let bindings = []
 
   $: tableOptions = $tables.list || []
-  $: bindings = getBindableProperties($currentAsset, $store.selectedComponentId)
 </script>
 
 <div class="root">
diff --git a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/EventsEditor/actions/ExecuteQuery.svelte b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/EventsEditor/actions/ExecuteQuery.svelte
index d4e70dac05..5dc56a7d74 100644
--- a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/EventsEditor/actions/ExecuteQuery.svelte
+++ b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/EventsEditor/actions/ExecuteQuery.svelte
@@ -1,21 +1,16 @@
 <script>
   import { Select, Layout, Input, Checkbox } from "@budibase/bbui"
-  import { store, currentAsset } from "builderStore"
   import { datasources, integrations, queries } from "stores/backend"
-  import { getBindableProperties } from "builderStore/dataBinding"
   import ParameterBuilder from "components/integration/QueryParameterBuilder.svelte"
   import IntegrationQueryEditor from "components/integration/index.svelte"
 
   export let parameters
+  export let bindings = []
 
   $: query = $queries.list.find(q => q._id === parameters.queryId)
   $: datasource = $datasources.list.find(
     ds => ds._id === parameters.datasourceId
   )
-  $: bindableProperties = getBindableProperties(
-    $currentAsset,
-    $store.selectedComponentId
-  )
 
   function fetchQueryDefinition(query) {
     const source = $datasources.list.find(
@@ -61,7 +56,7 @@
           <ParameterBuilder
             bind:customParams={parameters.queryParams}
             parameters={query.parameters}
-            bindings={bindableProperties}
+            {bindings}
           />
           <IntegrationQueryEditor
             height={200}
diff --git a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/EventsEditor/actions/NavigateTo.svelte b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/EventsEditor/actions/NavigateTo.svelte
index e713ccce4a..23db9050ab 100644
--- a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/EventsEditor/actions/NavigateTo.svelte
+++ b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/EventsEditor/actions/NavigateTo.svelte
@@ -1,12 +1,9 @@
 <script>
   import { Label } from "@budibase/bbui"
-  import { getBindableProperties } from "builderStore/dataBinding"
-  import { currentAsset, store } from "builderStore"
   import DrawerBindableInput from "components/common/bindings/DrawerBindableInput.svelte"
 
   export let parameters
-
-  $: bindings = getBindableProperties($currentAsset, $store.selectedComponentId)
+  export let bindings = []
 </script>
 
 <div class="root">
@@ -18,19 +15,17 @@
     on:change={value => (parameters.url = value.detail)}
     {bindings}
   />
+  <div />
+  <Checkbox text="Open screen in modal" bind:value={parameters.peek} />
 </div>
 
 <style>
   .root {
-    display: flex;
-    flex-direction: row;
-    align-items: baseline;
+    display: grid;
+    align-items: center;
+    gap: var(--spacing-m);
+    grid-template-columns: auto 1fr;
     max-width: 800px;
     margin: 0 auto;
   }
-
-  .root :global(> div) {
-    flex: 1;
-    margin-left: var(--spacing-l);
-  }
 </style>
diff --git a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/EventsEditor/actions/SaveFields.svelte b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/EventsEditor/actions/SaveFields.svelte
index bf88ed2caf..52bd84c453 100644
--- a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/EventsEditor/actions/SaveFields.svelte
+++ b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/EventsEditor/actions/SaveFields.svelte
@@ -1,7 +1,5 @@
 <script>
   import { Label, ActionButton, Button, Select, Input } from "@budibase/bbui"
-  import { store, currentAsset } from "builderStore"
-  import { getBindableProperties } from "builderStore/dataBinding"
   import { createEventDispatcher } from "svelte"
   import DrawerBindableInput from "components/common/bindings/DrawerBindableInput.svelte"
 
@@ -11,13 +9,10 @@
   export let schemaFields
   export let fieldLabel = "Column"
   export let valueLabel = "Value"
+  export let bindings = []
 
   let fields = Object.entries(parameterFields || {})
   $: onChange(fields)
-  $: bindableProperties = getBindableProperties(
-    $currentAsset,
-    $store.selectedComponentId
-  )
 
   const addField = () => {
     fields = [...fields.filter(field => field[0]), ["", ""]]
@@ -69,7 +64,7 @@
     <DrawerBindableInput
       title={`Value for "${field[0]}"`}
       value={field[1]}
-      bindings={bindableProperties}
+      {bindings}
       on:change={event => updateFieldValue(idx, event.detail)}
     />
     <ActionButton
diff --git a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/EventsEditor/actions/SaveRow.svelte b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/EventsEditor/actions/SaveRow.svelte
index a2c3b6d49e..791380643f 100644
--- a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/EventsEditor/actions/SaveRow.svelte
+++ b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/EventsEditor/actions/SaveRow.svelte
@@ -9,6 +9,7 @@
   import SaveFields from "./SaveFields.svelte"
 
   export let parameters
+  export let bindings = []
 
   $: dataProviderComponents = getDataProviderComponents(
     $currentAsset,
@@ -70,6 +71,7 @@
         parameterFields={parameters.fields}
         {schemaFields}
         on:change={onFieldsChanged}
+        {bindings}
       />
     </div>
   {/if}
diff --git a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/EventsEditor/actions/TriggerAutomation.svelte b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/EventsEditor/actions/TriggerAutomation.svelte
index 545a805cc5..e5b4c9d108 100644
--- a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/EventsEditor/actions/TriggerAutomation.svelte
+++ b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/EventsEditor/actions/TriggerAutomation.svelte
@@ -3,13 +3,14 @@
   import { automationStore } from "builderStore"
   import SaveFields from "./SaveFields.svelte"
 
+  export let parameters = {}
+  export let bindings = []
+
   const AUTOMATION_STATUS = {
     NEW: "new",
     EXISTING: "existing",
   }
 
-  export let parameters = {}
-
   let automationStatus = parameters.automationId
     ? AUTOMATION_STATUS.EXISTING
     : AUTOMATION_STATUS.NEW
@@ -109,6 +110,7 @@
         parameterFields={parameters.fields}
         fieldLabel="Field"
         on:change={onFieldsChanged}
+        {bindings}
       />
     {/key}
   </div>
diff --git a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/EventsEditor/actions/index.js b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/EventsEditor/actions/index.js
index bfbf97701b..c769a2300f 100644
--- a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/EventsEditor/actions/index.js
+++ b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/EventsEditor/actions/index.js
@@ -6,6 +6,7 @@ import TriggerAutomation from "./TriggerAutomation.svelte"
 import ValidateForm from "./ValidateForm.svelte"
 import LogOut from "./LogOut.svelte"
 import ClearForm from "./ClearForm.svelte"
+import CloseScreenModal from "./CloseScreenModal.svelte"
 
 // Defines which actions are available to configure in the front end.
 // Unfortunately the "name" property is used as the identifier so please don't
@@ -47,4 +48,8 @@ export default [
     name: "Clear Form",
     component: ClearForm,
   },
+  {
+    name: "Close Screen Modal",
+    component: CloseScreenModal,
+  },
 ]
diff --git a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/FilterEditor/FilterEditor.svelte b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/FilterEditor/FilterEditor.svelte
index d190200044..adcf7ec29b 100644
--- a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/FilterEditor/FilterEditor.svelte
+++ b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/FilterEditor/FilterEditor.svelte
@@ -20,6 +20,8 @@
 
   export let value = []
   export let componentInstance
+  export let bindings = []
+
   let drawer
   let tempValue = value || []
 
@@ -51,7 +53,7 @@
           constraints.
         {/if}
       </Body>
-      <LuceneFilterBuilder bind:value={tempValue} {schemaFields} />
+      <LuceneFilterBuilder bind:value={tempValue} {schemaFields} {bindings} />
     </Layout>
   </DrawerContent>
 </Drawer>
diff --git a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/FilterEditor/LuceneFilterBuilder.svelte b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/FilterEditor/LuceneFilterBuilder.svelte
index e30c7dd63d..be46169f57 100644
--- a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/FilterEditor/LuceneFilterBuilder.svelte
+++ b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/FilterEditor/LuceneFilterBuilder.svelte
@@ -7,20 +7,15 @@
     Combobox,
     Input,
   } from "@budibase/bbui"
-  import { store, currentAsset } from "builderStore"
-  import { getBindableProperties } from "builderStore/dataBinding"
   import DrawerBindableInput from "components/common/bindings/DrawerBindableInput.svelte"
   import { generate } from "shortid"
   import { OperatorOptions, getValidOperatorsForType } from "helpers/lucene"
 
   export let schemaFields
   export let value
+  export let bindings = []
 
   const BannedTypes = ["link", "attachment"]
-  $: bindableProperties = getBindableProperties(
-    $currentAsset,
-    $store.selectedComponentId
-  )
   $: fieldOptions = (schemaFields ?? [])
     .filter(field => !BannedTypes.includes(field.type))
     .map(field => field.name)
@@ -101,7 +96,7 @@
           title={`Value for "${expression.field}"`}
           value={expression.value}
           placeholder="Value"
-          bindings={bindableProperties}
+          {bindings}
           on:change={event => (expression.value = event.detail)}
         />
       {:else if ["string", "longform", "number"].includes(expression.type)}
diff --git a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/PropertyControl.svelte b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/PropertyControl.svelte
index 40d579e9c9..4ca7d9fc12 100644
--- a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/PropertyControl.svelte
+++ b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/PropertyControl.svelte
@@ -1,8 +1,6 @@
 <script>
   import { Button, Icon, Drawer, Label } from "@budibase/bbui"
-  import { store, currentAsset } from "builderStore"
   import {
-    getBindableProperties,
     readableToRuntimeBinding,
     runtimeToReadableBinding,
   } from "builderStore/dataBinding"
@@ -18,18 +16,15 @@
   export let value = null
   export let props = {}
   export let onChange = () => {}
+  export let bindings = []
 
   let bindingDrawer
   let anchor
   let valid
 
-  $: bindableProperties = getBindableProperties(
-    $currentAsset,
-    $store.selectedComponentId
-  )
-  $: safeValue = getSafeValue(value, props.defaultValue, bindableProperties)
+  $: safeValue = getSafeValue(value, props.defaultValue, bindings)
   $: tempValue = safeValue
-  $: replaceBindings = val => readableToRuntimeBinding(bindableProperties, val)
+  $: replaceBindings = val => readableToRuntimeBinding(bindings, val)
 
   const handleClose = () => {
     handleChange(tempValue)
@@ -61,8 +56,8 @@
 
   // The "safe" value is the value with any bindings made readable
   // If there is no value set, any default value is used
-  const getSafeValue = (value, defaultValue, bindableProperties) => {
-    const enriched = runtimeToReadableBinding(bindableProperties, value)
+  const getSafeValue = (value, defaultValue, bindings) => {
+    const enriched = runtimeToReadableBinding(bindings, value)
     return enriched == null && defaultValue !== undefined
       ? defaultValue
       : enriched
@@ -83,6 +78,7 @@
       updateOnChange={false}
       on:change={handleChange}
       onChange={handleChange}
+      {bindings}
       name={key}
       text={label}
       {type}
@@ -108,7 +104,7 @@
           bind:valid
           value={safeValue}
           on:change={e => (tempValue = e.detail)}
-          {bindableProperties}
+          bindableProperties={bindings}
         />
       </Drawer>
     {/if}
diff --git a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/URLSelect.svelte b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/URLSelect.svelte
index 5a19c1add3..fb8b48b9ed 100644
--- a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/URLSelect.svelte
+++ b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/URLSelect.svelte
@@ -3,10 +3,11 @@
   import DrawerBindableCombobox from "components/common/bindings/DrawerBindableCombobox.svelte"
 
   export let value
+  export let bindings
 
   $: urlOptions = $store.screens
     .map(screen => screen.routing?.route)
     .filter(x => x != null)
 </script>
 
-<DrawerBindableCombobox {value} on:change options={urlOptions} />
+<DrawerBindableCombobox {value} {bindings} on:change options={urlOptions} />
diff --git a/packages/builder/src/components/design/PropertiesPanel/ScreenSettingsSection.svelte b/packages/builder/src/components/design/PropertiesPanel/ScreenSettingsSection.svelte
index a153c4fc87..79f262eaae 100644
--- a/packages/builder/src/components/design/PropertiesPanel/ScreenSettingsSection.svelte
+++ b/packages/builder/src/components/design/PropertiesPanel/ScreenSettingsSection.svelte
@@ -9,6 +9,7 @@
   import { FrontendTypes } from "constants"
 
   export let componentInstance
+  export let bindings
 
   function setAssetProps(name, value) {
     const selectedAsset = get(currentAsset)
@@ -44,6 +45,7 @@
         key={def.key}
         value={deepGet($currentAsset, def.key)}
         onChange={val => setAssetProps(def.key, val)}
+        {bindings}
       />
     {/each}
   </DetailSummary>
diff --git a/packages/builder/src/components/design/PropertiesPanel/StyleSection.svelte b/packages/builder/src/components/design/PropertiesPanel/StyleSection.svelte
index 0341c68534..18d63cfbce 100644
--- a/packages/builder/src/components/design/PropertiesPanel/StyleSection.svelte
+++ b/packages/builder/src/components/design/PropertiesPanel/StyleSection.svelte
@@ -7,6 +7,7 @@
   export let columns
   export let properties
   export let componentInstance
+  export let bindings = []
 
   $: style = componentInstance._styles.normal || {}
   $: changed = properties?.some(prop => hasPropChanged(style, prop)) ?? false
@@ -36,6 +37,7 @@
           value={style[prop.key]}
           onChange={val => store.actions.components.updateStyle(prop.key, val)}
           props={getControlProps(prop)}
+          {bindings}
         />
       </div>
     {/each}
diff --git a/packages/builder/src/pages/builder/app/[application]/data/datasource/[selectedDatasource]/CreateEditRelationship/CreateEditRelationship.svelte b/packages/builder/src/pages/builder/app/[application]/data/datasource/[selectedDatasource]/CreateEditRelationship/CreateEditRelationship.svelte
index 9a9b8b20b1..33ca4608ff 100644
--- a/packages/builder/src/pages/builder/app/[application]/data/datasource/[selectedDatasource]/CreateEditRelationship/CreateEditRelationship.svelte
+++ b/packages/builder/src/pages/builder/app/[application]/data/datasource/[selectedDatasource]/CreateEditRelationship/CreateEditRelationship.svelte
@@ -158,10 +158,16 @@
         fieldName: fromTable.primary[0],
       }
     } else {
+      // the relateFrom.fieldName should remain the same, as it is the foreignKey in the other
+      // table, this is due to the way that budibase represents relationships, the fieldName in a
+      // link column schema is the column linked to (FK in this case). The foreignKey column is
+      // essentially what is linked to in the from table, this is unique to SQL as this isn't a feature
+      // of Budibase internal tables.
+      // Essentially this means the fieldName is what we are linking to in the other table, and the
+      // foreignKey is what is linking out of the current table.
       relateFrom = {
         ...relateFrom,
-        foreignKey: relateFrom.fieldName,
-        fieldName: fromTable.primary[0],
+        foreignKey: fromTable.primary[0],
       }
       relateTo = {
         ...relateTo,
diff --git a/packages/cli/package.json b/packages/cli/package.json
index 97cf46b543..cff9d6ed48 100644
--- a/packages/cli/package.json
+++ b/packages/cli/package.json
@@ -1,6 +1,6 @@
 {
   "name": "@budibase/cli",
-  "version": "0.9.87-alpha.7",
+  "version": "0.9.96",
   "description": "Budibase CLI, for developers, self hosting and migrations.",
   "main": "src/index.js",
   "bin": {
diff --git a/packages/client/package.json b/packages/client/package.json
index b9be897525..270e5d64bf 100644
--- a/packages/client/package.json
+++ b/packages/client/package.json
@@ -1,6 +1,6 @@
 {
   "name": "@budibase/client",
-  "version": "0.9.87-alpha.7",
+  "version": "0.9.96",
   "license": "MPL-2.0",
   "module": "dist/budibase-client.js",
   "main": "dist/budibase-client.js",
@@ -18,9 +18,9 @@
     "dev:builder": "rollup -cw"
   },
   "dependencies": {
-    "@budibase/bbui": "^0.9.87-alpha.7",
-    "@budibase/standard-components": "^0.9.87-alpha.7",
-    "@budibase/string-templates": "^0.9.87-alpha.7",
+    "@budibase/bbui": "^0.9.96",
+    "@budibase/standard-components": "^0.9.96",
+    "@budibase/string-templates": "^0.9.96",
     "regexparam": "^1.3.0",
     "shortid": "^2.2.15",
     "svelte-spa-router": "^3.0.5"
diff --git a/packages/client/src/api/api.js b/packages/client/src/api/api.js
index b915f14fd1..5449c3f219 100644
--- a/packages/client/src/api/api.js
+++ b/packages/client/src/api/api.js
@@ -38,15 +38,15 @@ const makeApiCall = async ({ method, url, body, json = true }) => {
       case 200:
         return response.json()
       case 401:
-        notificationStore.danger("Invalid credentials")
+        notificationStore.actions.error("Invalid credentials")
         return handleError(`Invalid credentials`)
       case 404:
-        notificationStore.danger("Not found")
+        notificationStore.actions.warning("Not found")
         return handleError(`${url}: Not Found`)
       case 400:
         return handleError(`${url}: Bad Request`)
       case 403:
-        notificationStore.danger(
+        notificationStore.actions.error(
           "Your session has expired, or you don't have permission to access that data"
         )
         return handleError(`${url}: Forbidden`)
diff --git a/packages/client/src/api/automations.js b/packages/client/src/api/automations.js
index 4dd5958568..2b989f85ae 100644
--- a/packages/client/src/api/automations.js
+++ b/packages/client/src/api/automations.js
@@ -9,7 +9,7 @@ export const triggerAutomation = async (automationId, fields) => {
     body: { fields },
   })
   res.error
-    ? notificationStore.danger("An error has occurred")
-    : notificationStore.success("Automation triggered")
+    ? notificationStore.actions.error("An error has occurred")
+    : notificationStore.actions.success("Automation triggered")
   return res
 }
diff --git a/packages/client/src/api/queries.js b/packages/client/src/api/queries.js
index 715841f0fa..a6ef1a763f 100644
--- a/packages/client/src/api/queries.js
+++ b/packages/client/src/api/queries.js
@@ -7,7 +7,7 @@ import API from "./api"
 export const executeQuery = async ({ queryId, parameters }) => {
   const query = await API.get({ url: `/api/queries/${queryId}` })
   if (query?.datasourceId == null) {
-    notificationStore.danger("That query couldn't be found")
+    notificationStore.actions.error("That query couldn't be found")
     return
   }
   const res = await API.post({
@@ -17,9 +17,9 @@ export const executeQuery = async ({ queryId, parameters }) => {
     },
   })
   if (res.error) {
-    notificationStore.danger("An error has occurred")
+    notificationStore.actions.error("An error has occurred")
   } else if (!query.readable) {
-    notificationStore.success("Query executed successfully")
+    notificationStore.actions.success("Query executed successfully")
     dataSourceStore.actions.invalidateDataSource(query.datasourceId)
   }
   return res
diff --git a/packages/client/src/api/rows.js b/packages/client/src/api/rows.js
index 14d696351d..21f8ec1f98 100644
--- a/packages/client/src/api/rows.js
+++ b/packages/client/src/api/rows.js
@@ -27,8 +27,8 @@ export const saveRow = async row => {
     body: row,
   })
   res.error
-    ? notificationStore.danger("An error has occurred")
-    : notificationStore.success("Row saved")
+    ? notificationStore.actions.error("An error has occurred")
+    : notificationStore.actions.success("Row saved")
 
   // Refresh related datasources
   dataSourceStore.actions.invalidateDataSource(row.tableId)
@@ -48,8 +48,8 @@ export const updateRow = async row => {
     body: row,
   })
   res.error
-    ? notificationStore.danger("An error has occurred")
-    : notificationStore.success("Row updated")
+    ? notificationStore.actions.error("An error has occurred")
+    : notificationStore.actions.success("Row updated")
 
   // Refresh related datasources
   dataSourceStore.actions.invalidateDataSource(row.tableId)
@@ -72,8 +72,8 @@ export const deleteRow = async ({ tableId, rowId, revId }) => {
     },
   })
   res.error
-    ? notificationStore.danger("An error has occurred")
-    : notificationStore.success("Row deleted")
+    ? notificationStore.actions.error("An error has occurred")
+    : notificationStore.actions.success("Row deleted")
 
   // Refresh related datasources
   dataSourceStore.actions.invalidateDataSource(tableId)
@@ -95,8 +95,8 @@ export const deleteRows = async ({ tableId, rows }) => {
     },
   })
   res.error
-    ? notificationStore.danger("An error has occurred")
-    : notificationStore.success(`${rows.length} row(s) deleted`)
+    ? notificationStore.actions.error("An error has occurred")
+    : notificationStore.actions.success(`${rows.length} row(s) deleted`)
 
   // Refresh related datasources
   dataSourceStore.actions.invalidateDataSource(tableId)
diff --git a/packages/client/src/components/ClientApp.svelte b/packages/client/src/components/ClientApp.svelte
index 44ef49e239..1afcc4594d 100644
--- a/packages/client/src/components/ClientApp.svelte
+++ b/packages/client/src/components/ClientApp.svelte
@@ -4,6 +4,7 @@
   import Component from "./Component.svelte"
   import NotificationDisplay from "./NotificationDisplay.svelte"
   import ConfirmationDisplay from "./ConfirmationDisplay.svelte"
+  import PeekScreenDisplay from "./PeekScreenDisplay.svelte"
   import Provider from "./Provider.svelte"
   import SDK from "../sdk"
   import {
@@ -93,13 +94,14 @@
       </div>
     {:else if $screenStore.activeLayout}
       <Provider key="user" data={$authStore} {actions}>
-        <div id="app-root">
+        <div id="app-root" class:preview={$builderStore.inBuilder}>
           {#key $screenStore.activeLayout._id}
             <Component instance={$screenStore.activeLayout.props} />
           {/key}
         </div>
         <NotificationDisplay />
         <ConfirmationDisplay />
+        <PeekScreenDisplay />
         <!-- Key block needs to be outside the if statement or it breaks -->
         {#key $builderStore.selectedComponentId}
           {#if $builderStore.inBuilder}
@@ -131,6 +133,9 @@
   #app-root {
     position: relative;
   }
+  #app-root.preview {
+    border: 1px solid var(--spectrum-global-color-gray-300);
+  }
 
   /* Custom scrollbars */
   :global(::-webkit-scrollbar) {
diff --git a/packages/client/src/components/NotificationDisplay.svelte b/packages/client/src/components/NotificationDisplay.svelte
index 1a960c383a..f03fb692fd 100644
--- a/packages/client/src/components/NotificationDisplay.svelte
+++ b/packages/client/src/components/NotificationDisplay.svelte
@@ -1,36 +1,34 @@
 <script>
-  import { flip } from "svelte/animate"
+  import { notificationStore } from "../store"
+  import { Notification } from "@budibase/bbui"
   import { fly } from "svelte/transition"
-  import { getContext } from "svelte"
-  const { notifications } = getContext("sdk")
-
-  export let themes = {
-    danger: "#E26D69",
-    success: "#84C991",
-    warning: "#f0ad4e",
-    info: "#5bc0de",
-    default: "#aaaaaa",
-  }
 </script>
 
 <div class="notifications">
-  {#each $notifications as notification (notification.id)}
-    <div
-      animate:flip
-      class="toast"
-      style="background: {themes[notification.type]};"
-      transition:fly={{ y: -30 }}
-    >
-      <div class="content">{notification.message}</div>
-      {#if notification.icon}<i class={notification.icon} />{/if}
-    </div>
-  {/each}
+  {#if $notificationStore}
+    {#key $notificationStore.id}
+      <div
+        in:fly={{
+          duration: 300,
+          y: -20,
+          delay: $notificationStore.delay ? 300 : 0,
+        }}
+        out:fly={{ y: -20, duration: 150 }}
+      >
+        <Notification
+          type={$notificationStore.type}
+          message={$notificationStore.message}
+          icon={$notificationStore.icon}
+        />
+      </div>
+    {/key}
+  {/if}
 </div>
 
 <style>
   .notifications {
     position: fixed;
-    top: 10px;
+    top: 20px;
     left: 0;
     right: 0;
     margin: 0 auto;
@@ -42,19 +40,4 @@
     align-items: center;
     pointer-events: none;
   }
-
-  .toast {
-    flex: 0 0 auto;
-    margin-bottom: 10px;
-    border-radius: var(--border-radius-s);
-    /* The toasts now support being auto sized, so this static width could be removed */
-    width: 40vw;
-  }
-
-  .content {
-    padding: 10px;
-    display: block;
-    color: white;
-    font-weight: 600;
-  }
 </style>
diff --git a/packages/client/src/components/PeekScreenDisplay.svelte b/packages/client/src/components/PeekScreenDisplay.svelte
new file mode 100644
index 0000000000..6d6e8c39c7
--- /dev/null
+++ b/packages/client/src/components/PeekScreenDisplay.svelte
@@ -0,0 +1,120 @@
+<script>
+  import {
+    peekStore,
+    dataSourceStore,
+    notificationStore,
+    routeStore,
+  } from "../store"
+  import { Modal, ModalContent, ActionButton } from "@budibase/bbui"
+  import { onDestroy } from "svelte"
+
+  let iframe
+  let listenersAttached = false
+
+  const invalidateDataSource = event => {
+    const { dataSourceId } = event.detail
+    dataSourceStore.actions.invalidateDataSource(dataSourceId)
+  }
+
+  const proxyNotification = event => {
+    const { message, type, icon } = event.detail
+    notificationStore.actions.send(message, type, icon)
+  }
+
+  const attachListeners = () => {
+    // Mirror datasource invalidation to keep the parent window up to date
+    iframe.contentWindow.addEventListener(
+      "invalidate-datasource",
+      invalidateDataSource
+    )
+    // Listen for a close event to close the screen peek
+    iframe.contentWindow.addEventListener(
+      "close-screen-modal",
+      peekStore.actions.hidePeek
+    )
+    // Proxy notifications back to the parent window instead of iframe
+    iframe.contentWindow.addEventListener("notification", proxyNotification)
+  }
+
+  const handleCancel = () => {
+    peekStore.actions.hidePeek()
+    iframe.contentWindow.removeEventListener(
+      "invalidate-datasource",
+      invalidateDataSource
+    )
+    iframe.contentWindow.removeEventListener(
+      "close-screen-modal",
+      peekStore.actions.hidePeek
+    )
+    iframe.contentWindow.removeEventListener("notification", proxyNotification)
+  }
+
+  const handleFullscreen = () => {
+    if ($peekStore.external) {
+      window.location = $peekStore.href
+    } else {
+      routeStore.actions.navigate($peekStore.url)
+      handleCancel()
+    }
+  }
+
+  $: {
+    if (iframe && !listenersAttached) {
+      attachListeners()
+      listenersAttached = true
+    } else if (!iframe) {
+      listenersAttached = false
+    }
+  }
+
+  onDestroy(() => {
+    if (iframe) {
+      handleCancel()
+    }
+  })
+</script>
+
+{#if $peekStore.showPeek}
+  <Modal fixed on:cancel={handleCancel}>
+    <div class="actions spectrum--darkest" slot="outside">
+      <ActionButton size="S" quiet icon="OpenIn" on:click={handleFullscreen}>
+        Full screen
+      </ActionButton>
+      <ActionButton size="S" quiet icon="Close" on:click={handleCancel}>
+        Close
+      </ActionButton>
+    </div>
+    <ModalContent
+      showCancelButton={false}
+      showConfirmButton={false}
+      size="L"
+      showDivider={false}
+      showCloseIcon={false}
+    >
+      <iframe title="Peek" bind:this={iframe} src={$peekStore.href} />
+    </ModalContent>
+  </Modal>
+{/if}
+
+<style>
+  iframe {
+    margin: -40px;
+    border: none;
+    width: calc(100% + 80px);
+    height: 640px;
+    max-height: calc(100vh - 120px);
+    transition: width 1s ease, height 1s ease, top 1s ease, left 1s ease;
+    border-radius: var(--spectrum-global-dimension-size-100);
+  }
+
+  .actions {
+    display: flex;
+    flex-direction: row;
+    justify-content: flex-end;
+    align-items: center;
+    position: absolute;
+    top: 0;
+    width: 640px;
+    max-width: 100%;
+  }
+</style>
diff --git a/packages/client/src/components/Router.svelte b/packages/client/src/components/Router.svelte
index f3af2e94a4..5632d812b5 100644
--- a/packages/client/src/components/Router.svelte
+++ b/packages/client/src/components/Router.svelte
@@ -1,6 +1,6 @@
 <script>
   import { setContext, getContext } from "svelte"
-  import Router from "svelte-spa-router"
+  import Router, { querystring } from "svelte-spa-router"
   import { routeStore } from "../store"
   import Screen from "./Screen.svelte"
 
@@ -16,6 +16,18 @@
     id: $routeStore.routeSessionId,
   }
 
+  // Keep query params up to date
+  $: {
+    let queryParams = {}
+    if ($querystring) {
+      const urlSearchParams = new URLSearchParams($querystring)
+      for (const [key, value] of urlSearchParams) {
+        queryParams[key] = value
+      }
+    }
+    routeStore.actions.setQueryParams(queryParams)
+  }
+
   const getRouterConfig = routes => {
     let config = {}
     routes.forEach(route => {
diff --git a/packages/client/src/sdk.js b/packages/client/src/sdk.js
index 70b5509a83..32b9441849 100644
--- a/packages/client/src/sdk.js
+++ b/packages/client/src/sdk.js
@@ -15,7 +15,7 @@ import { ActionTypes } from "./constants"
 export default {
   API,
   authStore,
-  notifications: notificationStore,
+  notificationStore,
   routeStore,
   screenStore,
   builderStore,
diff --git a/packages/client/src/store/dataSource.js b/packages/client/src/store/dataSource.js
index 2645c949a2..963548158d 100644
--- a/packages/client/src/store/dataSource.js
+++ b/packages/client/src/store/dataSource.js
@@ -1,5 +1,4 @@
 import { writable, get } from "svelte/store"
-import { notificationStore } from "./notification"
 
 export const createDataSourceStore = () => {
   const store = writable([])
@@ -67,12 +66,17 @@ export const createDataSourceStore = () => {
     const relatedInstances = get(store).filter(instance => {
       return instance.dataSourceId === dataSourceId
     })
-    if (relatedInstances?.length) {
-      notificationStore.blockNotifications(1000)
-    }
     relatedInstances?.forEach(instance => {
       instance.refresh()
     })
+
+    // Emit this as a window event, so parent screens which are iframing us in
+    // can also invalidate the same datasource
+    window.dispatchEvent(
+      new CustomEvent("invalidate-datasource", {
+        detail: { dataSourceId },
+      })
+    )
   }
 
   return {
diff --git a/packages/client/src/store/index.js b/packages/client/src/store/index.js
index 9a6c74e028..43de7bb6da 100644
--- a/packages/client/src/store/index.js
+++ b/packages/client/src/store/index.js
@@ -6,6 +6,7 @@ export { screenStore } from "./screens"
 export { builderStore } from "./builder"
 export { dataSourceStore } from "./dataSource"
 export { confirmationStore } from "./confirmation"
+export { peekStore } from "./peek"
 
 // Context stores are layered and duplicated, so it is not a singleton
 export { createContextStore } from "./context"
diff --git a/packages/client/src/store/notification.js b/packages/client/src/store/notification.js
index 6c40ca275f..e3af9aacd1 100644
--- a/packages/client/src/store/notification.js
+++ b/packages/client/src/store/notification.js
@@ -1,56 +1,63 @@
-import { writable } from "svelte/store"
+import { writable, get } from "svelte/store"
+import { generate } from "shortid"
+import { routeStore } from "./routes"
 
 const NOTIFICATION_TIMEOUT = 3000
 
 const createNotificationStore = () => {
-  const timeoutIds = new Set()
-  const _notifications = writable([], () => {
+  let timeout
+  let block = false
+
+  const store = writable(null, () => {
     return () => {
-      // clear all the timers
-      timeoutIds.forEach(timeoutId => {
-        clearTimeout(timeoutId)
-      })
-      _notifications.set([])
+      clearTimeout(timeout)
     }
   })
-  let block = false
 
   const blockNotifications = (timeout = 1000) => {
     block = true
     setTimeout(() => (block = false), timeout)
   }
 
-  const send = (message, type = "default") => {
+  const send = (message, type = "info", icon) => {
     if (block) {
       return
     }
-    let _id = id()
-    _notifications.update(state => {
-      return [...state, { id: _id, type, message }]
-    })
-    const timeoutId = setTimeout(() => {
-      _notifications.update(state => {
-        return state.filter(({ id }) => id !== _id)
-      })
-    }, NOTIFICATION_TIMEOUT)
-    timeoutIds.add(timeoutId)
-  }
 
-  const { subscribe } = _notifications
+    // If peeking, pass notifications back to parent window
+    if (get(routeStore).queryParams?.peek) {
+      window.dispatchEvent(
+        new CustomEvent("notification", {
+          detail: { message, type, icon },
+        })
+      )
+      return
+    }
+
+    store.set({
+      id: generate(),
+      type,
+      message,
+      icon,
+      delay: get(store) != null,
+    })
+    clearTimeout(timeout)
+    timeout = setTimeout(() => {
+      store.set(null)
+    }, NOTIFICATION_TIMEOUT)
+  }
 
   return {
-    subscribe,
-    send,
-    danger: msg => send(msg, "danger"),
-    warning: msg => send(msg, "warning"),
-    info: msg => send(msg, "info"),
-    success: msg => send(msg, "success"),
-    blockNotifications,
+    subscribe: store.subscribe,
+    actions: {
+      send,
+      info: msg => send(msg, "info", "Info"),
+      success: msg => send(msg, "success", "CheckmarkCircle"),
+      warning: msg => send(msg, "warning", "Alert"),
+      error: msg => send(msg, "error", "Alert"),
+      blockNotifications,
+    },
   }
 }
 
-function id() {
-  return "_" + Math.random().toString(36).substr(2, 9)
-}
-
 export const notificationStore = createNotificationStore()
diff --git a/packages/client/src/store/peek.js b/packages/client/src/store/peek.js
new file mode 100644
index 0000000000..df41f5daff
--- /dev/null
+++ b/packages/client/src/store/peek.js
@@ -0,0 +1,36 @@
+import { writable } from "svelte/store"
+
+const initialState = {
+  showPeek: false,
+  url: null,
+  href: null,
+  external: false,
+}
+
+const createPeekStore = () => {
+  const store = writable(initialState)
+
+  const showPeek = url => {
+    let href = url
+    let external = !url.startsWith("/")
+    if (!external) {
+      href = `${window.location.href.split("#")[0]}#${url}?peek=true`
+    }
+    store.set({
+      showPeek: true,
+      url,
+      href,
+      external,
+    })
+  }
+  const hidePeek = () => {
+    store.set(initialState)
+  }
+
+  return {
+    subscribe: store.subscribe,
+    actions: { showPeek, hidePeek },
+  }
+}
+
+export const peekStore = createPeekStore()
diff --git a/packages/client/src/store/routes.js b/packages/client/src/store/routes.js
index d0e848b68e..e6473fb40c 100644
--- a/packages/client/src/store/routes.js
+++ b/packages/client/src/store/routes.js
@@ -9,6 +9,7 @@ const createRouteStore = () => {
     activeRoute: null,
     routeSessionId: Math.random(),
     routerLoaded: false,
+    queryParams: {},
   }
   const store = writable(initialState)
 
@@ -41,6 +42,17 @@ const createRouteStore = () => {
       return state
     })
   }
+  const setQueryParams = queryParams => {
+    store.update(state => {
+      state.queryParams = {
+        ...queryParams,
+        // Never unset the peek param - screen peek modals should always be
+        // in a peek state, even if they navigate to a different page
+        peek: queryParams.peek || state.queryParams?.peek,
+      }
+      return state
+    })
+  }
   const setActiveRoute = route => {
     store.update(state => {
       state.activeRoute = state.routes.find(x => x.path === route)
@@ -58,6 +70,7 @@ const createRouteStore = () => {
       fetchRoutes,
       navigate,
       setRouteParams,
+      setQueryParams,
       setActiveRoute,
       setRouterLoaded,
     },
diff --git a/packages/client/src/utils/buttonActions.js b/packages/client/src/utils/buttonActions.js
index ea29180d36..408b35a705 100644
--- a/packages/client/src/utils/buttonActions.js
+++ b/packages/client/src/utils/buttonActions.js
@@ -4,6 +4,7 @@ import {
   builderStore,
   confirmationStore,
   authStore,
+  peekStore,
 } from "../store"
 import { saveRow, deleteRow, executeQuery, triggerAutomation } from "../api"
 import { ActionTypes } from "../constants"
@@ -39,13 +40,17 @@ const triggerAutomationHandler = async action => {
 }
 
 const navigationHandler = action => {
-  const { url } = action.parameters
+  const { url, peek } = action.parameters
   if (url) {
-    const external = !url.startsWith("/")
-    if (external) {
-      window.location.href = url
+    if (peek) {
+      peekStore.actions.showPeek(url)
     } else {
-      routeStore.actions.navigate(action.parameters.url)
+      const external = !url.startsWith("/")
+      if (external) {
+        window.location.href = url
+      } else {
+        routeStore.actions.navigate(action.parameters.url)
+      }
     }
   }
 }
@@ -94,6 +99,12 @@ const clearFormHandler = async (action, context) => {
   )
 }
 
+const closeScreenModalHandler = () => {
+  // Emit this as a window event, so parent screens which are iframing us in
+  // can close the modal
+  window.dispatchEvent(new Event("close-screen-modal"))
+}
+
 const handlerMap = {
   ["Save Row"]: saveRowHandler,
   ["Delete Row"]: deleteRowHandler,
@@ -104,6 +115,7 @@ const handlerMap = {
   ["Refresh Datasource"]: refreshDatasourceHandler,
   ["Log Out"]: logoutHandler,
   ["Clear Form"]: clearFormHandler,
+  ["Close Screen Modal"]: closeScreenModalHandler,
 }
 
 const confirmTextMap = {
diff --git a/packages/server/package.json b/packages/server/package.json
index 9c4884f999..ae7053c3d7 100644
--- a/packages/server/package.json
+++ b/packages/server/package.json
@@ -1,7 +1,7 @@
 {
   "name": "@budibase/server",
   "email": "hi@budibase.com",
-  "version": "0.9.87-alpha.7",
+  "version": "0.9.96",
   "description": "Budibase Web Server",
   "main": "src/index.js",
   "repository": {
@@ -60,9 +60,9 @@
   "author": "Budibase",
   "license": "AGPL-3.0-or-later",
   "dependencies": {
-    "@budibase/auth": "^0.9.87-alpha.7",
-    "@budibase/client": "^0.9.87-alpha.7",
-    "@budibase/string-templates": "^0.9.87-alpha.7",
+    "@budibase/auth": "^0.9.96",
+    "@budibase/client": "^0.9.96",
+    "@budibase/string-templates": "^0.9.96",
     "@elastic/elasticsearch": "7.10.0",
     "@koa/router": "8.0.0",
     "@sendgrid/mail": "7.1.1",
@@ -115,7 +115,7 @@
   "devDependencies": {
     "@babel/core": "^7.14.3",
     "@babel/preset-env": "^7.14.4",
-    "@budibase/standard-components": "^0.9.87-alpha.7",
+    "@budibase/standard-components": "^0.9.96",
     "@jest/test-sequencer": "^24.8.0",
     "@types/bull": "^3.15.1",
     "@types/jest": "^26.0.23",
diff --git a/packages/server/src/api/controllers/row/ExternalRequest.ts b/packages/server/src/api/controllers/row/ExternalRequest.ts
index c5fad441bf..92a3838f51 100644
--- a/packages/server/src/api/controllers/row/ExternalRequest.ts
+++ b/packages/server/src/api/controllers/row/ExternalRequest.ts
@@ -165,6 +165,10 @@ module External {
         if (!row[key] || newRow[key] || field.autocolumn) {
           continue
         }
+        // parse floats/numbers
+        if (field.type === FieldTypes.NUMBER && !isNaN(parseFloat(row[key]))) {
+          newRow[key] = parseFloat(row[key])
+        }
         // if its not a link then just copy it over
         if (field.type !== FieldTypes.LINK) {
           newRow[key] = row[key]
diff --git a/packages/server/src/integrations/base/sql.ts b/packages/server/src/integrations/base/sql.ts
index 66dd269412..ea48eab793 100644
--- a/packages/server/src/integrations/base/sql.ts
+++ b/packages/server/src/integrations/base/sql.ts
@@ -19,8 +19,6 @@ function parseBody(body: any) {
     }
     if (isIsoDateString(value)) {
       body[key] = new Date(value)
-    } else if (!isNaN(parseFloat(value))) {
-      body[key] = parseFloat(value)
     }
   }
   return body
diff --git a/packages/standard-components/package.json b/packages/standard-components/package.json
index 49ac0480ef..9dceb44c28 100644
--- a/packages/standard-components/package.json
+++ b/packages/standard-components/package.json
@@ -29,13 +29,12 @@
   "keywords": [
     "svelte"
   ],
-  "version": "0.9.87-alpha.7",
+  "version": "0.9.96",
   "license": "MIT",
   "gitHead": "d1836a898cab3f8ab80ee6d8f42be1a9eed7dcdc",
   "dependencies": {
-    "@budibase/bbui": "^0.9.87-alpha.7",
+    "@budibase/bbui": "^0.9.96",
     "@spectrum-css/card": "^3.0.3",
-    "@spectrum-css/divider": "^1.0.3",
     "@spectrum-css/link": "^3.1.3",
     "@spectrum-css/page": "^3.0.1",
     "@spectrum-css/typography": "^3.0.2",
diff --git a/packages/standard-components/src/Layout.svelte b/packages/standard-components/src/Layout.svelte
index 24c9709895..08e0f290fe 100644
--- a/packages/standard-components/src/Layout.svelte
+++ b/packages/standard-components/src/Layout.svelte
@@ -1,6 +1,7 @@
 <script>
   import { getContext } from "svelte"
   import { Heading, Icon } from "@budibase/bbui"
+  import { routeStore } from "../../client/src/store"
 
   const { styleable, linkable, builderStore } = getContext("sdk")
   const component = getContext("component")
@@ -26,6 +27,14 @@
     Small: "s",
   }
 
+  // Permanently go into peek mode if we ever get the peek flag
+  let isPeeking = false
+  $: {
+    if ($routeStore.queryParams?.peek) {
+      isPeeking = true
+    }
+  }
+
   $: validLinks = links?.filter(link => link.text && link.url) || []
   $: typeClass = navigationClasses[navigation] || "none"
   $: widthClass = widthClasses[width] || "l"
@@ -51,7 +60,7 @@
 
 <div class="layout layout--{typeClass}" use:styleable={$component.styles}>
   {#if typeClass !== "none"}
-    <div class="nav-wrapper" class:sticky>
+    <div class="nav-wrapper" class:sticky class:hidden={isPeeking}>
       <div class="nav nav--{typeClass} size--{widthClass}">
         <div class="nav-header">
           {#if validLinks?.length}
@@ -139,6 +148,9 @@
     border-bottom: 1px solid var(--spectrum-global-color-gray-300);
     box-shadow: 0 0 10px 0 rgba(0, 0, 0, 0.05);
   }
+  .nav-wrapper.hidden {
+    display: none;
+  }
   .layout--top .nav-wrapper.sticky {
     position: sticky;
     top: 0;
diff --git a/packages/standard-components/src/Link.svelte b/packages/standard-components/src/Link.svelte
index 7498311e46..be1c8fa8f0 100644
--- a/packages/standard-components/src/Link.svelte
+++ b/packages/standard-components/src/Link.svelte
@@ -14,7 +14,7 @@
   export let underline
   export let size
 
-  $: external = url && !url.startsWith("/")
+  $: external = url && typeof url === "string" && !url.startsWith("/")
   $: target = openInNewTab ? "_blank" : "_self"
   $: placeholder = $builderStore.inBuilder && !text
   $: componentText = $builderStore.inBuilder
diff --git a/packages/standard-components/src/forms/AttachmentField.svelte b/packages/standard-components/src/forms/AttachmentField.svelte
index fbc36faeca..0b454f9800 100644
--- a/packages/standard-components/src/forms/AttachmentField.svelte
+++ b/packages/standard-components/src/forms/AttachmentField.svelte
@@ -10,12 +10,12 @@
   let fieldState
   let fieldApi
 
-  const { API, notifications } = getContext("sdk")
+  const { API, notificationStore } = getContext("sdk")
   const formContext = getContext("form")
   const BYTES_IN_MB = 1000000
 
   const handleFileTooLarge = fileSizeLimit => {
-    notifications.warning(
+    notificationStore.actions.warning(
       `Files cannot exceed ${
         fileSizeLimit / BYTES_IN_MB
       } MB. Please try again with smaller files.`
diff --git a/packages/string-templates/package.json b/packages/string-templates/package.json
index f2c78254a6..c8b5970b18 100644
--- a/packages/string-templates/package.json
+++ b/packages/string-templates/package.json
@@ -1,6 +1,6 @@
 {
   "name": "@budibase/string-templates",
-  "version": "0.9.87-alpha.7",
+  "version": "0.9.96",
   "description": "Handlebars wrapper for Budibase templating.",
   "main": "src/index.cjs",
   "module": "dist/bundle.mjs",
diff --git a/packages/worker/package.json b/packages/worker/package.json
index 93b4399043..5be4f3e66a 100644
--- a/packages/worker/package.json
+++ b/packages/worker/package.json
@@ -1,7 +1,7 @@
 {
   "name": "@budibase/worker",
   "email": "hi@budibase.com",
-  "version": "0.9.87-alpha.7",
+  "version": "0.9.96",
   "description": "Budibase background service",
   "main": "src/index.js",
   "repository": {
@@ -21,8 +21,8 @@
   "author": "Budibase",
   "license": "AGPL-3.0-or-later",
   "dependencies": {
-    "@budibase/auth": "^0.9.87-alpha.7",
-    "@budibase/string-templates": "^0.9.87-alpha.7",
+    "@budibase/auth": "^0.9.96",
+    "@budibase/string-templates": "^0.9.96",
     "@koa/router": "^8.0.0",
     "@techpass/passport-openidconnect": "^0.3.0",
     "aws-sdk": "^2.811.0",