From 3de8c531667ab04725e3de114100fefde66bc368 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Fri, 6 Oct 2023 11:57:11 +0100 Subject: [PATCH 01/20] Adding a mapping layer to search queries so that we can map search inputs based on the table schema if desired - primarily for the user column. --- .../controls/FilterEditor/FilterDrawer.svelte | 2 +- .../src/sdk/app/rows/search/external.ts | 5 +- .../src/sdk/app/rows/search/internal.ts | 6 +-- .../sdk/app/rows/search/tests/utils.spec.ts | 49 +++++++++++++++++ .../server/src/sdk/app/rows/search/utils.ts | 53 +++++++++++++++++++ packages/shared-core/src/filters.ts | 1 - 6 files changed, 110 insertions(+), 6 deletions(-) create mode 100644 packages/server/src/sdk/app/rows/search/tests/utils.spec.ts create mode 100644 packages/server/src/sdk/app/rows/search/utils.ts diff --git a/packages/builder/src/components/design/settings/controls/FilterEditor/FilterDrawer.svelte b/packages/builder/src/components/design/settings/controls/FilterEditor/FilterDrawer.svelte index 822442fcea..c03085e66f 100644 --- a/packages/builder/src/components/design/settings/controls/FilterEditor/FilterDrawer.svelte +++ b/packages/builder/src/components/design/settings/controls/FilterEditor/FilterDrawer.svelte @@ -191,7 +191,7 @@ } const getValidOperatorsForType = filter => { - if (!filter) { + if (!filter.field) { return [] } diff --git a/packages/server/src/sdk/app/rows/search/external.ts b/packages/server/src/sdk/app/rows/search/external.ts index f908be0b3c..8dd141f8ef 100644 --- a/packages/server/src/sdk/app/rows/search/external.ts +++ b/packages/server/src/sdk/app/rows/search/external.ts @@ -16,6 +16,7 @@ import { cleanExportRows } from "../utils" import { utils } from "@budibase/shared-core" import { ExportRowsParams, ExportRowsResult } from "../search" import { HTTPError, db } from "@budibase/backend-core" +import { searchInputMapping } from "./utils" import pick from "lodash/pick" import { outputProcessing } from "../../../../utilities/rowProcessor" @@ -50,7 +51,10 @@ export async function search(options: SearchParams) { [params.sort]: { direction }, } } + try { + const table = await sdk.tables.getTable(tableId) + options = searchInputMapping(table, options) let rows = (await handleRequest(Operation.READ, tableId, { filters: query, sort, @@ -76,7 +80,6 @@ export async function search(options: SearchParams) { rows = rows.map((r: any) => pick(r, fields)) } - const table = await sdk.tables.getTable(tableId) rows = await outputProcessing(table, rows, { preserveLinks: true }) // need wrapper object for bookmarks etc when paginating diff --git a/packages/server/src/sdk/app/rows/search/internal.ts b/packages/server/src/sdk/app/rows/search/internal.ts index 4cdeca87f6..d78c0213b3 100644 --- a/packages/server/src/sdk/app/rows/search/internal.ts +++ b/packages/server/src/sdk/app/rows/search/internal.ts @@ -29,6 +29,7 @@ import { } from "../../../../api/controllers/view/utils" import sdk from "../../../../sdk" import { ExportRowsParams, ExportRowsResult } from "../search" +import { searchInputMapping } from "./utils" import pick from "lodash/pick" export async function search(options: SearchParams) { @@ -47,9 +48,9 @@ export async function search(options: SearchParams) { disableEscaping: options.disableEscaping, } - let table + let table = await sdk.tables.getTable(tableId) + options = searchInputMapping(table, options) if (params.sort && !params.sortType) { - table = await sdk.tables.getTable(tableId) const schema = table.schema const sortField = schema[params.sort] params.sortType = sortField.type === "number" ? "number" : "string" @@ -68,7 +69,6 @@ export async function search(options: SearchParams) { if (tableId === InternalTables.USER_METADATA) { response.rows = await getGlobalUsersFromMetadata(response.rows) } - table = table || (await sdk.tables.getTable(tableId)) if (options.fields) { const fields = [...options.fields, ...db.CONSTANT_INTERNAL_ROW_COLS] diff --git a/packages/server/src/sdk/app/rows/search/tests/utils.spec.ts b/packages/server/src/sdk/app/rows/search/tests/utils.spec.ts new file mode 100644 index 0000000000..01db0d421b --- /dev/null +++ b/packages/server/src/sdk/app/rows/search/tests/utils.spec.ts @@ -0,0 +1,49 @@ +import { searchInputMapping } from "../utils" +import { db as dbCore } from "@budibase/backend-core" +import { + FieldType, + FieldTypeSubtypes, + Table, + SearchParams, +} from "@budibase/types" + +const tableId = "ta_a" +const tableWithUserCol: Table = { + _id: tableId, + name: "table", + schema: { + user: { + name: "user", + type: FieldType.BB_REFERENCE, + subtype: FieldTypeSubtypes.BB_REFERENCE.USER, + }, + }, +} + +describe("searchInputMapping", () => { + it("should be able to map ro_ to global user IDs", () => { + const globalUserId = dbCore.generateGlobalUserID() + const userMedataId = dbCore.generateUserMetadataID(globalUserId) + const params: SearchParams = { + tableId, + query: { + equal: { + "1:user": userMedataId, + }, + }, + } + const output = searchInputMapping(tableWithUserCol, params) + expect(output.query.equal!["1:user"]).toBe(globalUserId) + }) + + it("shouldn't change any other input", () => { + const params: SearchParams = { + tableId, + query: { + equal: { + "1:user": "test@test.com", + }, + }, + } + }) +}) diff --git a/packages/server/src/sdk/app/rows/search/utils.ts b/packages/server/src/sdk/app/rows/search/utils.ts new file mode 100644 index 0000000000..c86df9bc0d --- /dev/null +++ b/packages/server/src/sdk/app/rows/search/utils.ts @@ -0,0 +1,53 @@ +import { + FieldType, + FieldTypeSubtypes, + SearchParams, + Table, + DocumentType, + SEPARATOR, +} from "@budibase/types" +import { db as dbCore } from "@budibase/backend-core" + +function findColumnInQueries( + column: string, + options: SearchParams, + callback: (filter: T) => T +) { + for (let filterBlock of Object.values(options.query)) { + if (typeof filterBlock !== "object") { + continue + } + for (let [key, filter] of Object.entries(filterBlock)) { + if (key.endsWith(column)) { + filterBlock[key] = callback(filter) + } + } + } +} + +function userColumnMapping(column: string, options: SearchParams) { + findColumnInQueries(column, options, (filterValue: any): string => { + if (typeof filterValue !== "string") { + return filterValue + } + const rowPrefix = DocumentType.ROW + SEPARATOR + // TODO: at some point in future might want to handle mapping emails to IDs + if (filterValue.startsWith(rowPrefix)) { + return dbCore.getGlobalIDFromUserMetadataID(filterValue) + } + return filterValue + }) +} + +export function searchInputMapping(table: Table, options: SearchParams) { + for (let [key, column] of Object.entries(table.schema)) { + switch (column.type) { + case FieldType.BB_REFERENCE: + if (column.subtype === FieldTypeSubtypes.BB_REFERENCE.USER) { + userColumnMapping(key, options) + } + break + } + } + return options +} diff --git a/packages/shared-core/src/filters.ts b/packages/shared-core/src/filters.ts index 6ab8ce623e..e443f35dbe 100644 --- a/packages/shared-core/src/filters.ts +++ b/packages/shared-core/src/filters.ts @@ -14,7 +14,6 @@ const HBS_REGEX = /{{([^{].*?)}}/g /** * Returns the valid operator options for a certain data type - * @param type the data type */ export const getValidOperatorsForType = ( type: FieldType, From dc50515bcc16ed0935fd8bd4a1c04feb729758d9 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Fri, 6 Oct 2023 12:16:37 +0100 Subject: [PATCH 02/20] Adding negative test case and fixing build issue. --- packages/server/src/sdk/app/rows/search/tests/utils.spec.ts | 5 ++++- packages/server/src/sdk/app/rows/search/utils.ts | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/server/src/sdk/app/rows/search/tests/utils.spec.ts b/packages/server/src/sdk/app/rows/search/tests/utils.spec.ts index 01db0d421b..a1cb4fe48d 100644 --- a/packages/server/src/sdk/app/rows/search/tests/utils.spec.ts +++ b/packages/server/src/sdk/app/rows/search/tests/utils.spec.ts @@ -37,13 +37,16 @@ describe("searchInputMapping", () => { }) it("shouldn't change any other input", () => { + const email = "test@test.com" const params: SearchParams = { tableId, query: { equal: { - "1:user": "test@test.com", + "1:user": email, }, }, } + const output = searchInputMapping(tableWithUserCol, params) + expect(output.query.equal!["1:user"]).toBe(email) }) }) diff --git a/packages/server/src/sdk/app/rows/search/utils.ts b/packages/server/src/sdk/app/rows/search/utils.ts index c86df9bc0d..5afa13c53d 100644 --- a/packages/server/src/sdk/app/rows/search/utils.ts +++ b/packages/server/src/sdk/app/rows/search/utils.ts @@ -11,7 +11,7 @@ import { db as dbCore } from "@budibase/backend-core" function findColumnInQueries( column: string, options: SearchParams, - callback: (filter: T) => T + callback: (filter: any) => any ) { for (let filterBlock of Object.values(options.query)) { if (typeof filterBlock !== "object") { From 6e6c5bc776f0352ab5e81939ba57be64228dd6ae Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Fri, 6 Oct 2023 12:31:52 +0100 Subject: [PATCH 03/20] Handle arrays and fix issue brought up by REST testcase. --- .../sdk/app/rows/search/tests/utils.spec.ts | 29 ++++++++++++++++-- .../server/src/sdk/app/rows/search/utils.ts | 30 +++++++++++++++---- 2 files changed, 51 insertions(+), 8 deletions(-) diff --git a/packages/server/src/sdk/app/rows/search/tests/utils.spec.ts b/packages/server/src/sdk/app/rows/search/tests/utils.spec.ts index a1cb4fe48d..08d1f1b1cb 100644 --- a/packages/server/src/sdk/app/rows/search/tests/utils.spec.ts +++ b/packages/server/src/sdk/app/rows/search/tests/utils.spec.ts @@ -21,9 +21,10 @@ const tableWithUserCol: Table = { } describe("searchInputMapping", () => { + const globalUserId = dbCore.generateGlobalUserID() + const userMedataId = dbCore.generateUserMetadataID(globalUserId) + it("should be able to map ro_ to global user IDs", () => { - const globalUserId = dbCore.generateGlobalUserID() - const userMedataId = dbCore.generateUserMetadataID(globalUserId) const params: SearchParams = { tableId, query: { @@ -36,6 +37,22 @@ describe("searchInputMapping", () => { expect(output.query.equal!["1:user"]).toBe(globalUserId) }) + it("should handle array of user IDs", () => { + const params: SearchParams = { + tableId, + query: { + oneOf: { + "1:user": [userMedataId, globalUserId], + }, + }, + } + const output = searchInputMapping(tableWithUserCol, params) + expect(output.query.oneOf!["1:user"]).toStrictEqual([ + globalUserId, + globalUserId, + ]) + }) + it("shouldn't change any other input", () => { const email = "test@test.com" const params: SearchParams = { @@ -49,4 +66,12 @@ describe("searchInputMapping", () => { const output = searchInputMapping(tableWithUserCol, params) expect(output.query.equal!["1:user"]).toBe(email) }) + + it("shouldn't error if no query supplied", () => { + const params: any = { + tableId, + } + const output = searchInputMapping(tableWithUserCol, params) + expect(output.query).toBeUndefined() + }) }) diff --git a/packages/server/src/sdk/app/rows/search/utils.ts b/packages/server/src/sdk/app/rows/search/utils.ts index 5afa13c53d..f475296333 100644 --- a/packages/server/src/sdk/app/rows/search/utils.ts +++ b/packages/server/src/sdk/app/rows/search/utils.ts @@ -13,6 +13,9 @@ function findColumnInQueries( options: SearchParams, callback: (filter: any) => any ) { + if (!options.query) { + return + } for (let filterBlock of Object.values(options.query)) { if (typeof filterBlock !== "object") { continue @@ -27,15 +30,30 @@ function findColumnInQueries( function userColumnMapping(column: string, options: SearchParams) { findColumnInQueries(column, options, (filterValue: any): string => { - if (typeof filterValue !== "string") { + const isArray = Array.isArray(filterValue), + isString = typeof filterValue === "string" + if (!isString && !isArray) { return filterValue } - const rowPrefix = DocumentType.ROW + SEPARATOR - // TODO: at some point in future might want to handle mapping emails to IDs - if (filterValue.startsWith(rowPrefix)) { - return dbCore.getGlobalIDFromUserMetadataID(filterValue) + const processString = (input: string) => { + const rowPrefix = DocumentType.ROW + SEPARATOR + if (input.startsWith(rowPrefix)) { + return dbCore.getGlobalIDFromUserMetadataID(input) + } else { + return input + } + } + if (isArray) { + return filterValue.map(el => { + if (typeof el === "string") { + return processString(el) + } else { + return el + } + }) + } else { + return processString(filterValue) } - return filterValue }) } From 18cca671d49fcff4f84afe8b8d77c80e1178b7d5 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Fri, 6 Oct 2023 12:56:07 +0100 Subject: [PATCH 04/20] PR comments. --- .../design/settings/controls/FilterEditor/FilterDrawer.svelte | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/builder/src/components/design/settings/controls/FilterEditor/FilterDrawer.svelte b/packages/builder/src/components/design/settings/controls/FilterEditor/FilterDrawer.svelte index c03085e66f..0fd30b82bb 100644 --- a/packages/builder/src/components/design/settings/controls/FilterEditor/FilterDrawer.svelte +++ b/packages/builder/src/components/design/settings/controls/FilterEditor/FilterDrawer.svelte @@ -191,7 +191,7 @@ } const getValidOperatorsForType = filter => { - if (!filter.field) { + if (!filter?.field) { return [] } From 017b522a3f6ac014c9188498dfcbcb8f9e0537b9 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Fri, 6 Oct 2023 12:56:55 +0100 Subject: [PATCH 05/20] Comment to explain function. --- packages/server/src/sdk/app/rows/search/utils.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/server/src/sdk/app/rows/search/utils.ts b/packages/server/src/sdk/app/rows/search/utils.ts index f475296333..27964d2ad2 100644 --- a/packages/server/src/sdk/app/rows/search/utils.ts +++ b/packages/server/src/sdk/app/rows/search/utils.ts @@ -57,6 +57,8 @@ function userColumnMapping(column: string, options: SearchParams) { }) } +// maps through the search parameters to check if any of the inputs are invalid +// based on the table schema, converts them to something that is valid. export function searchInputMapping(table: Table, options: SearchParams) { for (let [key, column] of Object.entries(table.schema)) { switch (column.type) { From 7acc164e12a98c29d46df6d40126c33bdd7272e3 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Fri, 6 Oct 2023 13:28:27 +0100 Subject: [PATCH 06/20] Fix build. --- packages/server/src/sdk/app/rows/search/utils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/server/src/sdk/app/rows/search/utils.ts b/packages/server/src/sdk/app/rows/search/utils.ts index 27964d2ad2..1b4f60f7da 100644 --- a/packages/server/src/sdk/app/rows/search/utils.ts +++ b/packages/server/src/sdk/app/rows/search/utils.ts @@ -29,7 +29,7 @@ function findColumnInQueries( } function userColumnMapping(column: string, options: SearchParams) { - findColumnInQueries(column, options, (filterValue: any): string => { + findColumnInQueries(column, options, (filterValue: any): any => { const isArray = Array.isArray(filterValue), isString = typeof filterValue === "string" if (!isString && !isArray) { From bc17bc43fa7fb8716a8c7ee936dd6bfb2f42847d Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Fri, 6 Oct 2023 13:32:12 +0100 Subject: [PATCH 07/20] Fixing issue brought up by some unit tests. --- packages/server/src/sdk/app/rows/search/utils.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/server/src/sdk/app/rows/search/utils.ts b/packages/server/src/sdk/app/rows/search/utils.ts index 1b4f60f7da..14f7907e4f 100644 --- a/packages/server/src/sdk/app/rows/search/utils.ts +++ b/packages/server/src/sdk/app/rows/search/utils.ts @@ -60,6 +60,9 @@ function userColumnMapping(column: string, options: SearchParams) { // maps through the search parameters to check if any of the inputs are invalid // based on the table schema, converts them to something that is valid. export function searchInputMapping(table: Table, options: SearchParams) { + if (!table?.schema) { + return options + } for (let [key, column] of Object.entries(table.schema)) { switch (column.type) { case FieldType.BB_REFERENCE: From 575693d69a1f3f404bafa991b5e5bd194037818d Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Fri, 6 Oct 2023 14:07:12 +0100 Subject: [PATCH 08/20] Updating pro. --- packages/pro | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/pro b/packages/pro index 7040ae5282..044bec6447 160000 --- a/packages/pro +++ b/packages/pro @@ -1 +1 @@ -Subproject commit 7040ae5282cc23d7ae56ac1be8a369d1c32aab2f +Subproject commit 044bec6447066b215932d6726c437e7ec5a9e42e From 23b7a8de72b7637520359eaa8494a727078549f1 Mon Sep 17 00:00:00 2001 From: melohagan <101575380+melohagan@users.noreply.github.com> Date: Fri, 6 Oct 2023 14:17:36 +0100 Subject: [PATCH 09/20] Allow relationship to be deleted even if missing (#11991) * Allow relationship to be deleted even if missing * Comment --- .../server/src/db/linkedRows/LinkController.ts | 17 ++++++++++++----- .../server/src/db/tests/linkController.spec.js | 15 +++++++++++++++ 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/packages/server/src/db/linkedRows/LinkController.ts b/packages/server/src/db/linkedRows/LinkController.ts index 5bfae49e8b..457819251a 100644 --- a/packages/server/src/db/linkedRows/LinkController.ts +++ b/packages/server/src/db/linkedRows/LinkController.ts @@ -308,12 +308,19 @@ class LinkController { } }) ) - // remove schema from other table - let linkedTable = await this._db.get(field.tableId) - if (field.fieldName) { - delete linkedTable.schema[field.fieldName] + try { + // remove schema from other table, if it exists + let linkedTable = await this._db.get
(field.tableId) + if (field.fieldName) { + delete linkedTable.schema[field.fieldName] + } + await this._db.put(linkedTable) + } catch (error: any) { + // ignore missing to ensure broken relationship columns can be deleted + if (error.statusCode !== 404) { + throw error + } } - await this._db.put(linkedTable) } /** diff --git a/packages/server/src/db/tests/linkController.spec.js b/packages/server/src/db/tests/linkController.spec.js index 59d0f3f983..5caf35f61a 100644 --- a/packages/server/src/db/tests/linkController.spec.js +++ b/packages/server/src/db/tests/linkController.spec.js @@ -233,4 +233,19 @@ describe("test the link controller", () => { } await config.updateTable(table) }) + + it("should be able to remove a linked field from a table, even if the linked table does not exist", async () => { + await createLinkedRow() + await createLinkedRow("link2") + table1.schema["link"].tableId = "not_found" + const controller = await createLinkController(table1, null, table1) + await context.doInAppContext(appId, async () => { + let before = await controller.getTableLinkDocs() + await controller.removeFieldFromTable("link") + let after = await controller.getTableLinkDocs() + expect(before.length).toEqual(2) + // shouldn't delete the other field + expect(after.length).toEqual(1) + }) + }) }) From 9b52ae56282adcf1651fae4b693b679f5d6701fa Mon Sep 17 00:00:00 2001 From: Budibase Staging Release Bot <> Date: Fri, 6 Oct 2023 13:17:58 +0000 Subject: [PATCH 10/20] Bump version to 2.11.13 --- lerna.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lerna.json b/lerna.json index 6270454faa..f42284a20d 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "2.11.12", + "version": "2.11.13", "npmClient": "yarn", "packages": [ "packages/*" From 24b6d5d9ba319bceed541e01f760b5a7b0597152 Mon Sep 17 00:00:00 2001 From: Budibase Staging Release Bot <> Date: Fri, 6 Oct 2023 13:44:25 +0000 Subject: [PATCH 11/20] Bump version to 2.11.14 --- lerna.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lerna.json b/lerna.json index f42284a20d..6c50c0bc16 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "2.11.13", + "version": "2.11.14", "npmClient": "yarn", "packages": [ "packages/*" From d4335bca73b29ab0742b7c6aadd8a6c72de08482 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Fri, 6 Oct 2023 16:31:48 +0100 Subject: [PATCH 12/20] Quick fix for saving current user._id - make sure it is the correct format of ID. --- .../rowProcessor/bbReferenceProcessor.ts | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/packages/server/src/utilities/rowProcessor/bbReferenceProcessor.ts b/packages/server/src/utilities/rowProcessor/bbReferenceProcessor.ts index 6f41d3d55f..5b7e852f50 100644 --- a/packages/server/src/utilities/rowProcessor/bbReferenceProcessor.ts +++ b/packages/server/src/utilities/rowProcessor/bbReferenceProcessor.ts @@ -1,13 +1,15 @@ -import { cache } from "@budibase/backend-core" +import { cache, db as dbCore } from "@budibase/backend-core" import { utils } from "@budibase/shared-core" -import { FieldSubtype } from "@budibase/types" +import { FieldSubtype, DocumentType, SEPARATOR } from "@budibase/types" import { InvalidBBRefError } from "./errors" +const ROW_PREFIX = DocumentType.ROW + SEPARATOR + export async function processInputBBReferences( value: string | string[] | { _id: string } | { _id: string }[], subtype: FieldSubtype ): Promise { - const referenceIds: string[] = [] + let referenceIds: string[] = [] if (Array.isArray(value)) { referenceIds.push( @@ -26,6 +28,17 @@ export async function processInputBBReferences( ) } + // make sure all reference IDs are correct global user IDs + // they may be user metadata references (start with row prefix) + // and these need to be converted to global IDs + referenceIds = referenceIds.map(id => { + if (id?.startsWith(ROW_PREFIX)) { + return dbCore.getGlobalIDFromUserMetadataID(id) + } else { + return id + } + }) + switch (subtype) { case FieldSubtype.USER: const { notFoundIds } = await cache.user.getUsers(referenceIds) From 0dc28122fa5ffd04747aa7896b20f4b351bfa13c Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Fri, 6 Oct 2023 16:38:36 +0100 Subject: [PATCH 13/20] Adding test case. --- .../rowProcessor/tests/bbReferenceProcessor.spec.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/packages/server/src/utilities/rowProcessor/tests/bbReferenceProcessor.spec.ts b/packages/server/src/utilities/rowProcessor/tests/bbReferenceProcessor.spec.ts index d0932b399c..b6174861d4 100644 --- a/packages/server/src/utilities/rowProcessor/tests/bbReferenceProcessor.spec.ts +++ b/packages/server/src/utilities/rowProcessor/tests/bbReferenceProcessor.spec.ts @@ -154,6 +154,15 @@ describe("bbReferenceProcessor", () => { expect(result).toEqual(null) }) + + it("should convert user medata IDs to global IDs", async () => { + const userId = _.sample(users)!._id! + const userMetadataId = backendCore.db.generateUserMetadataID(userId) + const result = await config.doInTenant(() => + processInputBBReferences(userMetadataId, FieldSubtype.USER) + ) + expect(result).toBe(userId) + }) }) }) From d41f81bb45c52a59f35b8de3a311874e9a6f41dd Mon Sep 17 00:00:00 2001 From: Budibase Staging Release Bot <> Date: Fri, 6 Oct 2023 15:54:26 +0000 Subject: [PATCH 14/20] Bump version to 2.11.15 --- lerna.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lerna.json b/lerna.json index 6c50c0bc16..7968b8999f 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "2.11.14", + "version": "2.11.15", "npmClient": "yarn", "packages": [ "packages/*" From d8f1b7960e7e077c3f78b846743f2226a8425a91 Mon Sep 17 00:00:00 2001 From: melohagan <101575380+melohagan@users.noreply.github.com> Date: Mon, 9 Oct 2023 08:22:19 +0100 Subject: [PATCH 15/20] Fix form block crash on no data tables (#11995) * Fix form block crash on no data tables * Refactor * Refactor --- packages/builder/src/builderStore/dataBinding.js | 7 +++++-- .../controls/FieldConfiguration/FieldConfiguration.svelte | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/packages/builder/src/builderStore/dataBinding.js b/packages/builder/src/builderStore/dataBinding.js index 386b47105d..8445bf9e6d 100644 --- a/packages/builder/src/builderStore/dataBinding.js +++ b/packages/builder/src/builderStore/dataBinding.js @@ -948,12 +948,15 @@ export const buildFormSchema = (component, asset) => { if (component._component.endsWith("formblock")) { let schema = {} - const datasource = getDatasourceForProvider(asset, component) const info = getSchemaForDatasource(component, datasource) + if (!info?.schema) { + return schema + } + if (!component.fields) { - Object.values(info?.schema) + Object.values(info.schema) .filter( ({ autocolumn, name }) => !autocolumn && !["_rev", "_id"].includes(name) diff --git a/packages/builder/src/components/design/settings/controls/FieldConfiguration/FieldConfiguration.svelte b/packages/builder/src/components/design/settings/controls/FieldConfiguration/FieldConfiguration.svelte index 4c4fa0b7b7..4169cb7d3d 100644 --- a/packages/builder/src/components/design/settings/controls/FieldConfiguration/FieldConfiguration.svelte +++ b/packages/builder/src/components/design/settings/controls/FieldConfiguration/FieldConfiguration.svelte @@ -37,7 +37,7 @@ } $: datasource = getDatasourceForProvider($currentAsset, componentInstance) - $: resourceId = datasource.resourceId || datasource.tableId + $: resourceId = datasource?.resourceId || datasource?.tableId $: if (!isEqual(value, cachedValue)) { cachedValue = cloneDeep(value) From 247d96b641f4d10f636ece20accccd161280cb04 Mon Sep 17 00:00:00 2001 From: Budibase Staging Release Bot <> Date: Mon, 9 Oct 2023 07:22:41 +0000 Subject: [PATCH 16/20] Bump version to 2.11.16 --- lerna.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lerna.json b/lerna.json index 7968b8999f..d7478a01e7 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "2.11.15", + "version": "2.11.16", "npmClient": "yarn", "packages": [ "packages/*" From a4e3cd72cc45bce271893ee676c73351a02da775 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Mon, 9 Oct 2023 15:01:16 +0100 Subject: [PATCH 17/20] Add new app feature flag to allow disable user metadata columns in new apps, but allow them in old apps --- .../src/builderStore/store/frontend.js | 1 + .../backend/DataTable/TableDataTable.svelte | 24 ++++++++++--------- .../server/src/api/controllers/application.ts | 1 + packages/types/src/documents/app/app.ts | 1 + 4 files changed, 16 insertions(+), 11 deletions(-) diff --git a/packages/builder/src/builderStore/store/frontend.js b/packages/builder/src/builderStore/store/frontend.js index 6c029ddff3..a567caf87f 100644 --- a/packages/builder/src/builderStore/store/frontend.js +++ b/packages/builder/src/builderStore/store/frontend.js @@ -64,6 +64,7 @@ const INITIAL_FRONTEND_STATE = { }, features: { componentValidation: false, + disableUserMetadata: false, }, errors: [], hasAppPackage: false, diff --git a/packages/builder/src/components/backend/DataTable/TableDataTable.svelte b/packages/builder/src/components/backend/DataTable/TableDataTable.svelte index 2b7cde9201..c3b1fea51d 100644 --- a/packages/builder/src/components/backend/DataTable/TableDataTable.svelte +++ b/packages/builder/src/components/backend/DataTable/TableDataTable.svelte @@ -4,6 +4,7 @@ import { TableNames } from "constants" import { Grid } from "@budibase/frontend-core" import { API } from "api" + import { store } from "builderStore" import GridAddColumnModal from "components/backend/DataTable/modals/grid/GridCreateColumnModal.svelte" import GridCreateEditRowModal from "components/backend/DataTable/modals/grid/GridCreateEditRowModal.svelte" import GridEditUserModal from "components/backend/DataTable/modals/grid/GridEditUserModal.svelte" @@ -17,11 +18,11 @@ import GridUsersTableButton from "components/backend/DataTable/modals/grid/GridUsersTableButton.svelte" const userSchemaOverrides = { - firstName: { displayName: "First name" }, - lastName: { displayName: "Last name" }, - email: { displayName: "Email" }, - roleId: { displayName: "Role" }, - status: { displayName: "Status" }, + firstName: { displayName: "First name", disabled: true }, + lastName: { displayName: "Last name", disabled: true }, + email: { displayName: "Email", disabled: true }, + roleId: { displayName: "Role", disabled: true }, + status: { displayName: "Status", disabled: true }, } $: id = $tables.selected?._id @@ -35,6 +36,7 @@ return datasource._id === $tables.selected?.sourceId }) $: relationshipsEnabled = relationshipSupport(tableDatasource) + $: editable = !(isUsersTable && $store.features.disableUserMetadata) const relationshipSupport = datasource => { const integration = $integrations[datasource?.source] @@ -58,22 +60,22 @@ - {#if isUsersTable} + {#if !editable} {/if} - {#if !isUsersTable} + {#if editable} {/if} diff --git a/packages/server/src/api/controllers/application.ts b/packages/server/src/api/controllers/application.ts index 11f6e6c249..3797d1e966 100644 --- a/packages/server/src/api/controllers/application.ts +++ b/packages/server/src/api/controllers/application.ts @@ -289,6 +289,7 @@ async function performAppCreate(ctx: UserCtx) { }, features: { componentValidation: true, + disableUserMetadata: true, }, } diff --git a/packages/types/src/documents/app/app.ts b/packages/types/src/documents/app/app.ts index f42422b557..5bbdd86515 100644 --- a/packages/types/src/documents/app/app.ts +++ b/packages/types/src/documents/app/app.ts @@ -66,4 +66,5 @@ export interface AppIcon { export interface AppFeatures { componentValidation?: boolean + disableUserMetadata?: boolean } From 73e208292f048f6d88814907cc7b14ad429db8b7 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Mon, 9 Oct 2023 15:05:57 +0100 Subject: [PATCH 18/20] Simplify logic to be more readable --- .../backend/DataTable/TableDataTable.svelte | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/packages/builder/src/components/backend/DataTable/TableDataTable.svelte b/packages/builder/src/components/backend/DataTable/TableDataTable.svelte index c3b1fea51d..5fee849afb 100644 --- a/packages/builder/src/components/backend/DataTable/TableDataTable.svelte +++ b/packages/builder/src/components/backend/DataTable/TableDataTable.svelte @@ -36,7 +36,6 @@ return datasource._id === $tables.selected?.sourceId }) $: relationshipsEnabled = relationshipSupport(tableDatasource) - $: editable = !(isUsersTable && $store.features.disableUserMetadata) const relationshipSupport = datasource => { const integration = $integrations[datasource?.source] @@ -60,22 +59,22 @@ - {#if !editable} + {#if isUsersTable && $store.features.disableUserMetadata} {/if} - {#if editable} + {#if !isUsersTable} {/if} From b17ec630c1e85519a6fce46d575d66f9237ce685 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Mon, 9 Oct 2023 15:09:11 +0100 Subject: [PATCH 19/20] Ensure user table editing is still allowed for old apps that are imported --- packages/server/src/api/controllers/application.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/server/src/api/controllers/application.ts b/packages/server/src/api/controllers/application.ts index 3797d1e966..4afd7b23f9 100644 --- a/packages/server/src/api/controllers/application.ts +++ b/packages/server/src/api/controllers/application.ts @@ -311,10 +311,13 @@ async function performAppCreate(ctx: UserCtx) { } }) - // Keep existing validation setting + // Keep existing feature flags if (!existing.features?.componentValidation) { newApplication.features!.componentValidation = false } + if (!existing.features?.disableUserMetadata) { + newApplication.features!.disableUserMetadata = false + } // Migrate navigation settings and screens if required if (existing) { From 088ed1139c2214a1bee9a81282e2c3501f6185db Mon Sep 17 00:00:00 2001 From: Budibase Staging Release Bot <> Date: Tue, 10 Oct 2023 07:08:08 +0000 Subject: [PATCH 20/20] Bump version to 2.11.17 --- lerna.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lerna.json b/lerna.json index d7478a01e7..c1de6a01b5 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "2.11.16", + "version": "2.11.17", "npmClient": "yarn", "packages": [ "packages/*"