diff --git a/.eslintrc.json b/.eslintrc.json index 87f8269c50..79e0c00abd 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -16,7 +16,8 @@ "dist", "public", "*.spec.js", - "bundle.js" + "bundle.js", + "packages/pro" ], "plugins": ["svelte3"], "extends": ["eslint:recommended"], diff --git a/.github/workflows/deploy-cloud.yaml b/.github/workflows/deploy-cloud.yaml index fa80da846f..9f933746d6 100644 --- a/.github/workflows/deploy-cloud.yaml +++ b/.github/workflows/deploy-cloud.yaml @@ -1,43 +1,53 @@ name: Budibase Deploy Production on: - workflow_dispatch: - inputs: - version: - description: Budibase release version. For example - 1.0.0 - required: false + workflow_dispatch: + inputs: + version: + description: Budibase release version. For example - 1.0.0 + required: false jobs: release: runs-on: ubuntu-latest steps: - - name: Fail if branch is not master - if: github.ref != 'refs/heads/master' - run: | - echo "Ref is not master, you must run this job from master." - exit 1 + # - name: Fail if not a tag + # run: | + # if [[ $GITHUB_REF != refs/tags/* ]]; then + # echo "Workflow Dispatch can only be run on tags" + # exit 1 + # fi - uses: actions/checkout@v2 + # with: + # fetch-depth: 0 + + # - name: Fail if tag is not in master + # run: | + # if ! git merge-base --is-ancestor ${{ github.sha }} origin/master; then + # echo "Tag is not in master. This pipeline can only execute tags that are present on the master branch" + # exit 1 + # fi - name: Pull values.yaml from budibase-infra - run: | + run: | curl -H "Authorization: token ${{ secrets.GH_ACCESS_TOKEN }}" \ -H 'Accept: application/vnd.github.v3.raw' \ -o values.production.yaml \ -L https://api.github.com/repos/budibase/budibase-infra/contents/kubernetes/values.yaml wc -l values.production.yaml - + - name: Get the latest budibase release version id: version - run: | + run: | if [ -z "${{ github.event.inputs.version }}" ]; then release_version=$(cat lerna.json | jq -r '.version') else release_version=${{ github.event.inputs.version }} fi echo "RELEASE_VERSION=$release_version" >> $GITHUB_ENV - + - name: Configure AWS Credentials uses: aws-actions/configure-aws-credentials@v1 with: @@ -64,4 +74,3 @@ jobs: webhook-url: ${{ secrets.PROD_DEPLOY_WEBHOOK_URL }} content: "Production Deployment Complete: ${{ env.RELEASE_VERSION }} deployed to Budibase Cloud." embed-title: ${{ env.RELEASE_VERSION }} - diff --git a/.github/workflows/deploy-preprod.yml b/.github/workflows/deploy-preprod.yml index 57e2504ded..81395bc7e3 100644 --- a/.github/workflows/deploy-preprod.yml +++ b/.github/workflows/deploy-preprod.yml @@ -1,27 +1,35 @@ name: "deploy-preprod" on: workflow_dispatch: - inputs: - version: - description: Budibase release version. For example - 1.0.0 - required: false workflow_call: jobs: deploy-to-legacy-preprod-env: runs-on: ubuntu-latest steps: + - name: Fail if not a tag + run: | + if [[ $GITHUB_REF != refs/tags/* ]]; then + echo "Workflow Dispatch can only be run on tags" + exit 1 + fi + - uses: actions/checkout@v2 + with: + fetch-depth: 0 + + - name: Fail if tag is not in master + run: | + if ! git merge-base --is-ancestor ${{ github.sha }} origin/master; then + echo "Tag is not in master. This pipeline can only execute tags that are present on the master branch" + exit 1 + fi + - name: Get the latest budibase release version id: version run: | - if [ -z "${{ github.event.inputs.version }}" ]; then - git pull - release_version=$(cat lerna.json | jq -r '.version') - else - release_version=${{ github.event.inputs.version }} - fi + release_version=$(cat lerna.json | jq -r '.version') echo "RELEASE_VERSION=$release_version" >> $GITHUB_ENV - name: Configure AWS Credentials uses: aws-actions/configure-aws-credentials@v1 diff --git a/.github/workflows/release-develop.yml b/.github/workflows/release-develop.yml index 48c51e8457..503fc53194 100644 --- a/.github/workflows/release-develop.yml +++ b/.github/workflows/release-develop.yml @@ -22,6 +22,13 @@ jobs: runs-on: ubuntu-latest steps: + - name: Fail if not a tag + run: | + if [[ $GITHUB_REF != refs/tags/* ]]; then + echo "Workflow Dispatch can only be run on tags" + exit 1 + fi + - uses: actions/checkout@v2 with: submodules: true diff --git a/.github/workflows/release-master.yml b/.github/workflows/release-master.yml index f05d369a34..a4e679e7bf 100644 --- a/.github/workflows/release-master.yml +++ b/.github/workflows/release-master.yml @@ -9,12 +9,6 @@ on: - "v[0-9]+.[0-9]+.[0-9]+" # Exclude all pre-releases - "!v*[0-9]+.[0-9]+.[0-9]+-*" - workflow_dispatch: - inputs: - tags: - description: "Release tag" - required: true - type: boolean env: # Posthog token used by ui at build time @@ -33,12 +27,13 @@ jobs: token: ${{ secrets.PERSONAL_ACCESS_TOKEN }} fetch-depth: 0 - - name: Fail if branch is not master - if: github.ref != 'refs/heads/master' + - name: Fail if tag is not in master run: | - echo "Ref is not master, you must run this job from master." - // Change to "exit 1" when merged. Left to 0 to not fail all the pipelines and not to cause noise - exit 0 + if ! git merge-base --is-ancestor ${{ github.sha }} origin/master; then + echo "Tag is not in master. This pipeline can only execute tags that are present on the master branch" + exit 1 + fi + - uses: actions/setup-node@v1 with: @@ -65,7 +60,6 @@ jobs: - name: Publish budibase packages to NPM env: NPM_TOKEN: ${{ secrets.NPM_TOKEN }} - RELEASE_VERSION_TYPE: ${{ github.event.inputs.versioning }} run: | # setup the username and email. I tend to use 'GitHub Actions Bot' with no email by default git config --global user.name "Budibase Release Bot" @@ -140,7 +134,6 @@ jobs: - name: Get the latest budibase release version id: version run: | - git pull release_version=$(cat lerna.json | jq -r '.version') echo "RELEASE_VERSION=$release_version" >> $GITHUB_ENV diff --git a/.github/workflows/release-selfhost.yml b/.github/workflows/release-selfhost.yml index f5a2f643c3..7a56748dfb 100644 --- a/.github/workflows/release-selfhost.yml +++ b/.github/workflows/release-selfhost.yml @@ -1,22 +1,30 @@ name: Budibase Release Selfhost on: - workflow_dispatch: + workflow_dispatch: jobs: release: runs-on: ubuntu-latest steps: - - name: Fail if branch is not master - if: github.ref != 'refs/heads/master' + - name: Fail if not a tag run: | - echo "Ref is not master, you must run this job from master." - exit 1 + if [[ $GITHUB_REF != refs/tags/* ]]; then + echo "Workflow Dispatch can only be run on tags" + exit 1 + fi - uses: actions/checkout@v2 - with: - fetch_depth: 0 + with: + fetch-depth: 0 + + - name: Fail if tag is not in master + run: | + if ! git merge-base --is-ancestor ${{ github.sha }} origin/master; then + echo "Tag is not in master. This pipeline can only execute tags that are present on the master branch" + exit 1 + fi - name: Use Node.js 14.x uses: actions/setup-node@v1 @@ -30,7 +38,7 @@ jobs: echo "RELEASE_VERSION=$release_version" >> $GITHUB_ENV - name: Tag and release Docker images (Self Host) - run: | + run: | docker login -u $DOCKER_USER -p $DOCKER_PASSWORD release_tag=v${{ env.RELEASE_VERSION }} @@ -44,7 +52,7 @@ jobs: docker tag budibase/apps:$release_tag budibase/apps:$SELFHOST_TAG docker tag budibase/worker:$release_tag budibase/worker:$SELFHOST_TAG docker tag budibase/proxy:$release_tag budibase/proxy:$SELFHOST_TAG - + # Push images docker push budibase/apps:$SELFHOST_TAG docker push budibase/worker:$SELFHOST_TAG @@ -66,19 +74,19 @@ jobs: yarn yarn specs popd - - - name: Setup Helm + + - name: Setup Helm uses: azure/setup-helm@v1 id: helm-install # due to helm repo index issue: https://github.com/helm/helm/issues/7363 # we need to create new package in a different dir, merge the index and move the package back - name: Build and release helm chart - run: | + run: | git config user.name "Budibase Helm Bot" git config user.email "<>" git reset --hard - git pull + git fetch mkdir sync echo "Packaging chart to sync dir" helm package charts/budibase --version "$RELEASE_VERSION" --app-version "$RELEASE_VERSION" --destination sync diff --git a/.github/workflows/release-singleimage.yml b/.github/workflows/release-singleimage.yml index cd16574eea..fbf972a866 100644 --- a/.github/workflows/release-singleimage.yml +++ b/.github/workflows/release-singleimage.yml @@ -15,13 +15,24 @@ jobs: matrix: node-version: [14.x] steps: - - name: Fail if branch is not master - if: github.ref != 'refs/heads/master' - run: | - echo "Ref is not master, you must run this job from master." - exit 1 + - name: Fail if not a tag + run: | + if [[ $GITHUB_REF != refs/tags/* ]]; then + echo "Workflow Dispatch can only be run on tags" + exit 1 + fi - name: "Checkout" uses: actions/checkout@v2 + with: + fetch-depth: 0 + + - name: Fail if tag is not in master + run: | + if ! git merge-base --is-ancestor ${{ github.sha }} origin/master; then + echo "Tag is not in master. This pipeline can only execute tags that are present on the master branch" + exit 1 + fi + - name: Use Node.js ${{ matrix.node-version }} uses: actions/setup-node@v1 with: diff --git a/.github/workflows/tag-release.yml b/.github/workflows/tag-release.yml index 1dcb16ac56..f361c200a0 100644 --- a/.github/workflows/tag-release.yml +++ b/.github/workflows/tag-release.yml @@ -28,7 +28,7 @@ on: required: true jobs: - tag-prerelease: + tag-release: runs-on: ubuntu-latest steps: @@ -43,9 +43,11 @@ jobs: token: ${{ secrets.PERSONAL_ACCESS_TOKEN }} - run: yarn - - name: Tag prerelease + - name: Tag release run: | # setup the username and email. git config --global user.name "Budibase Staging Release Bot" git config --global user.email "<>" - ./scripts/versionCommit.sh ${{ github.event.inputs.versioning }} + BUMP_TYPE_INPUT=${{ github.event.inputs.versioning }} + BUMP_TYPE=${BUMP_TYPE_INPUT:-"patch"} + ./scripts/versionCommit.sh $BUMP_TYPE diff --git a/lerna.json b/lerna.json index 9f8cd12e31..21ffea6191 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "2.6.24-alpha.0", + "version": "2.7.1-alpha.1", "npmClient": "yarn", "packages": [ "packages/backend-core", diff --git a/package.json b/package.json index 3849c65274..ffb3fa775a 100644 --- a/package.json +++ b/package.json @@ -38,8 +38,8 @@ "backend:build": "./scripts/scopeBackend.sh 'lerna run --stream build'", "build:sdk": "lerna run --stream build:sdk", "deps:circular": "madge packages/server/dist/index.js packages/worker/src/index.ts packages/backend-core/dist/src/index.js packages/cli/src/index.js --circular", - "release": "lerna publish ${RELEASE_VERSION_TYPE:-patch} --yes --force-publish --no-git-tag-version --no-push --no-git-reset", - "release:develop": "lerna publish from-package --yes --force-publish --dist-tag develop --exact --no-git-tag-version --no-push --no-git-reset", + "release": "lerna publish from-package --yes --force-publish --no-git-tag-version --no-push --no-git-reset", + "release:develop": "yarn release --dist-tag develop", "restore": "yarn run clean && yarn run bootstrap && yarn run build", "nuke": "yarn run nuke:packages && yarn run nuke:docker", "nuke:packages": "yarn run restore", diff --git a/packages/backend-core/src/events/publishers/user.ts b/packages/backend-core/src/events/publishers/user.ts index 0d08c0a759..43e5355bd5 100644 --- a/packages/backend-core/src/events/publishers/user.ts +++ b/packages/backend-core/src/events/publishers/user.ts @@ -3,6 +3,7 @@ import { Event, User, UserCreatedEvent, + UserDataCollaborationEvent, UserDeletedEvent, UserInviteAcceptedEvent, UserInvitedEvent, @@ -173,6 +174,15 @@ async function passwordReset(user: User) { await publishEvent(Event.USER_PASSWORD_RESET, properties) } +// COLLABORATION + +async function dataCollaboration(users: number) { + const properties: UserDataCollaborationEvent = { + users, + } + await publishEvent(Event.USER_DATA_COLLABORATION, properties) +} + export default { created, updated, @@ -188,4 +198,5 @@ export default { passwordUpdated, passwordResetRequested, passwordReset, + dataCollaboration, } diff --git a/packages/backend-core/src/middleware/passport/datasource/google.ts b/packages/backend-core/src/middleware/passport/datasource/google.ts index 6fd4e9ff32..2f91e01d9a 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?continue_google_setup=${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 0783a9fe53..7b4808967d 100644 --- a/packages/builder/src/components/backend/DatasourceNavigator/modals/GoogleDatasourceConfigModal.svelte +++ b/packages/builder/src/components/backend/DatasourceNavigator/modals/GoogleDatasourceConfigModal.svelte @@ -1,43 +1,110 @@ - - {#if isGoogleConfigured === true} - + {#if step === GoogleDatasouceConfigStep.AUTH} + + {#if isGoogleConfigured === true} + + Authenticate with your google account to use the {integrationName} integration. + + + {:else if isGoogleConfigured === false} Authenticate with your google account to use the {IntegrationNames[ - datasource.type - ]} integration.Google authentication is not enabled, please complete Google SSO + configuration. + Configure Google SSO + {/if} + {/if} + {#if step === GoogleDatasouceConfigStep.SET_URL} + + Add the URL of the sheet you want to connect. + + (isValid = e.detail)} + /> - save(datasource, true)} /> - {:else if isGoogleConfigured === false} - Google authentication is not enabled, please complete Google SSO - configuration. - Configure Google SSO {/if} 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..8ff974112b 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 @@ -129,9 +130,19 @@ return integrationsArray } + let continueGoogleSetup + onMount(() => { + const urlParams = new URLSearchParams(window.location.search) + continueGoogleSetup = urlParams.get("continue_google_setup") + }) + const fetchIntegrations = async () => { const unsortedIntegrations = await API.getIntegrations() integrations = sortIntegrations(unsortedIntegrations) + + if (continueGoogleSetup) { + handleIntegrationSelect(IntegrationTypes.GOOGLE_SHEETS) + } } $: fetchIntegrations() @@ -141,9 +152,17 @@ - + { + continueGoogleSetup = null + }} +> {#if integration?.auth?.type === "google"} - + {:else} {/if} 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 @@ + + +{#if providers.google} + + + +
+ + Google +
+
+ + To allow users to authenticate using their Google accounts, fill out the + fields below. Read the documentation for more information. + +
+ + {#each GoogleConfigFields.Google as field} +
+ +
+
+ +
+ {#if field.copyButton} +
copyToClipboard(field.placeholder)} + > + +
+ {/if} +
+
+ {/each} +
+ + +
+
+
+ +
+{/if} + + 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 @@