Merge branch 'master' into feature/deprecate-table-component
This commit is contained in:
commit
322425cd54
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"version": "2.22.8",
|
||||
"version": "2.22.11",
|
||||
"npmClient": "yarn",
|
||||
"packages": [
|
||||
"packages/*",
|
||||
|
|
|
@ -34,7 +34,12 @@
|
|||
import { getBindings } from "components/backend/DataTable/formula"
|
||||
import JSONSchemaModal from "./JSONSchemaModal.svelte"
|
||||
import { ValidColumnNameRegex } from "@budibase/shared-core"
|
||||
import { FieldType, FieldSubtype, SourceName } from "@budibase/types"
|
||||
import {
|
||||
FieldType,
|
||||
FieldSubtype,
|
||||
SourceName,
|
||||
FieldTypeSubtypes,
|
||||
} from "@budibase/types"
|
||||
import RelationshipSelector from "components/common/RelationshipSelector.svelte"
|
||||
import { RowUtils } from "@budibase/frontend-core"
|
||||
import ServerBindingPanel from "components/common/bindings/ServerBindingPanel.svelte"
|
||||
|
@ -191,8 +196,10 @@
|
|||
// don't make field IDs for auto types
|
||||
if (type === AUTO_TYPE || autocolumn) {
|
||||
return type.toUpperCase()
|
||||
} else {
|
||||
} else if (type === FieldType.BB_REFERENCE) {
|
||||
return `${type}${subtype || ""}`.toUpperCase()
|
||||
} else {
|
||||
return type.toUpperCase()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -705,17 +712,14 @@
|
|||
/>
|
||||
{:else if editableColumn.type === FieldType.ATTACHMENT}
|
||||
<Toggle
|
||||
value={editableColumn.constraints?.length?.maximum !== 1}
|
||||
value={editableColumn.subtype !== FieldTypeSubtypes.ATTACHMENT.SINGLE &&
|
||||
// Checking config before the subtype was added
|
||||
editableColumn.constraints?.length?.maximum !== 1}
|
||||
on:change={e => {
|
||||
if (!e.detail) {
|
||||
editableColumn.constraints ??= { length: {} }
|
||||
editableColumn.constraints.length ??= {}
|
||||
editableColumn.constraints.length.maximum = 1
|
||||
editableColumn.constraints.length.message =
|
||||
"cannot contain multiple files"
|
||||
editableColumn.subtype = FieldTypeSubtypes.ATTACHMENT.SINGLE
|
||||
} else {
|
||||
delete editableColumn.constraints?.length?.maximum
|
||||
delete editableColumn.constraints?.length?.message
|
||||
delete editableColumn.subtype
|
||||
}
|
||||
}}
|
||||
thin
|
||||
|
|
|
@ -30,6 +30,8 @@ import {
|
|||
View,
|
||||
RelationshipFieldMetadata,
|
||||
FieldType,
|
||||
FieldTypeSubtypes,
|
||||
AttachmentFieldMetadata,
|
||||
} from "@budibase/types"
|
||||
|
||||
export async function clearColumns(table: Table, columnNames: string[]) {
|
||||
|
@ -88,6 +90,27 @@ export async function checkForColumnUpdates(
|
|||
// Update views
|
||||
await checkForViewUpdates(updatedTable, deletedColumns, columnRename)
|
||||
}
|
||||
|
||||
const changedAttachmentSubtypeColumns = Object.values(
|
||||
updatedTable.schema
|
||||
).filter(
|
||||
(column): column is AttachmentFieldMetadata =>
|
||||
column.type === FieldType.ATTACHMENT &&
|
||||
column.subtype !== oldTable?.schema[column.name]?.subtype
|
||||
)
|
||||
for (const attachmentColumn of changedAttachmentSubtypeColumns) {
|
||||
if (attachmentColumn.subtype === FieldTypeSubtypes.ATTACHMENT.SINGLE) {
|
||||
attachmentColumn.constraints ??= { length: {} }
|
||||
attachmentColumn.constraints.length ??= {}
|
||||
attachmentColumn.constraints.length.maximum = 1
|
||||
attachmentColumn.constraints.length.message =
|
||||
"cannot contain multiple files"
|
||||
} else {
|
||||
delete attachmentColumn.constraints?.length?.maximum
|
||||
delete attachmentColumn.constraints?.length?.message
|
||||
}
|
||||
}
|
||||
|
||||
return { rows: updatedRows, table: updatedTable }
|
||||
}
|
||||
|
||||
|
|
|
@ -60,7 +60,7 @@ function generateSchema(
|
|||
schema.text(key)
|
||||
break
|
||||
case FieldType.BB_REFERENCE: {
|
||||
const subtype = column.subtype as FieldSubtype
|
||||
const subtype = column.subtype
|
||||
switch (subtype) {
|
||||
case FieldSubtype.USER:
|
||||
schema.text(key)
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -1,6 +1,5 @@
|
|||
const {
|
||||
getJsHelperList,
|
||||
} = require("../../../../string-templates/src/helpers/list.js")
|
||||
// eslint-disable-next-line local-rules/no-budibase-imports
|
||||
import { getJsHelperList } from "@budibase/string-templates/src/helpers/list"
|
||||
|
||||
export default {
|
||||
...getJsHelperList(),
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
"use strict";var snippets=(()=>{var u=Object.create;var n=Object.defineProperty;var a=Object.getOwnPropertyDescriptor;var h=Object.getOwnPropertyNames;var x=Object.getPrototypeOf,C=Object.prototype.hasOwnProperty;var l=(i,e)=>()=>(e||i((e={exports:{}}).exports,e),e.exports),W=(i,e)=>{for(var p in e)n(i,p,{get:e[p],enumerable:!0})},f=(i,e,p,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let t of h(e))!C.call(i,t)&&t!==p&&n(i,t,{get:()=>e[t],enumerable:!(r=a(e,t))||r.enumerable});return i};var d=(i,e,p)=>(p=i!=null?u(x(i)):{},f(e||!i||!i.__esModule?n(p,"default",{value:i,enumerable:!0}):p,i)),g=i=>f(n({},"__esModule",{value:!0}),i);var s=l((D,o)=>{o.exports.iifeWrapper=i=>`(function(){
|
||||
"use strict";var snippets=(()=>{var p=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var s=Object.getOwnPropertyNames;var c=Object.prototype.hasOwnProperty;var u=(i,e)=>{for(var n in e)p(i,n,{get:e[n],enumerable:!0})},a=(i,e,n,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let t of s(e))!c.call(i,t)&&t!==n&&p(i,t,{get:()=>e[t],enumerable:!(r=f(e,t))||r.enumerable});return i};var h=i=>a(p({},"__esModule",{value:!0}),i);var C={};u(C,{default:()=>x});var o=i=>`(function(){
|
||||
${i}
|
||||
})();`});var w={};W(w,{default:()=>v});var c=d(s()),v=new Proxy({},{get:function(i,e){return e in snippetCache||(snippetCache[e]=[eval][0]((0,c.iifeWrapper)(snippetDefinitions[e]))),snippetCache[e]}});return g(w);})();
|
||||
})();`;var x=new Proxy({},{get:function(i,e){return e in snippetCache||(snippetCache[e]=[eval][0](o(snippetDefinitions[e]))),snippetCache[e]}});return h(C);})();
|
||||
|
|
|
@ -67,7 +67,7 @@ export function searchInputMapping(table: Table, options: SearchParams) {
|
|||
for (let [key, column] of Object.entries(table.schema)) {
|
||||
switch (column.type) {
|
||||
case FieldType.BB_REFERENCE: {
|
||||
const subtype = column.subtype as FieldSubtype
|
||||
const subtype = column.subtype
|
||||
switch (subtype) {
|
||||
case FieldSubtype.USER:
|
||||
case FieldSubtype.USERS:
|
||||
|
|
|
@ -7,7 +7,7 @@ const ROW_PREFIX = DocumentType.ROW + SEPARATOR
|
|||
|
||||
export async function processInputBBReferences(
|
||||
value: string | string[] | { _id: string } | { _id: string }[],
|
||||
subtype: FieldSubtype
|
||||
subtype: FieldSubtype.USER | FieldSubtype.USERS
|
||||
): Promise<string | string[] | null> {
|
||||
let referenceIds: string[] = []
|
||||
|
||||
|
@ -61,7 +61,7 @@ export async function processInputBBReferences(
|
|||
|
||||
export async function processOutputBBReferences(
|
||||
value: string | string[],
|
||||
subtype: FieldSubtype
|
||||
subtype: FieldSubtype.USER | FieldSubtype.USERS
|
||||
) {
|
||||
if (value === null || value === undefined) {
|
||||
// Already processed or nothing to process
|
||||
|
|
|
@ -6,7 +6,6 @@ import { TYPE_TRANSFORM_MAP } from "./map"
|
|||
import {
|
||||
FieldType,
|
||||
AutoFieldSubType,
|
||||
FieldSubtype,
|
||||
Row,
|
||||
RowAttachment,
|
||||
Table,
|
||||
|
@ -159,10 +158,7 @@ export async function inputProcessing(
|
|||
}
|
||||
|
||||
if (field.type === FieldType.BB_REFERENCE && value) {
|
||||
clonedRow[key] = await processInputBBReferences(
|
||||
value,
|
||||
field.subtype as FieldSubtype
|
||||
)
|
||||
clonedRow[key] = await processInputBBReferences(value, field.subtype)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -238,7 +234,7 @@ export async function outputProcessing<T extends Row[] | Row>(
|
|||
for (let row of enriched) {
|
||||
row[property] = await processOutputBBReferences(
|
||||
row[property],
|
||||
column.subtype as FieldSubtype
|
||||
column.subtype
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,26 +1,14 @@
|
|||
import { FieldType, FieldSubtype } from "@budibase/types"
|
||||
import {
|
||||
FieldType,
|
||||
FieldSubtype,
|
||||
TableSchema,
|
||||
FieldSchema,
|
||||
Row,
|
||||
} from "@budibase/types"
|
||||
import { ValidColumnNameRegex, utils } from "@budibase/shared-core"
|
||||
import { db } from "@budibase/backend-core"
|
||||
import { parseCsvExport } from "../api/controllers/view/exporters"
|
||||
|
||||
interface SchemaColumn {
|
||||
readonly name: string
|
||||
readonly type: FieldType
|
||||
readonly subtype: FieldSubtype
|
||||
readonly autocolumn?: boolean
|
||||
readonly constraints?: {
|
||||
presence: boolean
|
||||
}
|
||||
}
|
||||
|
||||
interface Schema {
|
||||
readonly [index: string]: SchemaColumn
|
||||
}
|
||||
|
||||
interface Row {
|
||||
[index: string]: any
|
||||
}
|
||||
|
||||
type Rows = Array<Row>
|
||||
|
||||
interface SchemaValidation {
|
||||
|
@ -34,12 +22,10 @@ interface ValidationResults {
|
|||
errors: Record<string, string>
|
||||
}
|
||||
|
||||
export function isSchema(schema: any): schema is Schema {
|
||||
export function isSchema(schema: any): schema is TableSchema {
|
||||
return (
|
||||
typeof schema === "object" &&
|
||||
Object.values(schema).every(rawColumn => {
|
||||
const column = rawColumn as SchemaColumn
|
||||
|
||||
Object.values<FieldSchema>(schema).every(column => {
|
||||
return (
|
||||
column !== null &&
|
||||
typeof column === "object" &&
|
||||
|
@ -54,7 +40,7 @@ export function isRows(rows: any): rows is Rows {
|
|||
return Array.isArray(rows) && rows.every(row => typeof row === "object")
|
||||
}
|
||||
|
||||
export function validate(rows: Rows, schema: Schema): ValidationResults {
|
||||
export function validate(rows: Rows, schema: TableSchema): ValidationResults {
|
||||
const results: ValidationResults = {
|
||||
schemaValidation: {},
|
||||
allValid: false,
|
||||
|
@ -64,9 +50,11 @@ export function validate(rows: Rows, schema: Schema): ValidationResults {
|
|||
|
||||
rows.forEach(row => {
|
||||
Object.entries(row).forEach(([columnName, columnData]) => {
|
||||
const columnType = schema[columnName]?.type
|
||||
const columnSubtype = schema[columnName]?.subtype
|
||||
const isAutoColumn = schema[columnName]?.autocolumn
|
||||
const {
|
||||
type: columnType,
|
||||
subtype: columnSubtype,
|
||||
autocolumn: isAutoColumn,
|
||||
} = schema[columnName]
|
||||
|
||||
// If the column had an invalid value we don't want to override it
|
||||
if (results.schemaValidation[columnName] === false) {
|
||||
|
@ -123,7 +111,7 @@ export function validate(rows: Rows, schema: Schema): ValidationResults {
|
|||
return results
|
||||
}
|
||||
|
||||
export function parse(rows: Rows, schema: Schema): Rows {
|
||||
export function parse(rows: Rows, schema: TableSchema): Rows {
|
||||
return rows.map(row => {
|
||||
const parsedRow: Row = {}
|
||||
|
||||
|
@ -133,9 +121,7 @@ export function parse(rows: Rows, schema: Schema): Rows {
|
|||
return
|
||||
}
|
||||
|
||||
const columnType = schema[columnName].type
|
||||
const columnSubtype = schema[columnName].subtype
|
||||
|
||||
const { type: columnType, subtype: columnSubtype } = schema[columnName]
|
||||
if (columnType === FieldType.NUMBER) {
|
||||
// If provided must be a valid number
|
||||
parsedRow[columnName] = columnData ? Number(columnData) : columnData
|
||||
|
@ -172,7 +158,7 @@ export function parse(rows: Rows, schema: Schema): Rows {
|
|||
|
||||
function isValidBBReference(
|
||||
columnData: any,
|
||||
columnSubtype: FieldSubtype
|
||||
columnSubtype: FieldSubtype.USER | FieldSubtype.USERS
|
||||
): boolean {
|
||||
switch (columnSubtype) {
|
||||
case FieldSubtype.USER:
|
||||
|
|
|
@ -18,7 +18,8 @@
|
|||
"@budibase/backend-core/*": ["../backend-core/*"],
|
||||
"@budibase/shared-core": ["../shared-core/src"],
|
||||
"@budibase/pro": ["../pro/src"],
|
||||
"@budibase/string-templates": ["../string-templates/src"]
|
||||
"@budibase/string-templates": ["../string-templates/src"],
|
||||
"@budibase/string-templates/*": ["../string-templates/*"]
|
||||
},
|
||||
"allowArbitraryExtensions": true
|
||||
},
|
||||
|
|
|
@ -1,17 +1,29 @@
|
|||
import { date, duration } from "./date"
|
||||
|
||||
import {
|
||||
math,
|
||||
array,
|
||||
number,
|
||||
url,
|
||||
string,
|
||||
comparison,
|
||||
object,
|
||||
regex,
|
||||
uuid,
|
||||
// @ts-expect-error
|
||||
} from "@budibase/handlebars-helpers"
|
||||
/*
|
||||
@budibase/handlebars-helpers is not treeshakeable, so we can't use the barrel files.
|
||||
Otherwise, we have issues when generating the isolated-vm bundle because of the treeshaking
|
||||
*/
|
||||
/* eslint-disable local-rules/no-budibase-imports */
|
||||
// @ts-expect-error
|
||||
import math from "@budibase/handlebars-helpers/lib/math"
|
||||
// @ts-expect-error
|
||||
import array from "@budibase/handlebars-helpers/lib/array"
|
||||
// @ts-expect-error
|
||||
import number from "@budibase/handlebars-helpers/lib/number"
|
||||
// @ts-expect-error
|
||||
import url from "@budibase/handlebars-helpers/lib/url"
|
||||
// @ts-expect-error
|
||||
import string from "@budibase/handlebars-helpers/lib/string"
|
||||
// @ts-expect-error
|
||||
import comparison from "@budibase/handlebars-helpers/lib/comparison"
|
||||
// @ts-expect-error
|
||||
import object from "@budibase/handlebars-helpers/lib/object"
|
||||
// @ts-expect-error
|
||||
import regex from "@budibase/handlebars-helpers/lib/regex"
|
||||
// @ts-expect-error
|
||||
import uuid from "@budibase/handlebars-helpers/lib/uuid"
|
||||
/* eslint-enable local-rules/no-budibase-imports */
|
||||
|
||||
// https://github.com/evanw/esbuild/issues/56
|
||||
const externalCollections = {
|
||||
|
@ -42,14 +54,14 @@ export function getJsHelperList() {
|
|||
|
||||
helpers = {}
|
||||
for (let collection of Object.values(externalCollections)) {
|
||||
for (let [key, func] of Object.entries<any>(collection())) {
|
||||
for (let [key, func] of Object.entries<any>(collection)) {
|
||||
// Handlebars injects the hbs options to the helpers by default. We are adding an empty {} as a last parameter to simulate it
|
||||
helpers[key] = (...props: any) => func(...props, {})
|
||||
}
|
||||
}
|
||||
helpers = {
|
||||
...helpers,
|
||||
addedHelpers,
|
||||
...addedHelpers,
|
||||
}
|
||||
|
||||
for (const toRemove of helpersToRemoveForJs) {
|
||||
|
|
|
@ -94,7 +94,7 @@ export async function processObject<T extends Record<string, any>>(
|
|||
for (const key of Object.keys(object || {})) {
|
||||
if (object[key] != null) {
|
||||
const val = object[key]
|
||||
let parsedValue
|
||||
let parsedValue = val
|
||||
if (typeof val === "string") {
|
||||
parsedValue = await processString(object[key], context, opts)
|
||||
} else if (typeof val === "object") {
|
||||
|
|
|
@ -104,6 +104,26 @@ describe("Test that the object processing works correctly", () => {
|
|||
}
|
||||
expect(error).toBeNull()
|
||||
})
|
||||
|
||||
it("should be able to handle booleans", async () => {
|
||||
const output = await processObject(
|
||||
{
|
||||
first: true,
|
||||
second: "true",
|
||||
third: "another string",
|
||||
forth: "with {{ template }}",
|
||||
},
|
||||
{
|
||||
template: "value",
|
||||
}
|
||||
)
|
||||
expect(output).toEqual({
|
||||
first: true,
|
||||
second: "true",
|
||||
third: "another string",
|
||||
forth: "with value",
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("check returning objects", () => {
|
||||
|
|
|
@ -38,11 +38,16 @@ export interface Row extends Document {
|
|||
export enum FieldSubtype {
|
||||
USER = "user",
|
||||
USERS = "users",
|
||||
SINGLE = "single",
|
||||
}
|
||||
|
||||
// The 'as' are required for typescript not to type the outputs as generic FieldSubtype
|
||||
export const FieldTypeSubtypes = {
|
||||
BB_REFERENCE: {
|
||||
USER: FieldSubtype.USER,
|
||||
USERS: FieldSubtype.USERS,
|
||||
USER: FieldSubtype.USER as FieldSubtype.USER,
|
||||
USERS: FieldSubtype.USERS as FieldSubtype.USERS,
|
||||
},
|
||||
ATTACHMENT: {
|
||||
SINGLE: FieldSubtype.SINGLE as FieldSubtype.SINGLE,
|
||||
},
|
||||
}
|
||||
|
|
|
@ -112,6 +112,12 @@ export interface BBReferenceFieldMetadata
|
|||
relationshipType?: RelationshipType
|
||||
}
|
||||
|
||||
export interface AttachmentFieldMetadata
|
||||
extends Omit<BaseFieldSchema, "subtype"> {
|
||||
type: FieldType.ATTACHMENT
|
||||
subtype?: FieldSubtype.SINGLE
|
||||
}
|
||||
|
||||
export interface FieldConstraints {
|
||||
type?: string
|
||||
email?: boolean
|
||||
|
@ -119,6 +125,7 @@ export interface FieldConstraints {
|
|||
length?: {
|
||||
minimum?: string | number | null
|
||||
maximum?: string | number | null
|
||||
message?: string
|
||||
}
|
||||
numericality?: {
|
||||
greaterThanOrEqualTo: string | null
|
||||
|
@ -156,6 +163,8 @@ interface OtherFieldMetadata extends BaseFieldSchema {
|
|||
| FieldType.FORMULA
|
||||
| FieldType.NUMBER
|
||||
| FieldType.LONGFORM
|
||||
| FieldType.BB_REFERENCE
|
||||
| FieldType.ATTACHMENT
|
||||
>
|
||||
}
|
||||
|
||||
|
@ -169,6 +178,7 @@ export type FieldSchema =
|
|||
| LongFormFieldMetadata
|
||||
| BBReferenceFieldMetadata
|
||||
| JsonFieldMetadata
|
||||
| AttachmentFieldMetadata
|
||||
|
||||
export interface TableSchema {
|
||||
[key: string]: FieldSchema
|
||||
|
@ -203,3 +213,9 @@ export function isBBReferenceField(
|
|||
): field is BBReferenceFieldMetadata {
|
||||
return field.type === FieldType.BB_REFERENCE
|
||||
}
|
||||
|
||||
export function isAttachmentField(
|
||||
field: FieldSchema
|
||||
): field is AttachmentFieldMetadata {
|
||||
return field.type === FieldType.ATTACHMENT
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue