From ee81fd7a5931770f4b1647bed2aac87cfeefd52b Mon Sep 17 00:00:00 2001
From: Adria Navarro <adria@budibase.com>
Date: Mon, 29 May 2023 15:39:39 +0200
Subject: [PATCH 01/12] Split auth google section

---
 .../portal/settings/auth/google.svelte        | 235 ++++++++++++++++++
 .../builder/portal/settings/auth/index.svelte | 154 +-----------
 2 files changed, 237 insertions(+), 152 deletions(-)
 create mode 100644 packages/builder/src/pages/builder/portal/settings/auth/google.svelte

diff --git a/packages/builder/src/pages/builder/portal/settings/auth/google.svelte b/packages/builder/src/pages/builder/portal/settings/auth/google.svelte
new file mode 100644
index 0000000000..82ab13cc8e
--- /dev/null
+++ b/packages/builder/src/pages/builder/portal/settings/auth/google.svelte
@@ -0,0 +1,235 @@
+<script>
+  import GoogleLogo from "./_logos/Google.svelte"
+  import { isEqual, cloneDeep } from "lodash/fp"
+  import {
+    Button,
+    Heading,
+    Divider,
+    Label,
+    notifications,
+    Layout,
+    Input,
+    Body,
+    Toggle,
+    Icon,
+    Helpers,
+    Link,
+  } from "@budibase/bbui"
+  import { onMount } from "svelte"
+  import { API } from "api"
+  import { organisation, admin } from "stores/portal"
+
+  const ConfigTypes = {
+    Google: "google",
+  }
+
+  // Some older google configs contain a manually specified value - retain the functionality to edit the field
+  // When there is no value or we are in the cloud - prohibit editing the field, must use platform url to change
+  $: googleCallbackUrl = undefined
+  $: googleCallbackReadonly = $admin.cloud || !googleCallbackUrl
+
+  // Indicate to user that callback is based on platform url
+  // If there is an existing value, indicate that it may be removed to return to default behaviour
+  $: googleCallbackTooltip = $admin.cloud
+    ? null
+    : googleCallbackReadonly
+    ? "Visit the organisation page to update the platform URL"
+    : "Leave blank to use the default callback URL"
+  $: googleSheetsCallbackUrl = `${$organisation.platformUrl}/api/global/auth/datasource/google/callback`
+
+  $: GoogleConfigFields = {
+    Google: [
+      { name: "clientID", label: "Client ID" },
+      { name: "clientSecret", label: "Client secret" },
+      {
+        name: "callbackURL",
+        label: "Callback URL",
+        readonly: googleCallbackReadonly,
+        tooltip: googleCallbackTooltip,
+        placeholder: $organisation.googleCallbackUrl,
+        copyButton: true,
+      },
+      {
+        name: "sheetsURL",
+        label: "Sheets URL",
+        readonly: googleCallbackReadonly,
+        tooltip: googleCallbackTooltip,
+        placeholder: googleSheetsCallbackUrl,
+        copyButton: true,
+      },
+    ],
+  }
+
+  let google
+
+  const providers = { google }
+
+  // control the state of the save button depending on whether form has changed
+  let originalGoogleDoc
+  let googleSaveButtonDisabled
+  $: {
+    isEqual(providers.google?.config, originalGoogleDoc?.config)
+      ? (googleSaveButtonDisabled = true)
+      : (googleSaveButtonDisabled = false)
+  }
+
+  $: googleComplete = !!(
+    providers.google?.config?.clientID && providers.google?.config?.clientSecret
+  )
+
+  async function saveConfig(config) {
+    // Delete unsupported fields
+    delete config.createdAt
+    delete config.updatedAt
+    return API.saveConfig(config)
+  }
+
+  async function saveGoogle() {
+    if (!googleComplete) {
+      notifications.error(
+        `Please fill in all required ${ConfigTypes.Google} fields`
+      )
+      return
+    }
+
+    const google = providers.google
+
+    try {
+      const res = await saveConfig(google)
+      providers[res.type]._rev = res._rev
+      providers[res.type]._id = res._id
+      notifications.success(`Settings saved`)
+    } catch (e) {
+      notifications.error(e.message)
+      return
+    }
+
+    googleSaveButtonDisabled = true
+    originalGoogleDoc = cloneDeep(providers.google)
+  }
+
+  const copyToClipboard = async value => {
+    await Helpers.copyToClipboard(value)
+    notifications.success("Copied")
+  }
+
+  onMount(async () => {
+    try {
+      await organisation.init()
+    } catch (error) {
+      notifications.error("Error getting org config")
+    }
+
+    // Fetch Google config
+    let googleDoc
+    try {
+      googleDoc = await API.getConfig(ConfigTypes.Google)
+    } catch (error) {
+      notifications.error("Error fetching Google OAuth config")
+    }
+    if (!googleDoc?._id) {
+      providers.google = {
+        type: ConfigTypes.Google,
+        config: { activated: false },
+      }
+      originalGoogleDoc = cloneDeep(googleDoc)
+    } else {
+      // Default activated to true for older configs
+      if (googleDoc.config.activated === undefined) {
+        googleDoc.config.activated = true
+      }
+      originalGoogleDoc = cloneDeep(googleDoc)
+      providers.google = googleDoc
+    }
+    googleCallbackUrl = providers?.google?.config?.callbackURL
+  })
+</script>
+
+{#if providers.google}
+  <Divider />
+  <Layout gap="XS" noPadding>
+    <Heading size="S">
+      <div class="provider-title">
+        <GoogleLogo />
+        <span>Google</span>
+      </div>
+    </Heading>
+    <Body size="S">
+      To allow users to authenticate using their Google accounts, fill out the
+      fields below. Read the <Link
+        size="M"
+        href={"https://docs.budibase.com/docs/sso-with-google"}
+        >documentation</Link
+      > for more information.
+    </Body>
+  </Layout>
+  <Layout gap="XS" noPadding>
+    {#each GoogleConfigFields.Google as field}
+      <div class="form-row">
+        <Label size="L" tooltip={field.tooltip}>{field.label}</Label>
+        <div class="inputContainer">
+          <div class="input">
+            <Input
+              bind:value={providers.google.config[field.name]}
+              readonly={field.readonly}
+              placeholder={field.placeholder}
+            />
+          </div>
+          {#if field.copyButton}
+            <div
+              class="copy"
+              on:click={() => copyToClipboard(field.placeholder)}
+            >
+              <Icon size="S" name="Copy" />
+            </div>
+          {/if}
+        </div>
+      </div>
+    {/each}
+    <div class="form-row">
+      <Label size="L">Activated</Label>
+      <Toggle text="" bind:value={providers.google.config.activated} />
+    </div>
+  </Layout>
+  <div>
+    <Button
+      disabled={googleSaveButtonDisabled}
+      cta
+      on:click={() => saveGoogle()}
+    >
+      Save
+    </Button>
+  </div>
+{/if}
+
+<style>
+  .form-row {
+    display: grid;
+    grid-template-columns: 120px 1fr;
+    grid-gap: var(--spacing-l);
+    align-items: center;
+  }
+
+  .provider-title {
+    display: flex;
+    flex-direction: row;
+    justify-content: space-between;
+    align-items: center;
+    gap: var(--spacing-m);
+  }
+  .provider-title span {
+    flex: 1 1 auto;
+  }
+  .inputContainer {
+    display: flex;
+    flex-direction: row;
+  }
+  .input {
+    flex: 1;
+  }
+  .copy {
+    display: flex;
+    align-items: center;
+    margin-left: 10px;
+  }
+</style>
diff --git a/packages/builder/src/pages/builder/portal/settings/auth/index.svelte b/packages/builder/src/pages/builder/portal/settings/auth/index.svelte
index 38f5e0788b..36cf5c13a8 100644
--- a/packages/builder/src/pages/builder/portal/settings/auth/index.svelte
+++ b/packages/builder/src/pages/builder/portal/settings/auth/index.svelte
@@ -1,5 +1,4 @@
 <script>
-  import GoogleLogo from "./_logos/Google.svelte"
   import OidcLogo from "./_logos/OIDC.svelte"
   import MicrosoftLogo from "assets/microsoft-logo.png"
   import Auth0Logo from "assets/auth0-logo.png"
@@ -28,9 +27,9 @@
   import { API } from "api"
   import { organisation, admin, licensing } from "stores/portal"
   import Scim from "./scim.svelte"
+  import Google from "./google.svelte"
 
   const ConfigTypes = {
-    Google: "google",
     OIDC: "oidc",
   }
 
@@ -38,43 +37,6 @@
 
   $: enforcedSSO = $organisation.isSSOEnforced
 
-  // Some older google configs contain a manually specified value - retain the functionality to edit the field
-  // When there is no value or we are in the cloud - prohibit editing the field, must use platform url to change
-  $: googleCallbackUrl = undefined
-  $: googleCallbackReadonly = $admin.cloud || !googleCallbackUrl
-
-  // Indicate to user that callback is based on platform url
-  // If there is an existing value, indicate that it may be removed to return to default behaviour
-  $: googleCallbackTooltip = $admin.cloud
-    ? null
-    : googleCallbackReadonly
-    ? "Visit the organisation page to update the platform URL"
-    : "Leave blank to use the default callback URL"
-  $: googleSheetsCallbackUrl = `${$organisation.platformUrl}/api/global/auth/datasource/google/callback`
-
-  $: GoogleConfigFields = {
-    Google: [
-      { name: "clientID", label: "Client ID" },
-      { name: "clientSecret", label: "Client secret" },
-      {
-        name: "callbackURL",
-        label: "Callback URL",
-        readonly: googleCallbackReadonly,
-        tooltip: googleCallbackTooltip,
-        placeholder: $organisation.googleCallbackUrl,
-        copyButton: true,
-      },
-      {
-        name: "sheetsURL",
-        label: "Sheets URL",
-        readonly: googleCallbackReadonly,
-        tooltip: googleCallbackTooltip,
-        placeholder: googleSheetsCallbackUrl,
-        copyButton: true,
-      },
-    ],
-  }
-
   $: OIDCConfigFields = {
     Oidc: [
       { name: "configUrl", label: "Config URL" },
@@ -133,15 +95,9 @@
   const providers = { google, oidc }
 
   // control the state of the save button depending on whether form has changed
-  let originalGoogleDoc
   let originalOidcDoc
-  let googleSaveButtonDisabled
   let oidcSaveButtonDisabled
   $: {
-    isEqual(providers.google?.config, originalGoogleDoc?.config)
-      ? (googleSaveButtonDisabled = true)
-      : (googleSaveButtonDisabled = false)
-
     // delete the callback url which is never saved to the oidc
     // config doc, to ensure an accurate comparison
     delete providers.oidc?.config.configs[0].callbackURL
@@ -151,10 +107,6 @@
       : (oidcSaveButtonDisabled = false)
   }
 
-  $: googleComplete = !!(
-    providers.google?.config?.clientID && providers.google?.config?.clientSecret
-  )
-
   $: oidcComplete = !!(
     providers.oidc?.config?.configs[0].configUrl &&
     providers.oidc?.config?.configs[0].clientID &&
@@ -230,30 +182,6 @@
     originalOidcDoc = cloneDeep(providers.oidc)
   }
 
-  async function saveGoogle() {
-    if (!googleComplete) {
-      notifications.error(
-        `Please fill in all required ${ConfigTypes.Google} fields`
-      )
-      return
-    }
-
-    const google = providers.google
-
-    try {
-      const res = await saveConfig(google)
-      providers[res.type]._rev = res._rev
-      providers[res.type]._id = res._id
-      notifications.success(`Settings saved`)
-    } catch (e) {
-      notifications.error(e.message)
-      return
-    }
-
-    googleSaveButtonDisabled = true
-    originalGoogleDoc = cloneDeep(providers.google)
-  }
-
   let defaultScopes = ["profile", "email", "offline_access"]
 
   const refreshScopes = idx => {
@@ -281,29 +209,6 @@
       notifications.error("Error getting org config")
     }
 
-    // Fetch Google config
-    let googleDoc
-    try {
-      googleDoc = await API.getConfig(ConfigTypes.Google)
-    } catch (error) {
-      notifications.error("Error fetching Google OAuth config")
-    }
-    if (!googleDoc?._id) {
-      providers.google = {
-        type: ConfigTypes.Google,
-        config: { activated: false },
-      }
-      originalGoogleDoc = cloneDeep(googleDoc)
-    } else {
-      // Default activated to true for older configs
-      if (googleDoc.config.activated === undefined) {
-        googleDoc.config.activated = true
-      }
-      originalGoogleDoc = cloneDeep(googleDoc)
-      providers.google = googleDoc
-    }
-    googleCallbackUrl = providers?.google?.config?.callbackURL
-
     // Get the list of user uploaded logos and push it to the dropdown options.
     // This needs to be done before the config call so they're available when
     // the dropdown renders.
@@ -395,62 +300,7 @@
       > before enabling this feature.
     </Body>
   </Layout>
-  {#if providers.google}
-    <Divider />
-    <Layout gap="XS" noPadding>
-      <Heading size="S">
-        <div class="provider-title">
-          <GoogleLogo />
-          <span>Google</span>
-        </div>
-      </Heading>
-      <Body size="S">
-        To allow users to authenticate using their Google accounts, fill out the
-        fields below. Read the <Link
-          size="M"
-          href={"https://docs.budibase.com/docs/sso-with-google"}
-          >documentation</Link
-        > for more information.
-      </Body>
-    </Layout>
-    <Layout gap="XS" noPadding>
-      {#each GoogleConfigFields.Google as field}
-        <div class="form-row">
-          <Label size="L" tooltip={field.tooltip}>{field.label}</Label>
-          <div class="inputContainer">
-            <div class="input">
-              <Input
-                bind:value={providers.google.config[field.name]}
-                readonly={field.readonly}
-                placeholder={field.placeholder}
-              />
-            </div>
-            {#if field.copyButton}
-              <div
-                class="copy"
-                on:click={() => copyToClipboard(field.placeholder)}
-              >
-                <Icon size="S" name="Copy" />
-              </div>
-            {/if}
-          </div>
-        </div>
-      {/each}
-      <div class="form-row">
-        <Label size="L">Activated</Label>
-        <Toggle text="" bind:value={providers.google.config.activated} />
-      </div>
-    </Layout>
-    <div>
-      <Button
-        disabled={googleSaveButtonDisabled}
-        cta
-        on:click={() => saveGoogle()}
-      >
-        Save
-      </Button>
-    </div>
-  {/if}
+  <Google />
   {#if providers.oidc}
     <Divider />
     <Layout gap="XS" noPadding>

From 7da9a041243e26b9e415e87a5f3b317e30735cd2 Mon Sep 17 00:00:00 2001
From: Budibase Staging Release Bot <>
Date: Tue, 6 Jun 2023 09:14:18 +0000
Subject: [PATCH 02/12] Bump version to 2.6.24-alpha.1

---
 lerna.json | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lerna.json b/lerna.json
index 9f8cd12e31..e44a4b60c7 100644
--- a/lerna.json
+++ b/lerna.json
@@ -1,5 +1,5 @@
 {
-  "version": "2.6.24-alpha.0",
+  "version": "2.6.24-alpha.1",
   "npmClient": "yarn",
   "packages": [
     "packages/backend-core",

From 498eedaf1979306fb7d32aa17888ca0e339ac803 Mon Sep 17 00:00:00 2001
From: Adria Navarro <adria@budibase.com>
Date: Mon, 29 May 2023 11:45:40 +0200
Subject: [PATCH 03/12] Remove confirm button while setting up google
 datasource

---
 .../modals/GoogleDatasourceConfigModal.svelte                    | 1 +
 1 file changed, 1 insertion(+)

diff --git a/packages/builder/src/components/backend/DatasourceNavigator/modals/GoogleDatasourceConfigModal.svelte b/packages/builder/src/components/backend/DatasourceNavigator/modals/GoogleDatasourceConfigModal.svelte
index 0783a9fe53..bc6afe82c5 100644
--- a/packages/builder/src/components/backend/DatasourceNavigator/modals/GoogleDatasourceConfigModal.svelte
+++ b/packages/builder/src/components/backend/DatasourceNavigator/modals/GoogleDatasourceConfigModal.svelte
@@ -22,6 +22,7 @@
   title={`Connect to ${IntegrationNames[datasource.type]}`}
   cancelText="Back"
   size="L"
+  showConfirmButton={false}
 >
   <!-- check true and false directly, don't render until flag is set -->
   {#if isGoogleConfigured === true}

From c89708cda352c08736424320edb2a6cdee44b516 Mon Sep 17 00:00:00 2001
From: Adria Navarro <adria@budibase.com>
Date: Mon, 29 May 2023 11:45:58 +0200
Subject: [PATCH 04/12] Google wizard on the same page

---
 .../modals/GoogleDatasourceConfigModal.svelte                   | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/packages/builder/src/components/backend/DatasourceNavigator/modals/GoogleDatasourceConfigModal.svelte b/packages/builder/src/components/backend/DatasourceNavigator/modals/GoogleDatasourceConfigModal.svelte
index bc6afe82c5..4d82ad187f 100644
--- a/packages/builder/src/components/backend/DatasourceNavigator/modals/GoogleDatasourceConfigModal.svelte
+++ b/packages/builder/src/components/backend/DatasourceNavigator/modals/GoogleDatasourceConfigModal.svelte
@@ -33,7 +33,7 @@
         ]} integration.</Body
       >
     </Layout>
-    <GoogleButton preAuthStep={() => save(datasource, true)} />
+    <GoogleButton preAuthStep={() => save(datasource, true)} samePage />
   {:else if isGoogleConfigured === false}
     <Body size="S"
       >Google authentication is not enabled, please complete Google SSO

From 3a6a3eb8a5b716247ce35da53e492d5fa58ea57f Mon Sep 17 00:00:00 2001
From: Adria Navarro <adria@budibase.com>
Date: Wed, 31 May 2023 10:32:11 +0200
Subject: [PATCH 05/12] Store tokens in cache and amend redirect

---
 .../middleware/passport/datasource/google.ts  | 35 ++++++++-----------
 .../_components/GoogleButton.svelte           | 14 +-------
 .../modals/GoogleDatasourceConfigModal.svelte |  3 +-
 .../worker/src/api/controllers/global/auth.ts |  1 -
 4 files changed, 16 insertions(+), 37 deletions(-)

diff --git a/packages/backend-core/src/middleware/passport/datasource/google.ts b/packages/backend-core/src/middleware/passport/datasource/google.ts
index 6fd4e9ff32..3e8306c296 100644
--- a/packages/backend-core/src/middleware/passport/datasource/google.ts
+++ b/packages/backend-core/src/middleware/passport/datasource/google.ts
@@ -1,10 +1,10 @@
 import * as google from "../sso/google"
 import { Cookie } from "../../../constants"
 import { clearCookie, getCookie } from "../../../utils"
-import { doWithDB } from "../../../db"
 import * as configs from "../../../configs"
-import { BBContext, Database, SSOProfile } from "@budibase/types"
+import { BBContext, SSOProfile } from "@budibase/types"
 import { ssoSaveUserNoOp } from "../sso/sso"
+import { cache, utils } from "../../../"
 const GoogleStrategy = require("passport-google-oauth").OAuth2Strategy
 
 type Passport = {
@@ -36,8 +36,8 @@ export async function preAuth(
     ssoSaveUserNoOp
   )
 
-  if (!ctx.query.appId || !ctx.query.datasourceId) {
-    ctx.throw(400, "appId and datasourceId query params not present.")
+  if (!ctx.query.appId) {
+    ctx.throw(400, "appId query param not present.")
   }
 
   return passport.authenticate(strategy, {
@@ -69,7 +69,7 @@ export async function postAuth(
       (
         accessToken: string,
         refreshToken: string,
-        profile: SSOProfile,
+        _profile: SSOProfile,
         done: Function
       ) => {
         clearCookie(ctx, Cookie.DatasourceAuth)
@@ -79,23 +79,16 @@ export async function postAuth(
     { successRedirect: "/", failureRedirect: "/error" },
     async (err: any, tokens: string[]) => {
       const baseUrl = `/builder/app/${authStateCookie.appId}/data`
-      // update the DB for the datasource with all the user info
-      await doWithDB(authStateCookie.appId, async (db: Database) => {
-        let datasource
-        try {
-          datasource = await db.get(authStateCookie.datasourceId)
-        } catch (err: any) {
-          if (err.status === 404) {
-            ctx.redirect(baseUrl)
-          }
+
+      const id = utils.newid()
+      await cache.store(
+        `datasource:creation:${authStateCookie.appId}:google:${id}`,
+        {
+          tokens,
         }
-        if (!datasource.config) {
-          datasource.config = {}
-        }
-        datasource.config.auth = { type: "google", ...tokens }
-        await db.put(datasource)
-        ctx.redirect(`${baseUrl}/datasource/${authStateCookie.datasourceId}`)
-      })
+      )
+
+      ctx.redirect(`${baseUrl}/new?type=google&action=continue&id=${id}`)
     }
   )(ctx, next)
 }
diff --git a/packages/builder/src/components/backend/DatasourceNavigator/_components/GoogleButton.svelte b/packages/builder/src/components/backend/DatasourceNavigator/_components/GoogleButton.svelte
index b7d70d88b7..ceb8fd7f4b 100644
--- a/packages/builder/src/components/backend/DatasourceNavigator/_components/GoogleButton.svelte
+++ b/packages/builder/src/components/backend/DatasourceNavigator/_components/GoogleButton.svelte
@@ -3,8 +3,6 @@
   import { store } from "builderStore"
   import { auth } from "stores/portal"
 
-  export let preAuthStep
-  export let datasource
   export let disabled
   export let samePage
 
@@ -15,18 +13,8 @@
   class:disabled
   {disabled}
   on:click={async () => {
-    let ds = datasource
     let appId = $store.appId
-    if (!ds) {
-      const resp = await preAuthStep()
-      if (resp.datasource && resp.appId) {
-        ds = resp.datasource
-        appId = resp.appId
-      } else {
-        ds = resp
-      }
-    }
-    const url = `/api/global/auth/${tenantId}/datasource/google?datasourceId=${ds._id}&appId=${appId}`
+    const url = `/api/global/auth/${tenantId}/datasource/google?appId=${appId}`
     if (samePage) {
       window.location = url
     } else {
diff --git a/packages/builder/src/components/backend/DatasourceNavigator/modals/GoogleDatasourceConfigModal.svelte b/packages/builder/src/components/backend/DatasourceNavigator/modals/GoogleDatasourceConfigModal.svelte
index 4d82ad187f..6388cfb7b5 100644
--- a/packages/builder/src/components/backend/DatasourceNavigator/modals/GoogleDatasourceConfigModal.svelte
+++ b/packages/builder/src/components/backend/DatasourceNavigator/modals/GoogleDatasourceConfigModal.svelte
@@ -3,7 +3,6 @@
   import { IntegrationNames } from "constants/backend"
   import cloneDeep from "lodash/cloneDeepWith"
   import GoogleButton from "../_components/GoogleButton.svelte"
-  import { saveDatasource as save } from "builderStore/datasource"
   import { organisation } from "stores/portal"
   import { onMount } from "svelte"
 
@@ -33,7 +32,7 @@
         ]} integration.</Body
       >
     </Layout>
-    <GoogleButton preAuthStep={() => save(datasource, true)} samePage />
+    <GoogleButton samePage />
   {:else if isGoogleConfigured === false}
     <Body size="S"
       >Google authentication is not enabled, please complete Google SSO
diff --git a/packages/worker/src/api/controllers/global/auth.ts b/packages/worker/src/api/controllers/global/auth.ts
index c8f75b3610..131601c6ad 100644
--- a/packages/worker/src/api/controllers/global/auth.ts
+++ b/packages/worker/src/api/controllers/global/auth.ts
@@ -140,7 +140,6 @@ export const datasourcePreAuth = async (ctx: any, next: any) => {
     {
       provider,
       appId: ctx.query.appId,
-      datasourceId: ctx.query.datasourceId,
     },
     Cookie.DatasourceAuth
   )

From d4ba73f331273accf8363b0404dca8de346de832 Mon Sep 17 00:00:00 2001
From: Adria Navarro <adria@budibase.com>
Date: Wed, 31 May 2023 11:24:06 +0200
Subject: [PATCH 06/12] Open continue

---
 .../middleware/passport/datasource/google.ts  |  2 +-
 .../modals/GoogleDatasourceConfigModal.svelte | 50 ++++++++++++-------
 .../builder/app/[application]/data/new.svelte | 22 ++++++--
 3 files changed, 51 insertions(+), 23 deletions(-)

diff --git a/packages/backend-core/src/middleware/passport/datasource/google.ts b/packages/backend-core/src/middleware/passport/datasource/google.ts
index 3e8306c296..7f5e7f0d90 100644
--- a/packages/backend-core/src/middleware/passport/datasource/google.ts
+++ b/packages/backend-core/src/middleware/passport/datasource/google.ts
@@ -88,7 +88,7 @@ export async function postAuth(
         }
       )
 
-      ctx.redirect(`${baseUrl}/new?type=google&action=continue&id=${id}`)
+      ctx.redirect(`${baseUrl}/new?action=google_continue&id=${id}`)
     }
   )(ctx, next)
 }
diff --git a/packages/builder/src/components/backend/DatasourceNavigator/modals/GoogleDatasourceConfigModal.svelte b/packages/builder/src/components/backend/DatasourceNavigator/modals/GoogleDatasourceConfigModal.svelte
index 6388cfb7b5..79fb0f6b5b 100644
--- a/packages/builder/src/components/backend/DatasourceNavigator/modals/GoogleDatasourceConfigModal.svelte
+++ b/packages/builder/src/components/backend/DatasourceNavigator/modals/GoogleDatasourceConfigModal.svelte
@@ -1,43 +1,55 @@
 <script>
   import { ModalContent, Body, Layout, Link } from "@budibase/bbui"
-  import { IntegrationNames } from "constants/backend"
-  import cloneDeep from "lodash/cloneDeepWith"
+  import { IntegrationNames, IntegrationTypes } from "constants/backend"
   import GoogleButton from "../_components/GoogleButton.svelte"
   import { organisation } from "stores/portal"
   import { onMount } from "svelte"
 
-  export let integration
+  export let continueSetup = false
 
-  // kill the reference so the input isn't saved
-  let datasource = cloneDeep(integration)
   $: isGoogleConfigured = !!$organisation.googleDatasourceConfigured
 
   onMount(async () => {
     await organisation.init()
   })
+  const integrationName = IntegrationNames[IntegrationTypes.GOOGLE_SHEETS]
+
+  export const GoogleDatasouceConfigStep = {
+    AUTH: "Auth",
+    SET_URL: "Set_url",
+  }
+
+  let step = continueSetup
+    ? GoogleDatasouceConfigStep.SET_URL
+    : GoogleDatasouceConfigStep.AUTH
 </script>
 
 <ModalContent
-  title={`Connect to ${IntegrationNames[datasource.type]}`}
+  title={`Connect to ${integrationName}`}
   cancelText="Back"
   size="L"
   showConfirmButton={false}
 >
-  <!-- check true and false directly, don't render until flag is set -->
-  {#if isGoogleConfigured === true}
-    <Layout noPadding>
+  {#if step === GoogleDatasouceConfigStep.AUTH}
+    <!-- check true and false directly, don't render until flag is set -->
+    {#if isGoogleConfigured === true}
+      <Layout noPadding>
+        <Body size="S"
+          >Authenticate with your google account to use the {integrationName} integration.</Body
+        >
+      </Layout>
+      <GoogleButton samePage />
+    {:else if isGoogleConfigured === false}
       <Body size="S"
-        >Authenticate with your google account to use the {IntegrationNames[
-          datasource.type
-        ]} integration.</Body
+        >Google authentication is not enabled, please complete Google SSO
+        configuration.</Body
       >
+      <Link href="/builder/portal/settings/auth">Configure Google SSO</Link>
+    {/if}
+  {/if}
+  {#if step === GoogleDatasouceConfigStep.SET_URL}
+    <Layout noPadding>
+      <Body size="S">Add the URL of the sheet you want to connect</Body>
     </Layout>
-    <GoogleButton samePage />
-  {:else if isGoogleConfigured === false}
-    <Body size="S"
-      >Google authentication is not enabled, please complete Google SSO
-      configuration.</Body
-    >
-    <Link href="/builder/portal/settings/auth">Configure Google SSO</Link>
   {/if}
 </ModalContent>
diff --git a/packages/builder/src/pages/builder/app/[application]/data/new.svelte b/packages/builder/src/pages/builder/app/[application]/data/new.svelte
index fedaf013da..ed2e7f360d 100644
--- a/packages/builder/src/pages/builder/app/[application]/data/new.svelte
+++ b/packages/builder/src/pages/builder/app/[application]/data/new.svelte
@@ -17,6 +17,7 @@
   import IntegrationIcon from "components/backend/DatasourceNavigator/IntegrationIcon.svelte"
   import ICONS from "components/backend/DatasourceNavigator/icons/index.js"
   import FontAwesomeIcon from "components/common/FontAwesomeIcon.svelte"
+  import { onMount } from "svelte"
 
   let internalTableModal
   let externalDatasourceModal
@@ -24,6 +25,7 @@
   let integration = null
   let disabled = false
   let promptUpload = false
+  let continueGoogleSetup
 
   $: hasData = $datasources.list.length > 1 || $tables.list.length > 1
   $: hasDefaultData =
@@ -135,15 +137,29 @@
   }
 
   $: fetchIntegrations()
+
+  onMount(() => {
+    const urlParams = new URLSearchParams(window.location.search)
+    const action = urlParams.get("action")
+    if (action === "google_continue") {
+      continueGoogleSetup = true
+      externalDatasourceModal.show()
+    }
+  })
 </script>
 
 <Modal bind:this={internalTableModal}>
   <CreateTableModal {promptUpload} afterSave={handleInternalTableSave} />
 </Modal>
 
-<Modal bind:this={externalDatasourceModal}>
-  {#if integration?.auth?.type === "google"}
-    <GoogleDatasourceConfigModal {integration} />
+<Modal
+  bind:this={externalDatasourceModal}
+  on:hide={() => {
+    continueGoogleSetup = false
+  }}
+>
+  {#if integration?.auth?.type === "google" || continueGoogleSetup}
+    <GoogleDatasourceConfigModal continueSetup={continueGoogleSetup} />
   {:else}
     <DatasourceConfigModal {integration} />
   {/if}

From 1e238ce69376987e13db2ac1fabfe281a0d7df52 Mon Sep 17 00:00:00 2001
From: Adria Navarro <adria@budibase.com>
Date: Wed, 31 May 2023 12:26:01 +0200
Subject: [PATCH 07/12] Validate google sheets url

---
 .../modals/GoogleDatasourceConfigModal.svelte | 40 +++++++++++++++++--
 .../builder/app/[application]/data/new.svelte | 33 +++++++++------
 .../server/src/integrations/googlesheets.ts   |  2 +-
 3 files changed, 57 insertions(+), 18 deletions(-)

diff --git a/packages/builder/src/components/backend/DatasourceNavigator/modals/GoogleDatasourceConfigModal.svelte b/packages/builder/src/components/backend/DatasourceNavigator/modals/GoogleDatasourceConfigModal.svelte
index 79fb0f6b5b..a0b0902480 100644
--- a/packages/builder/src/components/backend/DatasourceNavigator/modals/GoogleDatasourceConfigModal.svelte
+++ b/packages/builder/src/components/backend/DatasourceNavigator/modals/GoogleDatasourceConfigModal.svelte
@@ -4,9 +4,15 @@
   import GoogleButton from "../_components/GoogleButton.svelte"
   import { organisation } from "stores/portal"
   import { onMount } from "svelte"
+  import { validateDatasourceConfig } from "builderStore/datasource"
+  import cloneDeep from "lodash/cloneDeepWith"
+  import IntegrationConfigForm from "../TableIntegrationMenu/IntegrationConfigForm.svelte"
 
+  export let integration
   export let continueSetup = false
 
+  let datasource = cloneDeep(integration)
+
   $: isGoogleConfigured = !!$organisation.googleDatasourceConfigured
 
   onMount(async () => {
@@ -22,13 +28,32 @@
   let step = continueSetup
     ? GoogleDatasouceConfigStep.SET_URL
     : GoogleDatasouceConfigStep.AUTH
+
+  let isValid
+
+  const modalConfig = {
+    [GoogleDatasouceConfigStep.AUTH]: {},
+    [GoogleDatasouceConfigStep.SET_URL]: {
+      confirmButtonText: "Connect",
+      onConfirm: async () => {
+        const resp = await validateDatasourceConfig(datasource)
+        if (!resp.connected) {
+          displayError(`Unable to connect - ${resp.error}`)
+        }
+
+        return false
+      },
+    },
+  }
 </script>
 
 <ModalContent
   title={`Connect to ${integrationName}`}
-  cancelText="Back"
+  cancelText="Cancel"
   size="L"
-  showConfirmButton={false}
+  confirmText={modalConfig[step].confirmButtonText}
+  showConfirmButton={!!modalConfig[step].onConfirm}
+  onConfirm={modalConfig[step].onConfirm}
 >
   {#if step === GoogleDatasouceConfigStep.AUTH}
     <!-- check true and false directly, don't render until flag is set -->
@@ -48,8 +73,15 @@
     {/if}
   {/if}
   {#if step === GoogleDatasouceConfigStep.SET_URL}
-    <Layout noPadding>
-      <Body size="S">Add the URL of the sheet you want to connect</Body>
+    <Layout noPadding no>
+      <Body size="S">Add the URL of the sheet you want to connect.</Body>
+
+      <IntegrationConfigForm
+        schema={datasource.schema}
+        bind:datasource
+        creating={true}
+        on:valid={e => (isValid = e.detail)}
+      />
     </Layout>
   {/if}
 </ModalContent>
diff --git a/packages/builder/src/pages/builder/app/[application]/data/new.svelte b/packages/builder/src/pages/builder/app/[application]/data/new.svelte
index ed2e7f360d..536859d4f9 100644
--- a/packages/builder/src/pages/builder/app/[application]/data/new.svelte
+++ b/packages/builder/src/pages/builder/app/[application]/data/new.svelte
@@ -131,21 +131,25 @@
     return integrationsArray
   }
 
-  const fetchIntegrations = async () => {
-    const unsortedIntegrations = await API.getIntegrations()
-    integrations = sortIntegrations(unsortedIntegrations)
-  }
-
-  $: fetchIntegrations()
-
+  let isGoogleContinueAction
   onMount(() => {
     const urlParams = new URLSearchParams(window.location.search)
     const action = urlParams.get("action")
-    if (action === "google_continue") {
-      continueGoogleSetup = true
-      externalDatasourceModal.show()
-    }
+
+    isGoogleContinueAction = action === "google_continue"
   })
+
+  const fetchIntegrations = async () => {
+    const unsortedIntegrations = await API.getIntegrations()
+    integrations = sortIntegrations(unsortedIntegrations)
+    console.log(integrations[IntegrationTypes.GOOGLE_SHEETS])
+
+    if (isGoogleContinueAction) {
+      handleIntegrationSelect(IntegrationTypes.GOOGLE_SHEETS)
+    }
+  }
+
+  $: fetchIntegrations()
 </script>
 
 <Modal bind:this={internalTableModal}>
@@ -158,8 +162,11 @@
     continueGoogleSetup = false
   }}
 >
-  {#if integration?.auth?.type === "google" || continueGoogleSetup}
-    <GoogleDatasourceConfigModal continueSetup={continueGoogleSetup} />
+  {#if integration?.auth?.type === "google"}
+    <GoogleDatasourceConfigModal
+      continueSetup={isGoogleContinueAction}
+      {integration}
+    />
   {:else}
     <DatasourceConfigModal {integration} />
   {/if}
diff --git a/packages/server/src/integrations/googlesheets.ts b/packages/server/src/integrations/googlesheets.ts
index 8863aa0b3a..2598f6db62 100644
--- a/packages/server/src/integrations/googlesheets.ts
+++ b/packages/server/src/integrations/googlesheets.ts
@@ -72,7 +72,7 @@ const SCHEMA: Integration = {
   },
   datasource: {
     spreadsheetId: {
-      display: "Google Sheet URL",
+      display: "Spreadsheet URL",
       type: DatasourceFieldType.STRING,
       required: true,
     },

From 25c921e3406eb653f3acf21fc5a6878bc945a05c Mon Sep 17 00:00:00 2001
From: Adria Navarro <adria@budibase.com>
Date: Wed, 31 May 2023 13:00:33 +0200
Subject: [PATCH 08/12] Validate url

---
 .../src/middleware/passport/datasource/google.ts  |  2 +-
 .../modals/GoogleDatasourceConfigModal.svelte     | 15 +++++++++++----
 .../builder/app/[application]/data/new.svelte     | 13 +++++--------
 packages/server/src/api/controllers/datasource.ts |  3 ++-
 4 files changed, 19 insertions(+), 14 deletions(-)

diff --git a/packages/backend-core/src/middleware/passport/datasource/google.ts b/packages/backend-core/src/middleware/passport/datasource/google.ts
index 7f5e7f0d90..2f91e01d9a 100644
--- a/packages/backend-core/src/middleware/passport/datasource/google.ts
+++ b/packages/backend-core/src/middleware/passport/datasource/google.ts
@@ -88,7 +88,7 @@ export async function postAuth(
         }
       )
 
-      ctx.redirect(`${baseUrl}/new?action=google_continue&id=${id}`)
+      ctx.redirect(`${baseUrl}/new?continue_google_setup=${id}`)
     }
   )(ctx, next)
 }
diff --git a/packages/builder/src/components/backend/DatasourceNavigator/modals/GoogleDatasourceConfigModal.svelte b/packages/builder/src/components/backend/DatasourceNavigator/modals/GoogleDatasourceConfigModal.svelte
index a0b0902480..f93f7b29da 100644
--- a/packages/builder/src/components/backend/DatasourceNavigator/modals/GoogleDatasourceConfigModal.svelte
+++ b/packages/builder/src/components/backend/DatasourceNavigator/modals/GoogleDatasourceConfigModal.svelte
@@ -1,5 +1,11 @@
 <script>
-  import { ModalContent, Body, Layout, Link } from "@budibase/bbui"
+  import {
+    ModalContent,
+    Body,
+    Layout,
+    Link,
+    notifications,
+  } from "@budibase/bbui"
   import { IntegrationNames, IntegrationTypes } from "constants/backend"
   import GoogleButton from "../_components/GoogleButton.svelte"
   import { organisation } from "stores/portal"
@@ -9,9 +15,10 @@
   import IntegrationConfigForm from "../TableIntegrationMenu/IntegrationConfigForm.svelte"
 
   export let integration
-  export let continueSetup = false
+  export let continueSetupId = false
 
   let datasource = cloneDeep(integration)
+  datasource.config.continueSetupId = continueSetupId
 
   $: isGoogleConfigured = !!$organisation.googleDatasourceConfigured
 
@@ -25,7 +32,7 @@
     SET_URL: "Set_url",
   }
 
-  let step = continueSetup
+  let step = continueSetupId
     ? GoogleDatasouceConfigStep.SET_URL
     : GoogleDatasouceConfigStep.AUTH
 
@@ -38,7 +45,7 @@
       onConfirm: async () => {
         const resp = await validateDatasourceConfig(datasource)
         if (!resp.connected) {
-          displayError(`Unable to connect - ${resp.error}`)
+          notifications.error(`Unable to connect - ${resp.error}`)
         }
 
         return false
diff --git a/packages/builder/src/pages/builder/app/[application]/data/new.svelte b/packages/builder/src/pages/builder/app/[application]/data/new.svelte
index 536859d4f9..23d719247d 100644
--- a/packages/builder/src/pages/builder/app/[application]/data/new.svelte
+++ b/packages/builder/src/pages/builder/app/[application]/data/new.svelte
@@ -25,7 +25,6 @@
   let integration = null
   let disabled = false
   let promptUpload = false
-  let continueGoogleSetup
 
   $: hasData = $datasources.list.length > 1 || $tables.list.length > 1
   $: hasDefaultData =
@@ -131,12 +130,10 @@
     return integrationsArray
   }
 
-  let isGoogleContinueAction
+  let continueGoogleSetup
   onMount(() => {
     const urlParams = new URLSearchParams(window.location.search)
-    const action = urlParams.get("action")
-
-    isGoogleContinueAction = action === "google_continue"
+    continueGoogleSetup = urlParams.get("continue_google_setup")
   })
 
   const fetchIntegrations = async () => {
@@ -144,7 +141,7 @@
     integrations = sortIntegrations(unsortedIntegrations)
     console.log(integrations[IntegrationTypes.GOOGLE_SHEETS])
 
-    if (isGoogleContinueAction) {
+    if (continueGoogleSetup) {
       handleIntegrationSelect(IntegrationTypes.GOOGLE_SHEETS)
     }
   }
@@ -159,12 +156,12 @@
 <Modal
   bind:this={externalDatasourceModal}
   on:hide={() => {
-    continueGoogleSetup = false
+    continueGoogleSetup = null
   }}
 >
   {#if integration?.auth?.type === "google"}
     <GoogleDatasourceConfigModal
-      continueSetup={isGoogleContinueAction}
+      continueSetupId={continueGoogleSetup}
       {integration}
     />
   {:else}
diff --git a/packages/server/src/api/controllers/datasource.ts b/packages/server/src/api/controllers/datasource.ts
index 8fe0ab70da..f3d0c5f83b 100644
--- a/packages/server/src/api/controllers/datasource.ts
+++ b/packages/server/src/api/controllers/datasource.ts
@@ -11,7 +11,7 @@ import { BuildSchemaErrors, InvalidColumns } from "../../constants"
 import { getIntegration } from "../../integrations"
 import { getDatasourceAndQuery } from "./row/utils"
 import { invalidateDynamicVariables } from "../../threads/utils"
-import { db as dbCore, context, events } from "@budibase/backend-core"
+import { db as dbCore, context, events, cache } from "@budibase/backend-core"
 import {
   UserCtx,
   Datasource,
@@ -25,6 +25,7 @@ import {
   FetchDatasourceInfoResponse,
   IntegrationBase,
   DatasourcePlus,
+  SourceName,
 } from "@budibase/types"
 import sdk from "../../sdk"
 import { builderSocket } from "../../websockets"

From 21e870109c82e1c4ae2c7e96c3b5caeb8525c287 Mon Sep 17 00:00:00 2001
From: Adria Navarro <adria@budibase.com>
Date: Wed, 31 May 2023 14:29:45 +0200
Subject: [PATCH 09/12] Save datasource

---
 .../modals/GoogleDatasourceConfigModal.svelte | 26 +++++++++++++++----
 .../server/src/api/controllers/datasource.ts  | 11 ++++++++
 .../server/src/integrations/googlesheets.ts   | 18 ++++++++++++-
 3 files changed, 49 insertions(+), 6 deletions(-)

diff --git a/packages/builder/src/components/backend/DatasourceNavigator/modals/GoogleDatasourceConfigModal.svelte b/packages/builder/src/components/backend/DatasourceNavigator/modals/GoogleDatasourceConfigModal.svelte
index f93f7b29da..7b4808967d 100644
--- a/packages/builder/src/components/backend/DatasourceNavigator/modals/GoogleDatasourceConfigModal.svelte
+++ b/packages/builder/src/components/backend/DatasourceNavigator/modals/GoogleDatasourceConfigModal.svelte
@@ -13,6 +13,10 @@
   import { validateDatasourceConfig } from "builderStore/datasource"
   import cloneDeep from "lodash/cloneDeepWith"
   import IntegrationConfigForm from "../TableIntegrationMenu/IntegrationConfigForm.svelte"
+  import { goto } from "@roxi/routify"
+
+  import { saveDatasource } from "builderStore/datasource"
+  import { DatasourceFeature } from "@budibase/types"
 
   export let integration
   export let continueSetupId = false
@@ -36,19 +40,30 @@
     ? GoogleDatasouceConfigStep.SET_URL
     : GoogleDatasouceConfigStep.AUTH
 
-  let isValid
+  let isValid = false
 
   const modalConfig = {
     [GoogleDatasouceConfigStep.AUTH]: {},
     [GoogleDatasouceConfigStep.SET_URL]: {
       confirmButtonText: "Connect",
       onConfirm: async () => {
-        const resp = await validateDatasourceConfig(datasource)
-        if (!resp.connected) {
-          notifications.error(`Unable to connect - ${resp.error}`)
+        if (integration.features[DatasourceFeature.CONNECTION_CHECKING]) {
+          const resp = await validateDatasourceConfig(datasource)
+          if (!resp.connected) {
+            notifications.error(`Unable to connect - ${resp.error}`)
+            return false
+          }
         }
 
-        return false
+        try {
+          const resp = await saveDatasource(datasource)
+          $goto(`./datasource/${resp._id}`)
+          notifications.success(`Datasource created successfully.`)
+        } catch (err) {
+          notifications.error(err?.message ?? "Error saving datasource")
+          // prevent the modal from closing
+          return false
+        }
       },
     },
   }
@@ -61,6 +76,7 @@
   confirmText={modalConfig[step].confirmButtonText}
   showConfirmButton={!!modalConfig[step].onConfirm}
   onConfirm={modalConfig[step].onConfirm}
+  disabled={!isValid}
 >
   {#if step === GoogleDatasouceConfigStep.AUTH}
     <!-- check true and false directly, don't render until flag is set -->
diff --git a/packages/server/src/api/controllers/datasource.ts b/packages/server/src/api/controllers/datasource.ts
index f3d0c5f83b..d21db8ad03 100644
--- a/packages/server/src/api/controllers/datasource.ts
+++ b/packages/server/src/api/controllers/datasource.ts
@@ -29,6 +29,7 @@ import {
 } from "@budibase/types"
 import sdk from "../../sdk"
 import { builderSocket } from "../../websockets"
+import { setupCreationAuth as googleSetupCreationAuth } from "src/integrations/googlesheets"
 
 function getErrorTables(errors: any, errorType: string) {
   return Object.entries(errors)
@@ -307,6 +308,12 @@ export async function update(ctx: UserCtx<any, UpdateDatasourceResponse>) {
   builderSocket?.emitDatasourceUpdate(ctx, datasource)
 }
 
+const preSaveAction: Partial<Record<SourceName, any>> = {
+  [SourceName.GOOGLE_SHEETS]: async (datasource: Datasource) => {
+    await googleSetupCreationAuth(datasource.config as any)
+  },
+}
+
 export async function save(
   ctx: UserCtx<CreateDatasourceRequest, CreateDatasourceResponse>
 ) {
@@ -328,6 +335,10 @@ export async function save(
     setDefaultDisplayColumns(datasource)
   }
 
+  if (preSaveAction[datasource.source]) {
+    await preSaveAction[datasource.source](datasource)
+  }
+
   const dbResp = await db.put(datasource)
   await events.datasource.created(datasource)
   datasource._rev = dbResp.rev
diff --git a/packages/server/src/integrations/googlesheets.ts b/packages/server/src/integrations/googlesheets.ts
index 2598f6db62..a792f49b57 100644
--- a/packages/server/src/integrations/googlesheets.ts
+++ b/packages/server/src/integrations/googlesheets.ts
@@ -1,5 +1,6 @@
 import {
   ConnectionInfo,
+  Datasource,
   DatasourceFeature,
   DatasourceFieldType,
   DatasourcePlus,
@@ -19,13 +20,15 @@ import { OAuth2Client } from "google-auth-library"
 import { buildExternalTableId, finaliseExternalTables } from "./utils"
 import { GoogleSpreadsheet, GoogleSpreadsheetRow } from "google-spreadsheet"
 import fetch from "node-fetch"
-import { configs, HTTPError } from "@budibase/backend-core"
+import { cache, configs, context, HTTPError } from "@budibase/backend-core"
 import { dataFilters } from "@budibase/shared-core"
 import { GOOGLE_SHEETS_PRIMARY_KEY } from "../constants"
+import sdk from "../sdk"
 
 interface GoogleSheetsConfig {
   spreadsheetId: string
   auth: OAuthClientConfig
+  continueSetupId?: string
 }
 
 interface OAuthClientConfig {
@@ -147,6 +150,7 @@ class GoogleSheetsIntegration implements DatasourcePlus {
 
   async testConnection(): Promise<ConnectionInfo> {
     try {
+      await setupCreationAuth(this.config)
       await this.connect()
       return { connected: true }
     } catch (e: any) {
@@ -566,6 +570,18 @@ class GoogleSheetsIntegration implements DatasourcePlus {
   }
 }
 
+export async function setupCreationAuth(datasouce: GoogleSheetsConfig) {
+  if (datasouce.continueSetupId) {
+    const appId = context.getAppId()
+    const tokens = await cache.get(
+      `datasource:creation:${appId}:google:${datasouce.continueSetupId}`
+    )
+
+    datasouce.auth = tokens.tokens
+    delete datasouce.continueSetupId
+  }
+}
+
 export default {
   schema: SCHEMA,
   integration: GoogleSheetsIntegration,

From 4247b4425ca72fa9e30a33cb33d6b70c264c0301 Mon Sep 17 00:00:00 2001
From: Adria Navarro <adria@budibase.com>
Date: Thu, 1 Jun 2023 07:32:04 +0100
Subject: [PATCH 10/12] Clean code

---
 .../builder/src/pages/builder/app/[application]/data/new.svelte  | 1 -
 1 file changed, 1 deletion(-)

diff --git a/packages/builder/src/pages/builder/app/[application]/data/new.svelte b/packages/builder/src/pages/builder/app/[application]/data/new.svelte
index 23d719247d..8ff974112b 100644
--- a/packages/builder/src/pages/builder/app/[application]/data/new.svelte
+++ b/packages/builder/src/pages/builder/app/[application]/data/new.svelte
@@ -139,7 +139,6 @@
   const fetchIntegrations = async () => {
     const unsortedIntegrations = await API.getIntegrations()
     integrations = sortIntegrations(unsortedIntegrations)
-    console.log(integrations[IntegrationTypes.GOOGLE_SHEETS])
 
     if (continueGoogleSetup) {
       handleIntegrationSelect(IntegrationTypes.GOOGLE_SHEETS)

From c79b394907f4c31e1631a2de556318ffe7257cb0 Mon Sep 17 00:00:00 2001
From: Budibase Staging Release Bot <>
Date: Tue, 6 Jun 2023 10:42:24 +0000
Subject: [PATCH 11/12] Bump version to 2.6.24-alpha.2

---
 lerna.json | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lerna.json b/lerna.json
index e44a4b60c7..058b0d2e96 100644
--- a/lerna.json
+++ b/lerna.json
@@ -1,5 +1,5 @@
 {
-  "version": "2.6.24-alpha.1",
+  "version": "2.6.24-alpha.2",
   "npmClient": "yarn",
   "packages": [
     "packages/backend-core",

From 57a41e49bfdf0df24b0d61a1c4148847d2910278 Mon Sep 17 00:00:00 2001
From: Budibase Staging Release Bot <>
Date: Tue, 6 Jun 2023 10:57:28 +0000
Subject: [PATCH 12/12] Bump version to 2.6.28-alpha.0

---
 lerna.json | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lerna.json b/lerna.json
index 1352dd768e..ee9375e919 100644
--- a/lerna.json
+++ b/lerna.json
@@ -1,5 +1,5 @@
 {
-  "version": "2.6.27",
+  "version": "2.6.28-alpha.0",
   "npmClient": "yarn",
   "packages": [
     "packages/backend-core",