diff --git a/.github/workflows/budibase_ci.yml b/.github/workflows/budibase_ci.yml index 1b236caab56..4c5cc94d2b4 100644 --- a/.github/workflows/budibase_ci.yml +++ b/.github/workflows/budibase_ci.yml @@ -240,7 +240,7 @@ jobs: any_commit=$(git log --no-merges $base_commit_excluding_merges...$pro_commit) - if [ -n "$any_commit" ]; then + if [ -n "$any_commit" ] && [ "$base_commit" != "$pro_commit" ]; then echo $any_commit echo "An error occurred: " diff --git a/charts/budibase/templates/app-service-deployment.yaml b/charts/budibase/templates/app-service-deployment.yaml index a60b2797ead..2b099d01f59 100644 --- a/charts/budibase/templates/app-service-deployment.yaml +++ b/charts/budibase/templates/app-service-deployment.yaml @@ -212,10 +212,6 @@ spec: - name: APP_FEATURES value: "api" {{- end }} - {{- if .Values.globals.sqs.enabled }} - - name: SQS_SEARCH_ENABLE - value: "true" - {{- end }} {{- range .Values.services.apps.extraEnv }} - name: {{ .name }} value: {{ .value | quote }} diff --git a/charts/budibase/templates/worker-service-deployment.yaml b/charts/budibase/templates/worker-service-deployment.yaml index fbd88e862f9..dcab33fa58c 100644 --- a/charts/budibase/templates/worker-service-deployment.yaml +++ b/charts/budibase/templates/worker-service-deployment.yaml @@ -198,10 +198,6 @@ spec: - name: NODE_TLS_REJECT_UNAUTHORIZED value: {{ .Values.services.tlsRejectUnauthorized }} {{ end }} - {{- if .Values.globals.sqs.enabled }} - - name: SQS_SEARCH_ENABLE - value: "true" - {{- end }} {{- range .Values.services.worker.extraEnv }} - name: {{ .name }} value: {{ .value | quote }} diff --git a/examples/nextjs-api-sales/yarn.lock b/examples/nextjs-api-sales/yarn.lock index 2c360662114..a44956ba21c 100644 --- a/examples/nextjs-api-sales/yarn.lock +++ b/examples/nextjs-api-sales/yarn.lock @@ -329,7 +329,7 @@ brace-expansion@^1.1.7: balanced-match "^1.0.0" concat-map "0.0.1" -braces@^3.0.1, braces@~3.0.2: +braces@^3.0.3, braces@~3.0.2: version "3.0.3" resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== @@ -1201,12 +1201,12 @@ merge2@^1.3.0, merge2@^1.4.1: integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== micromatch@^4.0.4: - version "4.0.4" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.4.tgz#896d519dfe9db25fce94ceb7a500919bf881ebf9" - integrity sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg== + version "4.0.8" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202" + integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA== dependencies: - braces "^3.0.1" - picomatch "^2.2.3" + braces "^3.0.3" + picomatch "^2.3.1" minimatch@^3.0.4, minimatch@^3.1.2: version "3.1.2" @@ -1422,7 +1422,7 @@ picocolors@^1.0.0: resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== -picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3: +picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.3.1: version "2.3.1" resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== diff --git a/hosting/docker-compose.build.yaml b/hosting/docker-compose.build.yaml index 253dda02323..1f16baa9e29 100644 --- a/hosting/docker-compose.build.yaml +++ b/hosting/docker-compose.build.yaml @@ -29,7 +29,7 @@ services: BB_ADMIN_USER_EMAIL: ${BB_ADMIN_USER_EMAIL} BB_ADMIN_USER_PASSWORD: ${BB_ADMIN_USER_PASSWORD} PLUGINS_DIR: ${PLUGINS_DIR} - SQS_SEARCH_ENABLE: 1 + TENANT_FEATURE_FLAGS: "*:SQS" depends_on: - worker-service - redis-service @@ -57,7 +57,7 @@ services: INTERNAL_API_KEY: ${INTERNAL_API_KEY} REDIS_URL: redis-service:6379 REDIS_PASSWORD: ${REDIS_PASSWORD} - SQS_SEARCH_ENABLE: 1 + TENANT_FEATURE_FLAGS: "*:SQS" depends_on: - redis-service - minio-service diff --git a/lerna.json b/lerna.json index 00a472c483d..754041d6efc 100644 --- a/lerna.json +++ b/lerna.json @@ -1,6 +1,6 @@ { "$schema": "node_modules/lerna/schemas/lerna-schema.json", - "version": "2.31.2", + "version": "2.31.3", "npmClient": "yarn", "packages": [ "packages/*", diff --git a/packages/account-portal b/packages/account-portal index 60f2b7531aa..c24374879d2 160000 --- a/packages/account-portal +++ b/packages/account-portal @@ -1 +1 @@ -Subproject commit 60f2b7531aac71b2161338b7e4ef08d2b3bd09e4 +Subproject commit c24374879d2b61516fabc24d7404e7da235be05e diff --git a/packages/backend-core/src/db/couch/DatabaseImpl.ts b/packages/backend-core/src/db/couch/DatabaseImpl.ts index 61fbb3d61e9..aa4656bf64d 100644 --- a/packages/backend-core/src/db/couch/DatabaseImpl.ts +++ b/packages/backend-core/src/db/couch/DatabaseImpl.ts @@ -25,8 +25,8 @@ import { newid } from "../../docIds/newid" import { SQLITE_DESIGN_DOC_ID } from "../../constants" import { DDInstrumentedDatabase } from "../instrumentation" import { checkSlashesInUrl } from "../../helpers" -import env from "../../environment" import { sqlLog } from "../../sql/utils" +import { flags } from "../../features" const DATABASE_NOT_FOUND = "Database does not exist." @@ -401,7 +401,10 @@ export class DatabaseImpl implements Database { } async destroy() { - if (env.SQS_SEARCH_ENABLE && (await this.exists(SQLITE_DESIGN_DOC_ID))) { + if ( + (await flags.isEnabled("SQS")) && + (await this.exists(SQLITE_DESIGN_DOC_ID)) + ) { // delete the design document, then run the cleanup operation const definition = await this.get(SQLITE_DESIGN_DOC_ID) // remove all tables - save the definition then trigger a cleanup diff --git a/packages/backend-core/src/db/tests/index.spec.js b/packages/backend-core/src/db/tests/index.spec.js deleted file mode 100644 index e03c9a5b0e7..00000000000 --- a/packages/backend-core/src/db/tests/index.spec.js +++ /dev/null @@ -1,24 +0,0 @@ -require("../../../tests") -const { structures } = require("../../../tests") -const { getDB } = require("../db") - -describe("db", () => { - describe("getDB", () => { - it("returns a db", async () => { - const dbName = structures.db.id() - const db = getDB(dbName) - expect(db).toBeDefined() - expect(db.name).toBe(dbName) - }) - - it("uses the custom put function", async () => { - const db = getDB(structures.db.id()) - let doc = { _id: "test" } - await db.put(doc) - doc = await db.get(doc._id) - expect(doc.createdAt).toBe(new Date().toISOString()) - expect(doc.updatedAt).toBe(new Date().toISOString()) - await db.destroy() - }) - }) -}) diff --git a/packages/backend-core/src/db/tests/index.spec.ts b/packages/backend-core/src/db/tests/index.spec.ts new file mode 100644 index 00000000000..cbad64a6a6f --- /dev/null +++ b/packages/backend-core/src/db/tests/index.spec.ts @@ -0,0 +1,32 @@ +import { doInTenant } from "../../context" +import { structures } from "../../../tests" +import { getDB } from "../db" + +interface Doc { + _id: string + createdAt?: string + updatedAt?: string +} + +describe("db", () => { + describe("getDB", () => { + it("returns a db", async () => { + const dbName = structures.db.id() + const db = getDB(dbName) + expect(db).toBeDefined() + expect(db.name).toBe(dbName) + }) + + it("uses the custom put function", async () => { + await doInTenant("foo", async () => { + const db = getDB(structures.db.id()) + let doc: Doc = { _id: "test" } + await db.put(doc) + doc = await db.get(doc._id) + expect(doc.createdAt).toBe(new Date().toISOString()) + expect(doc.updatedAt).toBe(new Date().toISOString()) + await db.destroy() + }) + }) + }) +}) diff --git a/packages/backend-core/src/db/utils.ts b/packages/backend-core/src/db/utils.ts index a7ad453066e..906a95e1db3 100644 --- a/packages/backend-core/src/db/utils.ts +++ b/packages/backend-core/src/db/utils.ts @@ -1,6 +1,6 @@ import env from "../environment" import { DEFAULT_TENANT_ID, SEPARATOR, DocumentType } from "../constants" -import { getTenantId, getGlobalDBName, isMultiTenant } from "../context" +import { getTenantId, getGlobalDBName } from "../context" import { doWithDB, directCouchAllDbs } from "./db" import { AppState, DeletedApp, getAppMetadata } from "../cache/appMetadata" import { isDevApp, isDevAppID, getProdAppID } from "../docIds/conversions" @@ -206,34 +206,3 @@ export function pagination( nextPage, } } - -export function isSqsEnabledForTenant(): boolean { - const tenantId = getTenantId() - if (!env.SQS_SEARCH_ENABLE) { - return false - } - - // single tenant (self host and dev) always enabled if flag set - if (!isMultiTenant()) { - return true - } - - // This is to guard against the situation in tests where tests pass because - // we're not actually using SQS, we're using Lucene and the tests pass due to - // parity. - if (env.isTest() && env.SQS_SEARCH_ENABLE_TENANTS.length === 0) { - throw new Error( - "to enable SQS you must specify a list of tenants in the SQS_SEARCH_ENABLE_TENANTS env var" - ) - } - - // Special case to enable all tenants, for testing in QA. - if ( - env.SQS_SEARCH_ENABLE_TENANTS.length === 1 && - env.SQS_SEARCH_ENABLE_TENANTS[0] === "*" - ) { - return true - } - - return env.SQS_SEARCH_ENABLE_TENANTS.includes(tenantId) -} diff --git a/packages/backend-core/src/environment.ts b/packages/backend-core/src/environment.ts index 6377d682d0c..3d931a8c67c 100644 --- a/packages/backend-core/src/environment.ts +++ b/packages/backend-core/src/environment.ts @@ -116,10 +116,6 @@ const environment = { API_ENCRYPTION_KEY: getAPIEncryptionKey(), COUCH_DB_URL: process.env.COUCH_DB_URL || "http://localhost:4005", COUCH_DB_SQL_URL: process.env.COUCH_DB_SQL_URL, - SQS_SEARCH_ENABLE: process.env.SQS_SEARCH_ENABLE, - SQS_SEARCH_ENABLE_TENANTS: - process.env.SQS_SEARCH_ENABLE_TENANTS?.split(",") || [], - SQS_MIGRATION_ENABLE: process.env.SQS_MIGRATION_ENABLE, COUCH_DB_USERNAME: process.env.COUCH_DB_USER, COUCH_DB_PASSWORD: process.env.COUCH_DB_PASSWORD, GOOGLE_CLIENT_ID: process.env.GOOGLE_CLIENT_ID, diff --git a/packages/backend-core/src/features/index.ts b/packages/backend-core/src/features/index.ts index e0bd29b1bc0..a8d6f0d0ef3 100644 --- a/packages/backend-core/src/features/index.ts +++ b/packages/backend-core/src/features/index.ts @@ -6,7 +6,7 @@ import tracer from "dd-trace" let posthog: PostHog | undefined export function init(opts?: PostHogOptions) { - if (env.POSTHOG_TOKEN && env.POSTHOG_API_HOST) { + if (env.POSTHOG_TOKEN && env.POSTHOG_API_HOST && !env.SELF_HOSTED) { console.log("initializing posthog client...") posthog = new PostHog(env.POSTHOG_TOKEN, { host: env.POSTHOG_API_HOST, @@ -267,4 +267,5 @@ export class FlagSet, T extends { [key: string]: V }> { // default values set correctly and their types flow through the system. export const flags = new FlagSet({ DEFAULT_VALUES: Flag.boolean(false), + SQS: Flag.boolean(false), }) diff --git a/packages/backend-core/src/features/tests/features.spec.ts b/packages/backend-core/src/features/tests/features.spec.ts index 5cd012f7a5d..d092585cc6b 100644 --- a/packages/backend-core/src/features/tests/features.spec.ts +++ b/packages/backend-core/src/features/tests/features.spec.ts @@ -147,13 +147,13 @@ describe("feature flags", () => { }) => { const env: Partial = { TENANT_FEATURE_FLAGS: environmentFlags, + SELF_HOSTED: false, } if (posthogFlags) { mockPosthogFlags(posthogFlags) env.POSTHOG_TOKEN = "test" env.POSTHOG_API_HOST = "https://us.i.posthog.com" - env.POSTHOG_PERSONAL_TOKEN = "test" } const ctx = { user: { license: { features: licenseFlags || [] } } } diff --git a/packages/backend-core/src/tenancy/db.ts b/packages/backend-core/src/tenancy/db.ts index d430296a5c2..332ecbca48a 100644 --- a/packages/backend-core/src/tenancy/db.ts +++ b/packages/backend-core/src/tenancy/db.ts @@ -15,7 +15,15 @@ export async function saveTenantInfo(tenantInfo: TenantInfo) { }) } -export async function getTenantInfo(tenantId: string): Promise { - const db = getTenantDB(tenantId) - return db.get("tenant_info") +export async function getTenantInfo( + tenantId: string +): Promise { + try { + const db = getTenantDB(tenantId) + const tenantInfo = (await db.get("tenant_info")) as TenantInfo + delete tenantInfo.owner.password + return tenantInfo + } catch { + return undefined + } } diff --git a/packages/bbui/src/Modal/Modal.svelte b/packages/bbui/src/Modal/Modal.svelte index dec1455d0cd..c5a6ffc17b6 100644 --- a/packages/bbui/src/Modal/Modal.svelte +++ b/packages/bbui/src/Modal/Modal.svelte @@ -10,7 +10,7 @@ export let inline = false export let disableCancel = false export let autoFocus = true - export let zIndex = 999 + export let zIndex = 1001 const dispatch = createEventDispatcher() let visible = fixed || inline diff --git a/packages/bbui/src/Table/SelectEditRenderer.svelte b/packages/bbui/src/Table/SelectEditRenderer.svelte index c6eafa3ed0c..0c88fa31672 100644 --- a/packages/bbui/src/Table/SelectEditRenderer.svelte +++ b/packages/bbui/src/Table/SelectEditRenderer.svelte @@ -6,10 +6,11 @@ export let onEdit export let allowSelectRows = false export let allowEditRows = false + export let data
- {#if allowSelectRows} + {#if allowSelectRows && data.__selectable !== false} {/if} {#if allowEditRows} diff --git a/packages/bbui/src/Table/Table.svelte b/packages/bbui/src/Table/Table.svelte index 868f7b3a0ba..3916bec7388 100644 --- a/packages/bbui/src/Table/Table.svelte +++ b/packages/bbui/src/Table/Table.svelte @@ -43,6 +43,8 @@ export let showHeaderBorder = true export let placeholderText = "No rows found" export let snippets = [] + export let defaultSortColumn + export let defaultSortOrder = "Ascending" const dispatch = createEventDispatcher() @@ -162,6 +164,8 @@ } const sortRows = (rows, sortColumn, sortOrder) => { + sortColumn = sortColumn ?? defaultSortColumn + sortOrder = sortOrder ?? defaultSortOrder if (!sortColumn || !sortOrder || disableSorting) { return rows } @@ -259,7 +263,10 @@ if (select) { // Add any rows which are not already in selected rows rows.forEach(row => { - if (selectedRows.findIndex(x => x._id === row._id) === -1) { + if ( + row.__selectable !== false && + selectedRows.findIndex(x => x._id === row._id) === -1 + ) { selectedRows.push(row) } }) @@ -396,6 +403,9 @@ class:noBorderCheckbox={!showHeaderBorder} class="spectrum-Table-cell spectrum-Table-cell--divider spectrum-Table-cell--edit" on:click={e => { + if (row.__selectable === false) { + return + } toggleSelectRow(row) e.stopPropagation() }} diff --git a/packages/builder/src/pages/builder/portal/users/users/[userId].svelte b/packages/builder/src/pages/builder/portal/users/users/[userId].svelte index d4e765a4be3..458c9a3f798 100644 --- a/packages/builder/src/pages/builder/portal/users/users/[userId].svelte +++ b/packages/builder/src/pages/builder/portal/users/users/[userId].svelte @@ -85,7 +85,7 @@ let popoverAnchor let searchTerm = "" let popover - let user + let user, tenantOwner let loaded = false $: internalGroups = $groups?.filter(g => !g?.scimInfo?.isSync) @@ -104,6 +104,7 @@ }) }) $: globalRole = users.getUserRole(user) + $: isTenantOwner = tenantOwner?.email && tenantOwner.email === user?.email const getAvailableApps = (appList, privileged, roles) => { let availableApps = appList.slice() @@ -205,6 +206,7 @@ if (!user?._id) { $goto("./") } + tenantOwner = await users.tenantOwner($auth.tenantId) } async function toggleFlags(detail) { @@ -268,9 +270,11 @@ Force password reset {/if} - - Delete - + {#if !isTenantOwner} + + Delete + + {/if}
{/if} @@ -310,9 +314,11 @@