Merge pull request #10172 from Budibase/fix/budi-6797
Googlesheets onboarding - fix in cloud, disable self host
This commit is contained in:
commit
1c6465edcb
|
@ -32,8 +32,7 @@ export async function getConfig<T extends Config>(
|
||||||
const db = context.getGlobalDB()
|
const db = context.getGlobalDB()
|
||||||
try {
|
try {
|
||||||
// await to catch error
|
// await to catch error
|
||||||
const config = (await db.get(generateConfigID(type))) as T
|
return (await db.get(generateConfigID(type))) as T
|
||||||
return config
|
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
if (e.status === 404) {
|
if (e.status === 404) {
|
||||||
return
|
return
|
||||||
|
|
|
@ -78,17 +78,23 @@ export async function postAuth(
|
||||||
),
|
),
|
||||||
{ successRedirect: "/", failureRedirect: "/error" },
|
{ successRedirect: "/", failureRedirect: "/error" },
|
||||||
async (err: any, tokens: string[]) => {
|
async (err: any, tokens: string[]) => {
|
||||||
|
const baseUrl = `/builder/app/${authStateCookie.appId}/data`
|
||||||
// update the DB for the datasource with all the user info
|
// update the DB for the datasource with all the user info
|
||||||
await doWithDB(authStateCookie.appId, async (db: Database) => {
|
await doWithDB(authStateCookie.appId, async (db: Database) => {
|
||||||
const datasource = await db.get(authStateCookie.datasourceId)
|
let datasource
|
||||||
|
try {
|
||||||
|
datasource = await db.get(authStateCookie.datasourceId)
|
||||||
|
} catch (err: any) {
|
||||||
|
if (err.status === 404) {
|
||||||
|
ctx.redirect(baseUrl)
|
||||||
|
}
|
||||||
|
}
|
||||||
if (!datasource.config) {
|
if (!datasource.config) {
|
||||||
datasource.config = {}
|
datasource.config = {}
|
||||||
}
|
}
|
||||||
datasource.config.auth = { type: "google", ...tokens }
|
datasource.config.auth = { type: "google", ...tokens }
|
||||||
await db.put(datasource)
|
await db.put(datasource)
|
||||||
ctx.redirect(
|
ctx.redirect(`${baseUrl}/datasource/${authStateCookie.datasourceId}`)
|
||||||
`/builder/app/${authStateCookie.appId}/data/datasource/${authStateCookie.datasourceId}`
|
|
||||||
)
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
)(ctx, next)
|
)(ctx, next)
|
||||||
|
|
|
@ -5,18 +5,28 @@
|
||||||
|
|
||||||
export let preAuthStep
|
export let preAuthStep
|
||||||
export let datasource
|
export let datasource
|
||||||
|
export let disabled
|
||||||
|
|
||||||
$: tenantId = $auth.tenantId
|
$: tenantId = $auth.tenantId
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<button
|
<button
|
||||||
|
class:disabled
|
||||||
|
{disabled}
|
||||||
on:click={async () => {
|
on:click={async () => {
|
||||||
let ds = datasource
|
let ds = datasource
|
||||||
|
let appId = $store.appId
|
||||||
if (!ds) {
|
if (!ds) {
|
||||||
ds = await preAuthStep()
|
const resp = await preAuthStep()
|
||||||
|
if (resp.datasource && resp.appId) {
|
||||||
|
ds = resp.datasource
|
||||||
|
appId = resp.appId
|
||||||
|
} else {
|
||||||
|
ds = resp
|
||||||
|
}
|
||||||
}
|
}
|
||||||
window.open(
|
window.open(
|
||||||
`/api/global/auth/${tenantId}/datasource/google?datasourceId=${ds._id}&appId=${$store.appId}`,
|
`/api/global/auth/${tenantId}/datasource/google?datasourceId=${ds._id}&appId=${appId}`,
|
||||||
"_blank"
|
"_blank"
|
||||||
)
|
)
|
||||||
}}
|
}}
|
||||||
|
@ -26,6 +36,10 @@
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
.disabled {
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
button {
|
button {
|
||||||
width: 195px;
|
width: 195px;
|
||||||
height: 40px;
|
height: 40px;
|
||||||
|
|
|
@ -1,12 +1,15 @@
|
||||||
<script>
|
<script>
|
||||||
import { Button, FancyForm, FancyInput, FancyCheckbox } from "@budibase/bbui"
|
import { Button, FancyForm, FancyInput, FancyCheckbox } from "@budibase/bbui"
|
||||||
|
import GoogleButton from "components/backend/DatasourceNavigator/_components/GoogleButton.svelte"
|
||||||
import { capitalise } from "helpers/helpers"
|
import { capitalise } from "helpers/helpers"
|
||||||
import PanelHeader from "./PanelHeader.svelte"
|
import PanelHeader from "./PanelHeader.svelte"
|
||||||
|
import { helpers } from "@budibase/shared-core"
|
||||||
|
|
||||||
export let title = ""
|
export let title = ""
|
||||||
export let onBack = null
|
export let onBack = null
|
||||||
export let onNext = () => {}
|
export let onNext = () => {}
|
||||||
export let fields = {}
|
export let fields = {}
|
||||||
|
export let type = ""
|
||||||
|
|
||||||
let errors = {}
|
let errors = {}
|
||||||
|
|
||||||
|
@ -57,8 +60,9 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
$: isValid = getIsValid(fields, errors, values)
|
$: isValid = getIsValid(fields, errors, values)
|
||||||
|
$: isGoogle = helpers.isGoogleSheets(type)
|
||||||
|
|
||||||
const handleNext = () => {
|
const handleNext = async () => {
|
||||||
const parsedValues = {}
|
const parsedValues = {}
|
||||||
|
|
||||||
Object.entries(values).forEach(([name, value]) => {
|
Object.entries(values).forEach(([name, value]) => {
|
||||||
|
@ -69,7 +73,10 @@
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
return onNext(parsedValues)
|
if (isGoogle) {
|
||||||
|
parsedValues.isGoogle = isGoogle
|
||||||
|
}
|
||||||
|
return await onNext(parsedValues)
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -99,7 +106,11 @@
|
||||||
{/each}
|
{/each}
|
||||||
</FancyForm>
|
</FancyForm>
|
||||||
</div>
|
</div>
|
||||||
<Button cta disabled={!isValid} on:click={handleNext}>Connect</Button>
|
{#if isGoogle}
|
||||||
|
<GoogleButton disabled={!isValid} preAuthStep={handleNext} />
|
||||||
|
{:else}
|
||||||
|
<Button cta disabled={!isValid} on:click={handleNext}>Connect</Button>
|
||||||
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
|
|
@ -4,19 +4,20 @@
|
||||||
import DataPanel from "./_components/DataPanel.svelte"
|
import DataPanel from "./_components/DataPanel.svelte"
|
||||||
import DatasourceConfigPanel from "./_components/DatasourceConfigPanel.svelte"
|
import DatasourceConfigPanel from "./_components/DatasourceConfigPanel.svelte"
|
||||||
import ExampleApp from "./_components/ExampleApp.svelte"
|
import ExampleApp from "./_components/ExampleApp.svelte"
|
||||||
import { FancyButton, notifications, Modal } from "@budibase/bbui"
|
import { FancyButton, notifications, Modal, Body } from "@budibase/bbui"
|
||||||
import IntegrationIcon from "components/backend/DatasourceNavigator/IntegrationIcon.svelte"
|
import IntegrationIcon from "components/backend/DatasourceNavigator/IntegrationIcon.svelte"
|
||||||
import { SplitPage } from "@budibase/frontend-core"
|
import { SplitPage } from "@budibase/frontend-core"
|
||||||
import { API } from "api"
|
import { API } from "api"
|
||||||
import { store, automationStore } from "builderStore"
|
import { store, automationStore } from "builderStore"
|
||||||
import { saveDatasource } from "builderStore/datasource"
|
import { saveDatasource } from "builderStore/datasource"
|
||||||
import { integrations } from "stores/backend"
|
import { integrations } from "stores/backend"
|
||||||
import { auth, admin } from "stores/portal"
|
import { auth, admin, organisation } from "stores/portal"
|
||||||
import FontAwesomeIcon from "components/common/FontAwesomeIcon.svelte"
|
import FontAwesomeIcon from "components/common/FontAwesomeIcon.svelte"
|
||||||
import CreateTableModal from "components/backend/TableNavigator/modals/CreateTableModal.svelte"
|
import CreateTableModal from "components/backend/TableNavigator/modals/CreateTableModal.svelte"
|
||||||
import createFromScratchScreen from "builderStore/store/screenTemplates/createFromScratchScreen"
|
import createFromScratchScreen from "builderStore/store/screenTemplates/createFromScratchScreen"
|
||||||
import { Roles } from "constants/backend"
|
import { Roles } from "constants/backend"
|
||||||
import Spinner from "components/common/Spinner.svelte"
|
import Spinner from "components/common/Spinner.svelte"
|
||||||
|
import { helpers } from "@budibase/shared-core"
|
||||||
|
|
||||||
let name = "My first app"
|
let name = "My first app"
|
||||||
let url = "my-first-app"
|
let url = "my-first-app"
|
||||||
|
@ -25,10 +26,11 @@
|
||||||
|
|
||||||
let plusIntegrations = {}
|
let plusIntegrations = {}
|
||||||
let integrationsLoading = true
|
let integrationsLoading = true
|
||||||
$: getIntegrations()
|
|
||||||
let creationLoading = false
|
let creationLoading = false
|
||||||
|
|
||||||
let uploadModal
|
let uploadModal
|
||||||
|
let googleComplete = false
|
||||||
|
|
||||||
|
$: getIntegrations()
|
||||||
|
|
||||||
const createApp = async useSampleData => {
|
const createApp = async useSampleData => {
|
||||||
creationLoading = true
|
creationLoading = true
|
||||||
|
@ -62,6 +64,7 @@
|
||||||
await store.actions.screens.save(defaultScreenTemplate)
|
await store.actions.screens.save(defaultScreenTemplate)
|
||||||
|
|
||||||
appId = createdApp.instance._id
|
appId = createdApp.instance._id
|
||||||
|
return createdApp
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
creationLoading = false
|
creationLoading = false
|
||||||
throw e
|
throw e
|
||||||
|
@ -74,6 +77,13 @@
|
||||||
const newPlusIntegrations = {}
|
const newPlusIntegrations = {}
|
||||||
|
|
||||||
Object.entries($integrations).forEach(([integrationType, schema]) => {
|
Object.entries($integrations).forEach(([integrationType, schema]) => {
|
||||||
|
// google sheets not available in self-host
|
||||||
|
if (
|
||||||
|
helpers.isGoogleSheets(integrationType) &&
|
||||||
|
!$organisation.googleDatasourceConfigured
|
||||||
|
) {
|
||||||
|
return
|
||||||
|
}
|
||||||
if (schema?.plus) {
|
if (schema?.plus) {
|
||||||
newPlusIntegrations[integrationType] = schema
|
newPlusIntegrations[integrationType] = schema
|
||||||
}
|
}
|
||||||
|
@ -92,12 +102,17 @@
|
||||||
notifications.success(`App created successfully`)
|
notifications.success(`App created successfully`)
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleCreateApp = async ({ datasourceConfig, useSampleData }) => {
|
const handleCreateApp = async ({
|
||||||
|
datasourceConfig,
|
||||||
|
useSampleData,
|
||||||
|
isGoogle,
|
||||||
|
}) => {
|
||||||
try {
|
try {
|
||||||
await createApp(useSampleData)
|
const app = await createApp(useSampleData)
|
||||||
|
|
||||||
|
let datasource
|
||||||
if (datasourceConfig) {
|
if (datasourceConfig) {
|
||||||
await saveDatasource({
|
datasource = await saveDatasource({
|
||||||
plus: true,
|
plus: true,
|
||||||
auth: undefined,
|
auth: undefined,
|
||||||
name: plusIntegrations[stage].friendlyName,
|
name: plusIntegrations[stage].friendlyName,
|
||||||
|
@ -107,7 +122,14 @@
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
goToApp()
|
store.set()
|
||||||
|
|
||||||
|
if (isGoogle) {
|
||||||
|
googleComplete = true
|
||||||
|
return { datasource, appId: app.appId }
|
||||||
|
} else {
|
||||||
|
goToApp()
|
||||||
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log(e)
|
console.log(e)
|
||||||
creationLoading = false
|
creationLoading = false
|
||||||
|
@ -127,8 +149,15 @@
|
||||||
<SplitPage>
|
<SplitPage>
|
||||||
{#if stage === "name"}
|
{#if stage === "name"}
|
||||||
<NamePanel bind:name bind:url onNext={() => (stage = "data")} />
|
<NamePanel bind:name bind:url onNext={() => (stage = "data")} />
|
||||||
|
{:else if googleComplete}
|
||||||
|
<div class="centered">
|
||||||
|
<Body
|
||||||
|
>Please login to your Google account in the new tab which as opened to
|
||||||
|
continue.</Body
|
||||||
|
>
|
||||||
|
</div>
|
||||||
{:else if integrationsLoading || creationLoading}
|
{:else if integrationsLoading || creationLoading}
|
||||||
<div class="spinner">
|
<div class="centered">
|
||||||
<Spinner />
|
<Spinner />
|
||||||
</div>
|
</div>
|
||||||
{:else if stage === "data"}
|
{:else if stage === "data"}
|
||||||
|
@ -174,8 +203,13 @@
|
||||||
<DatasourceConfigPanel
|
<DatasourceConfigPanel
|
||||||
title={plusIntegrations[stage].friendlyName}
|
title={plusIntegrations[stage].friendlyName}
|
||||||
fields={plusIntegrations[stage].datasource}
|
fields={plusIntegrations[stage].datasource}
|
||||||
|
type={stage}
|
||||||
onBack={() => (stage = "data")}
|
onBack={() => (stage = "data")}
|
||||||
onNext={data => handleCreateApp({ datasourceConfig: data })}
|
onNext={data => {
|
||||||
|
const isGoogle = data.isGoogle
|
||||||
|
delete data.isGoogle
|
||||||
|
return handleCreateApp({ datasourceConfig: data, isGoogle })
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
{:else}
|
{:else}
|
||||||
<p>There was an problem. Please refresh the page and try again.</p>
|
<p>There was an problem. Please refresh the page and try again.</p>
|
||||||
|
@ -186,7 +220,7 @@
|
||||||
</SplitPage>
|
</SplitPage>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.spinner {
|
.centered {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
|
@ -245,6 +245,10 @@ class GoogleSheetsIntegration implements DatasourcePlus {
|
||||||
}
|
}
|
||||||
|
|
||||||
async buildSchema(datasourceId: string, entities: Record<string, Table>) {
|
async buildSchema(datasourceId: string, entities: Record<string, Table>) {
|
||||||
|
// not fully configured yet
|
||||||
|
if (!this.config.auth) {
|
||||||
|
return
|
||||||
|
}
|
||||||
await this.connect()
|
await this.connect()
|
||||||
const sheets = this.client.sheetsByIndex
|
const sheets = this.client.sheetsByIndex
|
||||||
const tables: Record<string, Table> = {}
|
const tables: Record<string, Table> = {}
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
export * from "./helpers"
|
||||||
|
export * from "./integrations"
|
|
@ -0,0 +1,5 @@
|
||||||
|
import { SourceName } from "@budibase/types"
|
||||||
|
|
||||||
|
export function isGoogleSheets(type: SourceName) {
|
||||||
|
return type === SourceName.GOOGLE_SHEETS
|
||||||
|
}
|
Loading…
Reference in New Issue