Merge branch 'master' of github.com:budibase/budibase into sqs-auto-tests
This commit is contained in:
commit
951b7d3e59
|
@ -92,8 +92,6 @@ jobs:
|
|||
|
||||
test-libraries:
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
REUSE_CONTAINERS: true
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v4
|
||||
|
@ -150,8 +148,6 @@ jobs:
|
|||
|
||||
test-server:
|
||||
runs-on: budi-tubby-tornado-quad-core-150gb
|
||||
env:
|
||||
REUSE_CONTAINERS: true
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v4
|
||||
|
|
|
@ -1,16 +1,49 @@
|
|||
import { GenericContainer, Wait } from "testcontainers"
|
||||
import {
|
||||
GenericContainer,
|
||||
Wait,
|
||||
getContainerRuntimeClient,
|
||||
} from "testcontainers"
|
||||
import { ContainerInfo } from "dockerode"
|
||||
import path from "path"
|
||||
import lockfile from "proper-lockfile"
|
||||
|
||||
async function getBudibaseContainers() {
|
||||
const client = await getContainerRuntimeClient()
|
||||
const conatiners = await client.container.list()
|
||||
return conatiners.filter(
|
||||
container =>
|
||||
container.Labels["com.budibase"] === "true" &&
|
||||
container.Labels["org.testcontainers"] === "true"
|
||||
)
|
||||
}
|
||||
|
||||
async function killContainers(containers: ContainerInfo[]) {
|
||||
const client = await getContainerRuntimeClient()
|
||||
for (const container of containers) {
|
||||
const c = client.container.getById(container.Id)
|
||||
await c.kill()
|
||||
await c.remove()
|
||||
}
|
||||
}
|
||||
|
||||
export default async function setup() {
|
||||
const lockPath = path.resolve(__dirname, "globalSetup.ts")
|
||||
if (process.env.REUSE_CONTAINERS) {
|
||||
// If you run multiple tests at the same time, it's possible for the CouchDB
|
||||
// shared container to get started multiple times despite having an
|
||||
// identical reuse hash. To avoid that, we do a filesystem-based lock so
|
||||
// that only one globalSetup.ts is running at a time.
|
||||
lockfile.lockSync(lockPath)
|
||||
}
|
||||
// If you run multiple tests at the same time, it's possible for the CouchDB
|
||||
// shared container to get started multiple times despite having an
|
||||
// identical reuse hash. To avoid that, we do a filesystem-based lock so
|
||||
// that only one globalSetup.ts is running at a time.
|
||||
lockfile.lockSync(lockPath)
|
||||
|
||||
// Remove any containers that are older than 24 hours. This is to prevent
|
||||
// containers getting full volumes or accruing any other problems from being
|
||||
// left up for very long periods of time.
|
||||
const threshold = new Date(Date.now() - 1000 * 60 * 60 * 24)
|
||||
const containers = (await getBudibaseContainers()).filter(container => {
|
||||
const created = new Date(container.Created * 1000)
|
||||
return created < threshold
|
||||
})
|
||||
|
||||
await killContainers(containers)
|
||||
|
||||
try {
|
||||
let couchdb = new GenericContainer("budibase/couchdb:v3.2.1-sqs")
|
||||
|
@ -28,20 +61,16 @@ export default async function setup() {
|
|||
target: "/opt/couchdb/etc/local.d/test-couchdb.ini",
|
||||
},
|
||||
])
|
||||
.withLabels({ "com.budibase": "true" })
|
||||
.withReuse()
|
||||
.withWaitStrategy(
|
||||
Wait.forSuccessfulCommand(
|
||||
"curl http://budibase:budibase@localhost:5984/_up"
|
||||
).withStartupTimeout(20000)
|
||||
)
|
||||
|
||||
if (process.env.REUSE_CONTAINERS) {
|
||||
couchdb = couchdb.withReuse()
|
||||
}
|
||||
|
||||
await couchdb.start()
|
||||
} finally {
|
||||
if (process.env.REUSE_CONTAINERS) {
|
||||
lockfile.unlockSync(lockPath)
|
||||
}
|
||||
lockfile.unlockSync(lockPath)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -59,7 +59,8 @@
|
|||
"dev:all": "yarn run kill-all && lerna run --stream dev",
|
||||
"dev:built": "yarn run kill-all && cd packages/server && yarn dev:stack:up && cd ../../ && lerna run --stream dev:built",
|
||||
"dev:docker": "./scripts/devDocker.sh",
|
||||
"test": "REUSE_CONTAINERS=1 lerna run --concurrency 1 --stream test --stream",
|
||||
"test": "lerna run --concurrency 1 --stream test --stream",
|
||||
"test:containers:kill": "./scripts/killTestcontainers.sh",
|
||||
"lint:eslint": "eslint packages --max-warnings=0",
|
||||
"lint:prettier": "prettier --check \"packages/**/*.{js,ts,svelte}\" && prettier --write \"examples/**/*.{js,ts,svelte}\"",
|
||||
"lint": "yarn run lint:eslint && yarn run lint:prettier",
|
||||
|
|
|
@ -28,7 +28,11 @@ function getTestcontainers(): ContainerInfo[] {
|
|||
.split("\n")
|
||||
.filter(x => x.length > 0)
|
||||
.map(x => JSON.parse(x) as ContainerInfo)
|
||||
.filter(x => x.Labels.includes("org.testcontainers=true"))
|
||||
.filter(
|
||||
x =>
|
||||
x.Labels.includes("org.testcontainers=true") &&
|
||||
x.Labels.includes("com.budibase=true")
|
||||
)
|
||||
}
|
||||
|
||||
export function getContainerByImage(image: string) {
|
||||
|
|
|
@ -29,7 +29,11 @@
|
|||
import ModalBindableInput from "components/common/bindings/ModalBindableInput.svelte"
|
||||
import { getBindings } from "components/backend/DataTable/formula"
|
||||
import JSONSchemaModal from "./JSONSchemaModal.svelte"
|
||||
import { FieldType, FieldSubtype, SourceName } from "@budibase/types"
|
||||
import {
|
||||
FieldType,
|
||||
BBReferenceFieldSubType,
|
||||
SourceName,
|
||||
} from "@budibase/types"
|
||||
import RelationshipSelector from "components/common/RelationshipSelector.svelte"
|
||||
import { RowUtils } from "@budibase/frontend-core"
|
||||
import ServerBindingPanel from "components/common/bindings/ServerBindingPanel.svelte"
|
||||
|
@ -41,8 +45,6 @@
|
|||
const NUMBER_TYPE = FieldType.NUMBER
|
||||
const JSON_TYPE = FieldType.JSON
|
||||
const DATE_TYPE = FieldType.DATETIME
|
||||
const USER_TYPE = FieldSubtype.USER
|
||||
const USERS_TYPE = FieldSubtype.USERS
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
const PROHIBITED_COLUMN_NAMES = ["type", "_id", "_rev", "tableId"]
|
||||
|
@ -263,9 +265,9 @@
|
|||
delete saveColumn.fieldName
|
||||
}
|
||||
if (isUsersColumn(saveColumn)) {
|
||||
if (saveColumn.subtype === USER_TYPE) {
|
||||
if (saveColumn.subtype === BBReferenceFieldSubType.USER) {
|
||||
saveColumn.relationshipType = RelationshipType.ONE_TO_MANY
|
||||
} else if (saveColumn.subtype === USERS_TYPE) {
|
||||
} else if (saveColumn.subtype === BBReferenceFieldSubType.USERS) {
|
||||
saveColumn.relationshipType = RelationshipType.MANY_TO_MANY
|
||||
}
|
||||
}
|
||||
|
@ -375,7 +377,7 @@
|
|||
|
||||
const isUsers =
|
||||
editableColumn.type === FieldType.BB_REFERENCE &&
|
||||
editableColumn.subtype === FieldSubtype.USERS
|
||||
editableColumn.subtype === BBReferenceFieldSubType.USERS
|
||||
|
||||
if (!externalTable) {
|
||||
return [
|
||||
|
@ -485,7 +487,9 @@
|
|||
function isUsersColumn(column) {
|
||||
return (
|
||||
column.type === FieldType.BB_REFERENCE &&
|
||||
[FieldSubtype.USER, FieldSubtype.USERS].includes(column.subtype)
|
||||
[BBReferenceFieldSubType.USER, BBReferenceFieldSubType.USERS].includes(
|
||||
column.subtype
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -688,12 +692,14 @@
|
|||
>
|
||||
{:else if isUsersColumn(editableColumn) && datasource?.source !== SourceName.GOOGLE_SHEETS}
|
||||
<Toggle
|
||||
value={editableColumn.subtype === FieldSubtype.USERS}
|
||||
value={editableColumn.subtype === BBReferenceFieldSubType.USERS}
|
||||
on:change={e =>
|
||||
handleTypeChange(
|
||||
makeFieldId(
|
||||
FieldType.BB_REFERENCE,
|
||||
e.detail ? FieldSubtype.USERS : FieldSubtype.USER
|
||||
e.detail
|
||||
? BBReferenceFieldSubType.USERS
|
||||
: BBReferenceFieldSubType.USER
|
||||
)
|
||||
)}
|
||||
disabled={!isCreating}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<script>
|
||||
import { FieldType, FieldSubtype } from "@budibase/types"
|
||||
import { FieldType, BBReferenceFieldSubType } from "@budibase/types"
|
||||
import { Select, Toggle, Multiselect } from "@budibase/bbui"
|
||||
import { DB_TYPE_INTERNAL } from "constants/backend"
|
||||
import { API } from "api"
|
||||
|
@ -60,11 +60,11 @@
|
|||
},
|
||||
{
|
||||
label: "User",
|
||||
value: `${FieldType.BB_REFERENCE}${FieldSubtype.USER}`,
|
||||
value: `${FieldType.BB_REFERENCE}${BBReferenceFieldSubType.USER}`,
|
||||
},
|
||||
{
|
||||
label: "Users",
|
||||
value: `${FieldType.BB_REFERENCE}${FieldSubtype.USERS}`,
|
||||
value: `${FieldType.BB_REFERENCE}${BBReferenceFieldSubType.USERS}`,
|
||||
},
|
||||
]
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import {
|
||||
FieldType,
|
||||
FieldSubtype,
|
||||
BBReferenceFieldSubType,
|
||||
INTERNAL_TABLE_SOURCE_ID,
|
||||
AutoFieldSubType,
|
||||
Hosting,
|
||||
|
@ -160,13 +160,13 @@ export const FIELDS = {
|
|||
USER: {
|
||||
name: "User",
|
||||
type: FieldType.BB_REFERENCE,
|
||||
subtype: FieldSubtype.USER,
|
||||
subtype: BBReferenceFieldSubType.USER,
|
||||
icon: TypeIconMap[FieldType.USER],
|
||||
},
|
||||
USERS: {
|
||||
name: "Users",
|
||||
type: FieldType.BB_REFERENCE,
|
||||
subtype: FieldSubtype.USERS,
|
||||
subtype: BBReferenceFieldSubType.USERS,
|
||||
icon: TypeIconMap[FieldType.USERS],
|
||||
constraints: {
|
||||
type: "array",
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<script>
|
||||
import { getContext } from "svelte"
|
||||
import RelationshipCell from "./RelationshipCell.svelte"
|
||||
import { FieldSubtype, RelationshipType } from "@budibase/types"
|
||||
import { BBReferenceFieldSubType, RelationshipType } from "@budibase/types"
|
||||
|
||||
export let api
|
||||
|
||||
|
@ -13,13 +13,16 @@
|
|||
// This is not really used, just adding some content to be able to render the relationship cell
|
||||
tableId: "external",
|
||||
relationshipType:
|
||||
subtype === FieldSubtype.USER
|
||||
subtype === BBReferenceFieldSubType.USER
|
||||
? RelationshipType.ONE_TO_MANY
|
||||
: RelationshipType.MANY_TO_MANY,
|
||||
}
|
||||
|
||||
async function searchFunction(searchParams) {
|
||||
if (subtype !== FieldSubtype.USER && subtype !== FieldSubtype.USERS) {
|
||||
if (
|
||||
subtype !== BBReferenceFieldSubType.USER &&
|
||||
subtype !== BBReferenceFieldSubType.USERS
|
||||
) {
|
||||
throw `Search for '${subtype}' not implemented`
|
||||
}
|
||||
|
||||
|
|
|
@ -7,7 +7,11 @@
|
|||
} from "@budibase/bbui"
|
||||
import { getContext } from "svelte"
|
||||
import { ValidColumnNameRegex } from "@budibase/shared-core"
|
||||
import { FieldSubtype, FieldType, RelationshipType } from "@budibase/types"
|
||||
import {
|
||||
BBReferenceFieldSubType,
|
||||
FieldType,
|
||||
RelationshipType,
|
||||
} from "@budibase/types"
|
||||
|
||||
const { API, definition, rows } = getContext("grid")
|
||||
|
||||
|
@ -29,9 +33,9 @@
|
|||
}
|
||||
|
||||
const migrateUserColumn = async () => {
|
||||
let subtype = FieldSubtype.USERS
|
||||
let subtype = BBReferenceFieldSubType.USERS
|
||||
if (column.schema.relationshipType === RelationshipType.ONE_TO_MANY) {
|
||||
subtype = FieldSubtype.USER
|
||||
subtype = BBReferenceFieldSubType.USER
|
||||
}
|
||||
|
||||
try {
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
export { OperatorOptions, SqlNumberTypeRangeMap } from "@budibase/shared-core"
|
||||
export { Feature as Features } from "@budibase/types"
|
||||
import { BpmCorrelationKey } from "@budibase/shared-core"
|
||||
import { FieldType, FieldTypeSubtypes } from "@budibase/types"
|
||||
import { FieldType, BBReferenceFieldSubType } from "@budibase/types"
|
||||
|
||||
// Cookie names
|
||||
export const Cookies = {
|
||||
|
@ -134,7 +134,7 @@ export const TypeIconMap = {
|
|||
[FieldType.USER]: "User",
|
||||
[FieldType.USERS]: "UserGroup",
|
||||
[FieldType.BB_REFERENCE]: {
|
||||
[FieldTypeSubtypes.BB_REFERENCE.USER]: "User",
|
||||
[FieldTypeSubtypes.BB_REFERENCE.USERS]: "UserGroup",
|
||||
[BBReferenceFieldSubType.USER]: "User",
|
||||
[BBReferenceFieldSubType.USERS]: "UserGroup",
|
||||
},
|
||||
}
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit dff7b5a9dd1fd770f8a48fb8e6df1740be605f18
|
||||
Subproject commit 479879246aac5dd3073cc695945c62c41fae5b0e
|
|
@ -9,7 +9,7 @@ import { mocks } from "@budibase/backend-core/tests"
|
|||
import {
|
||||
Datasource,
|
||||
FieldSchema,
|
||||
FieldSubtype,
|
||||
BBReferenceFieldSubType,
|
||||
FieldType,
|
||||
QueryPreview,
|
||||
RelationshipType,
|
||||
|
@ -337,7 +337,7 @@ describe("/datasources", () => {
|
|||
[FieldType.BB_REFERENCE]: {
|
||||
name: "bb_reference",
|
||||
type: FieldType.BB_REFERENCE,
|
||||
subtype: FieldSubtype.USERS,
|
||||
subtype: BBReferenceFieldSubType.USERS,
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ import {
|
|||
DeleteRow,
|
||||
FieldSchema,
|
||||
FieldType,
|
||||
FieldTypeSubtypes,
|
||||
BBReferenceFieldSubType,
|
||||
FormulaType,
|
||||
INTERNAL_TABLE_SOURCE_ID,
|
||||
NumberFieldMetadata,
|
||||
|
@ -1015,12 +1015,12 @@ describe.each([
|
|||
user: {
|
||||
name: "user",
|
||||
type: FieldType.BB_REFERENCE,
|
||||
subtype: FieldTypeSubtypes.BB_REFERENCE.USER,
|
||||
subtype: BBReferenceFieldSubType.USER,
|
||||
},
|
||||
users: {
|
||||
name: "users",
|
||||
type: FieldType.BB_REFERENCE,
|
||||
subtype: FieldTypeSubtypes.BB_REFERENCE.USERS,
|
||||
subtype: BBReferenceFieldSubType.USERS,
|
||||
},
|
||||
}),
|
||||
() => config.createUser(),
|
||||
|
|
|
@ -2,7 +2,7 @@ import { context, events } from "@budibase/backend-core"
|
|||
import {
|
||||
AutoFieldSubType,
|
||||
Datasource,
|
||||
FieldSubtype,
|
||||
BBReferenceFieldSubType,
|
||||
FieldType,
|
||||
INTERNAL_TABLE_SOURCE_ID,
|
||||
InternalTable,
|
||||
|
@ -497,7 +497,7 @@ describe.each([
|
|||
newColumn: {
|
||||
name: "user column",
|
||||
type: FieldType.BB_REFERENCE,
|
||||
subtype: FieldSubtype.USER,
|
||||
subtype: BBReferenceFieldSubType.USER,
|
||||
},
|
||||
})
|
||||
|
||||
|
@ -562,7 +562,7 @@ describe.each([
|
|||
newColumn: {
|
||||
name: "user column",
|
||||
type: FieldType.BB_REFERENCE,
|
||||
subtype: FieldSubtype.USERS,
|
||||
subtype: BBReferenceFieldSubType.USERS,
|
||||
},
|
||||
})
|
||||
|
||||
|
@ -614,7 +614,7 @@ describe.each([
|
|||
newColumn: {
|
||||
name: "user column",
|
||||
type: FieldType.BB_REFERENCE,
|
||||
subtype: FieldSubtype.USERS,
|
||||
subtype: BBReferenceFieldSubType.USERS,
|
||||
},
|
||||
})
|
||||
|
||||
|
@ -669,7 +669,7 @@ describe.each([
|
|||
newColumn: {
|
||||
name: "user column",
|
||||
type: FieldType.BB_REFERENCE,
|
||||
subtype: FieldSubtype.USERS,
|
||||
subtype: BBReferenceFieldSubType.USERS,
|
||||
},
|
||||
})
|
||||
|
||||
|
@ -728,7 +728,7 @@ describe.each([
|
|||
newColumn: {
|
||||
name: "",
|
||||
type: FieldType.BB_REFERENCE,
|
||||
subtype: FieldSubtype.USERS,
|
||||
subtype: BBReferenceFieldSubType.USERS,
|
||||
},
|
||||
},
|
||||
{ status: 400 }
|
||||
|
@ -743,7 +743,7 @@ describe.each([
|
|||
newColumn: {
|
||||
name: "_id",
|
||||
type: FieldType.BB_REFERENCE,
|
||||
subtype: FieldSubtype.USERS,
|
||||
subtype: BBReferenceFieldSubType.USERS,
|
||||
},
|
||||
},
|
||||
{ status: 400 }
|
||||
|
@ -758,7 +758,7 @@ describe.each([
|
|||
newColumn: {
|
||||
name: "num",
|
||||
type: FieldType.BB_REFERENCE,
|
||||
subtype: FieldSubtype.USERS,
|
||||
subtype: BBReferenceFieldSubType.USERS,
|
||||
},
|
||||
},
|
||||
{ status: 400 }
|
||||
|
@ -772,12 +772,12 @@ describe.each([
|
|||
oldColumn: {
|
||||
name: "not a column",
|
||||
type: FieldType.BB_REFERENCE,
|
||||
subtype: FieldSubtype.USERS,
|
||||
subtype: BBReferenceFieldSubType.USERS,
|
||||
},
|
||||
newColumn: {
|
||||
name: "new column",
|
||||
type: FieldType.BB_REFERENCE,
|
||||
subtype: FieldSubtype.USERS,
|
||||
subtype: BBReferenceFieldSubType.USERS,
|
||||
},
|
||||
},
|
||||
{ status: 400 }
|
||||
|
|
|
@ -12,7 +12,7 @@ import SqlTableQueryBuilder from "./sqlTable"
|
|||
import {
|
||||
BBReferenceFieldMetadata,
|
||||
FieldSchema,
|
||||
FieldSubtype,
|
||||
BBReferenceFieldSubType,
|
||||
FieldType,
|
||||
JsonFieldMetadata,
|
||||
Operation,
|
||||
|
@ -767,7 +767,7 @@ class SqlQueryBuilder extends SqlTableQueryBuilder {
|
|||
return (
|
||||
field.type === FieldType.JSON ||
|
||||
(field.type === FieldType.BB_REFERENCE &&
|
||||
field.subtype === FieldSubtype.USERS)
|
||||
field.subtype === BBReferenceFieldSubType.USERS)
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { Knex, knex } from "knex"
|
||||
import {
|
||||
FieldSubtype,
|
||||
BBReferenceFieldSubType,
|
||||
FieldType,
|
||||
NumberFieldMetadata,
|
||||
Operation,
|
||||
|
@ -64,10 +64,10 @@ function generateSchema(
|
|||
case FieldType.BB_REFERENCE: {
|
||||
const subtype = column.subtype
|
||||
switch (subtype) {
|
||||
case FieldSubtype.USER:
|
||||
case BBReferenceFieldSubType.USER:
|
||||
schema.text(key)
|
||||
break
|
||||
case FieldSubtype.USERS:
|
||||
case BBReferenceFieldSubType.USERS:
|
||||
schema.json(key)
|
||||
break
|
||||
default:
|
||||
|
|
|
@ -65,9 +65,7 @@ export async function rawQuery(ds: Datasource, sql: string): Promise<any> {
|
|||
}
|
||||
|
||||
export async function startContainer(container: GenericContainer) {
|
||||
if (process.env.REUSE_CONTAINERS) {
|
||||
container = container.withReuse()
|
||||
}
|
||||
container = container.withReuse().withLabels({ "com.budibase": "true" })
|
||||
|
||||
const startedContainer = await container.start()
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ import { searchInputMapping } from "../utils"
|
|||
import { db as dbCore } from "@budibase/backend-core"
|
||||
import {
|
||||
FieldType,
|
||||
FieldTypeSubtypes,
|
||||
BBReferenceFieldSubType,
|
||||
INTERNAL_TABLE_SOURCE_ID,
|
||||
RowSearchParams,
|
||||
Table,
|
||||
|
@ -20,7 +20,7 @@ const tableWithUserCol: Table = {
|
|||
user: {
|
||||
name: "user",
|
||||
type: FieldType.BB_REFERENCE,
|
||||
subtype: FieldTypeSubtypes.BB_REFERENCE.USER,
|
||||
subtype: BBReferenceFieldSubType.USER,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -35,7 +35,7 @@ const tableWithUsersCol: Table = {
|
|||
user: {
|
||||
name: "user",
|
||||
type: FieldType.BB_REFERENCE,
|
||||
subtype: FieldTypeSubtypes.BB_REFERENCE.USERS,
|
||||
subtype: BBReferenceFieldSubType.USERS,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ import {
|
|||
Table,
|
||||
DocumentType,
|
||||
SEPARATOR,
|
||||
FieldSubtype,
|
||||
BBReferenceFieldSubType,
|
||||
SearchFilters,
|
||||
SearchIndex,
|
||||
SearchResponse,
|
||||
|
@ -89,8 +89,8 @@ export function searchInputMapping(table: Table, options: RowSearchParams) {
|
|||
case FieldType.BB_REFERENCE: {
|
||||
const subtype = column.subtype
|
||||
switch (subtype) {
|
||||
case FieldSubtype.USER:
|
||||
case FieldSubtype.USERS:
|
||||
case BBReferenceFieldSubType.USER:
|
||||
case BBReferenceFieldSubType.USERS:
|
||||
userColumnMapping(key, options)
|
||||
break
|
||||
default:
|
||||
|
|
|
@ -2,7 +2,7 @@ import { BadRequestError, context, db as dbCore } from "@budibase/backend-core"
|
|||
import {
|
||||
BBReferenceFieldMetadata,
|
||||
FieldSchema,
|
||||
FieldSubtype,
|
||||
BBReferenceFieldSubType,
|
||||
InternalTable,
|
||||
isBBReferenceField,
|
||||
isRelationshipField,
|
||||
|
@ -96,7 +96,7 @@ function getColumnMigrator(
|
|||
}
|
||||
|
||||
if (oldColumn.relationshipType === RelationshipType.ONE_TO_MANY) {
|
||||
if (newColumn.subtype !== FieldSubtype.USER) {
|
||||
if (newColumn.subtype !== BBReferenceFieldSubType.USER) {
|
||||
throw new BadRequestError(
|
||||
`Column "${oldColumn.name}" is a one-to-many column but "${newColumn.name}" is not a single user column`
|
||||
)
|
||||
|
@ -107,7 +107,7 @@ function getColumnMigrator(
|
|||
oldColumn.relationshipType === RelationshipType.MANY_TO_MANY ||
|
||||
oldColumn.relationshipType === RelationshipType.MANY_TO_ONE
|
||||
) {
|
||||
if (newColumn.subtype !== FieldSubtype.USERS) {
|
||||
if (newColumn.subtype !== BBReferenceFieldSubType.USERS) {
|
||||
throw new BadRequestError(
|
||||
`Column "${oldColumn.name}" is a ${oldColumn.relationshipType} column but "${newColumn.name}" is not a multi user column`
|
||||
)
|
||||
|
|
|
@ -1,13 +1,17 @@
|
|||
import { cache, db as dbCore } from "@budibase/backend-core"
|
||||
import { utils } from "@budibase/shared-core"
|
||||
import { FieldSubtype, DocumentType, SEPARATOR } from "@budibase/types"
|
||||
import {
|
||||
BBReferenceFieldSubType,
|
||||
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.USER | FieldSubtype.USERS
|
||||
subtype: BBReferenceFieldSubType.USER | BBReferenceFieldSubType.USERS
|
||||
): Promise<string | string[] | null> {
|
||||
let referenceIds: string[] = []
|
||||
|
||||
|
@ -40,15 +44,18 @@ export async function processInputBBReferences(
|
|||
})
|
||||
|
||||
switch (subtype) {
|
||||
case FieldSubtype.USER:
|
||||
case FieldSubtype.USERS: {
|
||||
case BBReferenceFieldSubType.USER:
|
||||
case BBReferenceFieldSubType.USERS: {
|
||||
const { notFoundIds } = await cache.user.getUsers(referenceIds)
|
||||
|
||||
if (notFoundIds?.length) {
|
||||
throw new InvalidBBRefError(notFoundIds[0], FieldSubtype.USER)
|
||||
throw new InvalidBBRefError(
|
||||
notFoundIds[0],
|
||||
BBReferenceFieldSubType.USER
|
||||
)
|
||||
}
|
||||
|
||||
if (subtype === FieldSubtype.USERS) {
|
||||
if (subtype === BBReferenceFieldSubType.USERS) {
|
||||
return referenceIds
|
||||
}
|
||||
|
||||
|
@ -61,7 +68,7 @@ export async function processInputBBReferences(
|
|||
|
||||
export async function processOutputBBReferences(
|
||||
value: string | string[],
|
||||
subtype: FieldSubtype.USER | FieldSubtype.USERS
|
||||
subtype: BBReferenceFieldSubType.USER | BBReferenceFieldSubType.USERS
|
||||
) {
|
||||
if (value === null || value === undefined) {
|
||||
// Already processed or nothing to process
|
||||
|
@ -72,8 +79,8 @@ export async function processOutputBBReferences(
|
|||
typeof value === "string" ? value.split(",").filter(id => !!id) : value
|
||||
|
||||
switch (subtype) {
|
||||
case FieldSubtype.USER:
|
||||
case FieldSubtype.USERS: {
|
||||
case BBReferenceFieldSubType.USER:
|
||||
case BBReferenceFieldSubType.USERS: {
|
||||
const { users } = await cache.user.getUsers(ids)
|
||||
if (!users.length) {
|
||||
return undefined
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { FieldSubtype } from "@budibase/types"
|
||||
import { BBReferenceFieldSubType } from "@budibase/types"
|
||||
|
||||
export class InvalidBBRefError extends Error {
|
||||
constructor(id: string, subtype: FieldSubtype) {
|
||||
constructor(id: string, subtype: BBReferenceFieldSubType) {
|
||||
super(`Id "${id}" is not valid for the subtype "${subtype}"`)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import _ from "lodash"
|
||||
import * as backendCore from "@budibase/backend-core"
|
||||
import { FieldSubtype, User } from "@budibase/types"
|
||||
import { BBReferenceFieldSubType, User } from "@budibase/types"
|
||||
import {
|
||||
processInputBBReferences,
|
||||
processOutputBBReferences,
|
||||
|
@ -63,7 +63,7 @@ describe("bbReferenceProcessor", () => {
|
|||
const userId = user!._id!
|
||||
|
||||
const result = await config.doInTenant(() =>
|
||||
processInputBBReferences(userId, FieldSubtype.USER)
|
||||
processInputBBReferences(userId, BBReferenceFieldSubType.USER)
|
||||
)
|
||||
|
||||
expect(result).toEqual(userId)
|
||||
|
@ -76,9 +76,11 @@ describe("bbReferenceProcessor", () => {
|
|||
|
||||
await expect(
|
||||
config.doInTenant(() =>
|
||||
processInputBBReferences(userId, FieldSubtype.USER)
|
||||
processInputBBReferences(userId, BBReferenceFieldSubType.USER)
|
||||
)
|
||||
).rejects.toThrow(new InvalidBBRefError(userId, FieldSubtype.USER))
|
||||
).rejects.toThrow(
|
||||
new InvalidBBRefError(userId, BBReferenceFieldSubType.USER)
|
||||
)
|
||||
expect(cacheGetUsersSpy).toHaveBeenCalledTimes(1)
|
||||
expect(cacheGetUsersSpy).toHaveBeenCalledWith([userId])
|
||||
})
|
||||
|
@ -88,7 +90,7 @@ describe("bbReferenceProcessor", () => {
|
|||
|
||||
const userIdCsv = userIds.join(" , ")
|
||||
const result = await config.doInTenant(() =>
|
||||
processInputBBReferences(userIdCsv, FieldSubtype.USER)
|
||||
processInputBBReferences(userIdCsv, BBReferenceFieldSubType.USER)
|
||||
)
|
||||
|
||||
expect(result).toEqual(userIds.join(","))
|
||||
|
@ -108,16 +110,21 @@ describe("bbReferenceProcessor", () => {
|
|||
|
||||
await expect(
|
||||
config.doInTenant(() =>
|
||||
processInputBBReferences(userIdCsv, FieldSubtype.USER)
|
||||
processInputBBReferences(userIdCsv, BBReferenceFieldSubType.USER)
|
||||
)
|
||||
).rejects.toThrow(new InvalidBBRefError(wrongId, FieldSubtype.USER))
|
||||
).rejects.toThrow(
|
||||
new InvalidBBRefError(wrongId, BBReferenceFieldSubType.USER)
|
||||
)
|
||||
})
|
||||
|
||||
it("validate valid user object", async () => {
|
||||
const userId = _.sample(users)!._id!
|
||||
|
||||
const result = await config.doInTenant(() =>
|
||||
processInputBBReferences({ _id: userId }, FieldSubtype.USER)
|
||||
processInputBBReferences(
|
||||
{ _id: userId },
|
||||
BBReferenceFieldSubType.USER
|
||||
)
|
||||
)
|
||||
|
||||
expect(result).toEqual(userId)
|
||||
|
@ -129,7 +136,7 @@ describe("bbReferenceProcessor", () => {
|
|||
const userIds = _.sampleSize(users, 3).map(x => x._id!)
|
||||
|
||||
const result = await config.doInTenant(() =>
|
||||
processInputBBReferences(userIds, FieldSubtype.USER)
|
||||
processInputBBReferences(userIds, BBReferenceFieldSubType.USER)
|
||||
)
|
||||
|
||||
expect(result).toEqual(userIds.join(","))
|
||||
|
@ -139,7 +146,7 @@ describe("bbReferenceProcessor", () => {
|
|||
|
||||
it("empty strings will return null", async () => {
|
||||
const result = await config.doInTenant(() =>
|
||||
processInputBBReferences("", FieldSubtype.USER)
|
||||
processInputBBReferences("", BBReferenceFieldSubType.USER)
|
||||
)
|
||||
|
||||
expect(result).toEqual(null)
|
||||
|
@ -147,7 +154,7 @@ describe("bbReferenceProcessor", () => {
|
|||
|
||||
it("empty arrays will return null", async () => {
|
||||
const result = await config.doInTenant(() =>
|
||||
processInputBBReferences([], FieldSubtype.USER)
|
||||
processInputBBReferences([], BBReferenceFieldSubType.USER)
|
||||
)
|
||||
|
||||
expect(result).toEqual(null)
|
||||
|
@ -157,7 +164,7 @@ describe("bbReferenceProcessor", () => {
|
|||
const userId = _.sample(users)!._id!
|
||||
const userMetadataId = backendCore.db.generateUserMetadataID(userId)
|
||||
const result = await config.doInTenant(() =>
|
||||
processInputBBReferences(userMetadataId, FieldSubtype.USER)
|
||||
processInputBBReferences(userMetadataId, BBReferenceFieldSubType.USER)
|
||||
)
|
||||
expect(result).toBe(userId)
|
||||
})
|
||||
|
@ -171,7 +178,7 @@ describe("bbReferenceProcessor", () => {
|
|||
const userId = user._id!
|
||||
|
||||
const result = await config.doInTenant(() =>
|
||||
processOutputBBReferences(userId, FieldSubtype.USER)
|
||||
processOutputBBReferences(userId, BBReferenceFieldSubType.USER)
|
||||
)
|
||||
|
||||
expect(result).toEqual([
|
||||
|
@ -195,7 +202,7 @@ describe("bbReferenceProcessor", () => {
|
|||
const result = await config.doInTenant(() =>
|
||||
processOutputBBReferences(
|
||||
[userId1, userId2].join(","),
|
||||
FieldSubtype.USER
|
||||
BBReferenceFieldSubType.USER
|
||||
)
|
||||
)
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ import { inputProcessing } from ".."
|
|||
import { generator, structures } from "@budibase/backend-core/tests"
|
||||
import {
|
||||
FieldType,
|
||||
FieldTypeSubtypes,
|
||||
BBReferenceFieldSubType,
|
||||
INTERNAL_TABLE_SOURCE_ID,
|
||||
Table,
|
||||
TableSourceType,
|
||||
|
@ -39,7 +39,7 @@ describe("rowProcessor - inputProcessing", () => {
|
|||
},
|
||||
user: {
|
||||
type: FieldType.BB_REFERENCE,
|
||||
subtype: FieldTypeSubtypes.BB_REFERENCE.USER,
|
||||
subtype: BBReferenceFieldSubType.USER,
|
||||
name: "user",
|
||||
constraints: {
|
||||
presence: true,
|
||||
|
@ -93,7 +93,7 @@ describe("rowProcessor - inputProcessing", () => {
|
|||
},
|
||||
user: {
|
||||
type: FieldType.BB_REFERENCE,
|
||||
subtype: FieldTypeSubtypes.BB_REFERENCE.USER,
|
||||
subtype: BBReferenceFieldSubType.USER,
|
||||
name: "user",
|
||||
constraints: {
|
||||
presence: false,
|
||||
|
@ -135,7 +135,7 @@ describe("rowProcessor - inputProcessing", () => {
|
|||
},
|
||||
user: {
|
||||
type: FieldType.BB_REFERENCE,
|
||||
subtype: FieldTypeSubtypes.BB_REFERENCE.USER,
|
||||
subtype: BBReferenceFieldSubType.USER,
|
||||
name: "user",
|
||||
constraints: {
|
||||
presence: false,
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import {
|
||||
FieldSubtype,
|
||||
FieldType,
|
||||
FieldTypeSubtypes,
|
||||
BBReferenceFieldSubType,
|
||||
INTERNAL_TABLE_SOURCE_ID,
|
||||
RowAttachment,
|
||||
Table,
|
||||
|
@ -42,7 +41,7 @@ describe("rowProcessor - outputProcessing", () => {
|
|||
},
|
||||
user: {
|
||||
type: FieldType.BB_REFERENCE,
|
||||
subtype: FieldTypeSubtypes.BB_REFERENCE.USER,
|
||||
subtype: BBReferenceFieldSubType.USER,
|
||||
name: "user",
|
||||
constraints: {
|
||||
presence: false,
|
||||
|
@ -69,7 +68,7 @@ describe("rowProcessor - outputProcessing", () => {
|
|||
).toHaveBeenCalledTimes(1)
|
||||
expect(bbReferenceProcessor.processOutputBBReferences).toHaveBeenCalledWith(
|
||||
"123",
|
||||
FieldSubtype.USER
|
||||
BBReferenceFieldSubType.USER
|
||||
)
|
||||
})
|
||||
|
||||
|
@ -175,7 +174,7 @@ describe("rowProcessor - outputProcessing", () => {
|
|||
},
|
||||
user: {
|
||||
type: FieldType.BB_REFERENCE,
|
||||
subtype: FieldTypeSubtypes.BB_REFERENCE.USER,
|
||||
subtype: BBReferenceFieldSubType.USER,
|
||||
name: "user",
|
||||
constraints: {
|
||||
presence: false,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import {
|
||||
FieldType,
|
||||
FieldSubtype,
|
||||
BBReferenceFieldSubType,
|
||||
TableSchema,
|
||||
FieldSchema,
|
||||
Row,
|
||||
|
@ -137,10 +137,10 @@ export function parse(rows: Rows, schema: TableSchema): Rows {
|
|||
parsedRow[columnName] = undefined
|
||||
} else {
|
||||
switch (columnSubtype) {
|
||||
case FieldSubtype.USER:
|
||||
case BBReferenceFieldSubType.USER:
|
||||
parsedRow[columnName] = parsedValues[0]?._id
|
||||
break
|
||||
case FieldSubtype.USERS:
|
||||
case BBReferenceFieldSubType.USERS:
|
||||
parsedRow[columnName] = parsedValues.map(u => u._id)
|
||||
break
|
||||
default:
|
||||
|
@ -164,11 +164,11 @@ export function parse(rows: Rows, schema: TableSchema): Rows {
|
|||
|
||||
function isValidBBReference(
|
||||
columnData: any,
|
||||
columnSubtype: FieldSubtype.USER | FieldSubtype.USERS
|
||||
columnSubtype: BBReferenceFieldSubType.USER | BBReferenceFieldSubType.USERS
|
||||
): boolean {
|
||||
switch (columnSubtype) {
|
||||
case FieldSubtype.USER:
|
||||
case FieldSubtype.USERS: {
|
||||
case BBReferenceFieldSubType.USER:
|
||||
case BBReferenceFieldSubType.USERS: {
|
||||
if (typeof columnData !== "string") {
|
||||
return false
|
||||
}
|
||||
|
@ -177,7 +177,10 @@ function isValidBBReference(
|
|||
return false
|
||||
}
|
||||
|
||||
if (columnSubtype === FieldSubtype.USER && userArray.length > 1) {
|
||||
if (
|
||||
columnSubtype === BBReferenceFieldSubType.USER &&
|
||||
userArray.length > 1
|
||||
) {
|
||||
return false
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import {
|
||||
Datasource,
|
||||
FieldSubtype,
|
||||
BBReferenceFieldSubType,
|
||||
FieldType,
|
||||
FormulaType,
|
||||
SearchFilter,
|
||||
|
@ -22,7 +22,7 @@ const HBS_REGEX = /{{([^{].*?)}}/g
|
|||
export const getValidOperatorsForType = (
|
||||
fieldType: {
|
||||
type: FieldType
|
||||
subtype?: FieldSubtype
|
||||
subtype?: BBReferenceFieldSubType
|
||||
formulaType?: FormulaType
|
||||
},
|
||||
field: string,
|
||||
|
@ -68,9 +68,15 @@ export const getValidOperatorsForType = (
|
|||
ops = numOps
|
||||
} else if (type === FieldType.FORMULA && formulaType === FormulaType.STATIC) {
|
||||
ops = stringOps.concat([Op.MoreThan, Op.LessThan])
|
||||
} else if (type === FieldType.BB_REFERENCE && subtype == FieldSubtype.USER) {
|
||||
} else if (
|
||||
type === FieldType.BB_REFERENCE &&
|
||||
subtype == BBReferenceFieldSubType.USER
|
||||
) {
|
||||
ops = [Op.Equals, Op.NotEquals, Op.Empty, Op.NotEmpty, Op.In]
|
||||
} else if (type === FieldType.BB_REFERENCE && subtype == FieldSubtype.USERS) {
|
||||
} else if (
|
||||
type === FieldType.BB_REFERENCE &&
|
||||
subtype == BBReferenceFieldSubType.USERS
|
||||
) {
|
||||
ops = [Op.Contains, Op.NotContains, Op.ContainsAny, Op.Empty, Op.NotEmpty]
|
||||
}
|
||||
|
||||
|
|
|
@ -124,16 +124,3 @@ export interface Row extends Document {
|
|||
_viewId?: string
|
||||
[key: string]: any
|
||||
}
|
||||
|
||||
export enum FieldSubtype {
|
||||
USER = "user",
|
||||
USERS = "users",
|
||||
}
|
||||
|
||||
// The 'as' are required for typescript not to type the outputs as generic FieldSubtype
|
||||
export const FieldTypeSubtypes = {
|
||||
BB_REFERENCE: {
|
||||
USER: FieldSubtype.USER as FieldSubtype.USER,
|
||||
USERS: FieldSubtype.USERS as FieldSubtype.USERS,
|
||||
},
|
||||
}
|
||||
|
|
|
@ -24,3 +24,8 @@ export enum FormulaType {
|
|||
STATIC = "static",
|
||||
DYNAMIC = "dynamic",
|
||||
}
|
||||
|
||||
export enum BBReferenceFieldSubType {
|
||||
USER = "user",
|
||||
USERS = "users",
|
||||
}
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
// all added by grid/table when defining the
|
||||
// column size, position and whether it can be viewed
|
||||
import { FieldSubtype, FieldType } from "../row"
|
||||
import { FieldType } from "../row"
|
||||
import {
|
||||
AutoFieldSubType,
|
||||
AutoReason,
|
||||
BBReferenceFieldSubType,
|
||||
FormulaType,
|
||||
JsonFieldSubType,
|
||||
RelationshipType,
|
||||
|
@ -109,7 +110,7 @@ export interface FormulaFieldMetadata extends BaseFieldSchema {
|
|||
export interface BBReferenceFieldMetadata
|
||||
extends Omit<BaseFieldSchema, "subtype"> {
|
||||
type: FieldType.BB_REFERENCE
|
||||
subtype: FieldSubtype.USER | FieldSubtype.USERS
|
||||
subtype: BBReferenceFieldSubType.USER | BBReferenceFieldSubType.USERS
|
||||
relationshipType?: RelationshipType
|
||||
}
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@ export enum PlanType {
|
|||
/** @deprecated */
|
||||
BUSINESS = "business",
|
||||
ENTERPRISE_BASIC = "enterprise_basic",
|
||||
ENTERPRISE_BASIC_TRIAL = "enterprise_basic_trial",
|
||||
ENTERPRISE = "enterprise",
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Find all Docker containers with the label "org.testcontainers=true"
|
||||
containers=$(docker ps -q -f "label=org.testcontainers=true")
|
||||
|
||||
# Check if there are any containers to stop
|
||||
if [ -z "$containers" ]; then
|
||||
echo "No containers with label 'org.testcontainers=true' found."
|
||||
else
|
||||
# Stop the containers
|
||||
echo "Stopping containers..."
|
||||
docker stop $containers
|
||||
|
||||
# Remove the containers
|
||||
echo "Removing containers..."
|
||||
docker rm $containers
|
||||
|
||||
echo "Containers have been stopped and removed."
|
||||
fi
|
Loading…
Reference in New Issue