Merge branch 'master' of github.com:Budibase/budibase into cheeks-fixes
This commit is contained in:
commit
aee5cf8886
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"version": "2.22.8",
|
"version": "2.22.9",
|
||||||
"npmClient": "yarn",
|
"npmClient": "yarn",
|
||||||
"packages": [
|
"packages": [
|
||||||
"packages/*",
|
"packages/*",
|
||||||
|
|
|
@ -34,7 +34,12 @@
|
||||||
import { getBindings } from "components/backend/DataTable/formula"
|
import { getBindings } from "components/backend/DataTable/formula"
|
||||||
import JSONSchemaModal from "./JSONSchemaModal.svelte"
|
import JSONSchemaModal from "./JSONSchemaModal.svelte"
|
||||||
import { ValidColumnNameRegex } from "@budibase/shared-core"
|
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 RelationshipSelector from "components/common/RelationshipSelector.svelte"
|
||||||
import { RowUtils } from "@budibase/frontend-core"
|
import { RowUtils } from "@budibase/frontend-core"
|
||||||
import ServerBindingPanel from "components/common/bindings/ServerBindingPanel.svelte"
|
import ServerBindingPanel from "components/common/bindings/ServerBindingPanel.svelte"
|
||||||
|
@ -191,8 +196,10 @@
|
||||||
// don't make field IDs for auto types
|
// don't make field IDs for auto types
|
||||||
if (type === AUTO_TYPE || autocolumn) {
|
if (type === AUTO_TYPE || autocolumn) {
|
||||||
return type.toUpperCase()
|
return type.toUpperCase()
|
||||||
} else {
|
} else if (type === FieldType.BB_REFERENCE) {
|
||||||
return `${type}${subtype || ""}`.toUpperCase()
|
return `${type}${subtype || ""}`.toUpperCase()
|
||||||
|
} else {
|
||||||
|
return type.toUpperCase()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -705,17 +712,14 @@
|
||||||
/>
|
/>
|
||||||
{:else if editableColumn.type === FieldType.ATTACHMENT}
|
{:else if editableColumn.type === FieldType.ATTACHMENT}
|
||||||
<Toggle
|
<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 => {
|
on:change={e => {
|
||||||
if (!e.detail) {
|
if (!e.detail) {
|
||||||
editableColumn.constraints ??= { length: {} }
|
editableColumn.subtype = FieldTypeSubtypes.ATTACHMENT.SINGLE
|
||||||
editableColumn.constraints.length ??= {}
|
|
||||||
editableColumn.constraints.length.maximum = 1
|
|
||||||
editableColumn.constraints.length.message =
|
|
||||||
"cannot contain multiple files"
|
|
||||||
} else {
|
} else {
|
||||||
delete editableColumn.constraints?.length?.maximum
|
delete editableColumn.subtype
|
||||||
delete editableColumn.constraints?.length?.message
|
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
thin
|
thin
|
||||||
|
|
|
@ -30,6 +30,8 @@ import {
|
||||||
View,
|
View,
|
||||||
RelationshipFieldMetadata,
|
RelationshipFieldMetadata,
|
||||||
FieldType,
|
FieldType,
|
||||||
|
FieldTypeSubtypes,
|
||||||
|
AttachmentFieldMetadata,
|
||||||
} from "@budibase/types"
|
} from "@budibase/types"
|
||||||
|
|
||||||
export async function clearColumns(table: Table, columnNames: string[]) {
|
export async function clearColumns(table: Table, columnNames: string[]) {
|
||||||
|
@ -88,6 +90,27 @@ export async function checkForColumnUpdates(
|
||||||
// Update views
|
// Update views
|
||||||
await checkForViewUpdates(updatedTable, deletedColumns, columnRename)
|
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 }
|
return { rows: updatedRows, table: updatedTable }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -60,7 +60,7 @@ function generateSchema(
|
||||||
schema.text(key)
|
schema.text(key)
|
||||||
break
|
break
|
||||||
case FieldType.BB_REFERENCE: {
|
case FieldType.BB_REFERENCE: {
|
||||||
const subtype = column.subtype as FieldSubtype
|
const subtype = column.subtype
|
||||||
switch (subtype) {
|
switch (subtype) {
|
||||||
case FieldSubtype.USER:
|
case FieldSubtype.USER:
|
||||||
schema.text(key)
|
schema.text(key)
|
||||||
|
|
|
@ -67,7 +67,7 @@ export function searchInputMapping(table: Table, options: SearchParams) {
|
||||||
for (let [key, column] of Object.entries(table.schema)) {
|
for (let [key, column] of Object.entries(table.schema)) {
|
||||||
switch (column.type) {
|
switch (column.type) {
|
||||||
case FieldType.BB_REFERENCE: {
|
case FieldType.BB_REFERENCE: {
|
||||||
const subtype = column.subtype as FieldSubtype
|
const subtype = column.subtype
|
||||||
switch (subtype) {
|
switch (subtype) {
|
||||||
case FieldSubtype.USER:
|
case FieldSubtype.USER:
|
||||||
case FieldSubtype.USERS:
|
case FieldSubtype.USERS:
|
||||||
|
|
|
@ -7,7 +7,7 @@ const ROW_PREFIX = DocumentType.ROW + SEPARATOR
|
||||||
|
|
||||||
export async function processInputBBReferences(
|
export async function processInputBBReferences(
|
||||||
value: string | string[] | { _id: string } | { _id: string }[],
|
value: string | string[] | { _id: string } | { _id: string }[],
|
||||||
subtype: FieldSubtype
|
subtype: FieldSubtype.USER | FieldSubtype.USERS
|
||||||
): Promise<string | string[] | null> {
|
): Promise<string | string[] | null> {
|
||||||
let referenceIds: string[] = []
|
let referenceIds: string[] = []
|
||||||
|
|
||||||
|
@ -61,7 +61,7 @@ export async function processInputBBReferences(
|
||||||
|
|
||||||
export async function processOutputBBReferences(
|
export async function processOutputBBReferences(
|
||||||
value: string | string[],
|
value: string | string[],
|
||||||
subtype: FieldSubtype
|
subtype: FieldSubtype.USER | FieldSubtype.USERS
|
||||||
) {
|
) {
|
||||||
if (value === null || value === undefined) {
|
if (value === null || value === undefined) {
|
||||||
// Already processed or nothing to process
|
// Already processed or nothing to process
|
||||||
|
|
|
@ -6,7 +6,6 @@ import { TYPE_TRANSFORM_MAP } from "./map"
|
||||||
import {
|
import {
|
||||||
FieldType,
|
FieldType,
|
||||||
AutoFieldSubType,
|
AutoFieldSubType,
|
||||||
FieldSubtype,
|
|
||||||
Row,
|
Row,
|
||||||
RowAttachment,
|
RowAttachment,
|
||||||
Table,
|
Table,
|
||||||
|
@ -159,10 +158,7 @@ export async function inputProcessing(
|
||||||
}
|
}
|
||||||
|
|
||||||
if (field.type === FieldType.BB_REFERENCE && value) {
|
if (field.type === FieldType.BB_REFERENCE && value) {
|
||||||
clonedRow[key] = await processInputBBReferences(
|
clonedRow[key] = await processInputBBReferences(value, field.subtype)
|
||||||
value,
|
|
||||||
field.subtype as FieldSubtype
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -238,7 +234,7 @@ export async function outputProcessing<T extends Row[] | Row>(
|
||||||
for (let row of enriched) {
|
for (let row of enriched) {
|
||||||
row[property] = await processOutputBBReferences(
|
row[property] = await processOutputBBReferences(
|
||||||
row[property],
|
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 { ValidColumnNameRegex, utils } from "@budibase/shared-core"
|
||||||
import { db } from "@budibase/backend-core"
|
import { db } from "@budibase/backend-core"
|
||||||
import { parseCsvExport } from "../api/controllers/view/exporters"
|
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>
|
type Rows = Array<Row>
|
||||||
|
|
||||||
interface SchemaValidation {
|
interface SchemaValidation {
|
||||||
|
@ -34,12 +22,10 @@ interface ValidationResults {
|
||||||
errors: Record<string, string>
|
errors: Record<string, string>
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isSchema(schema: any): schema is Schema {
|
export function isSchema(schema: any): schema is TableSchema {
|
||||||
return (
|
return (
|
||||||
typeof schema === "object" &&
|
typeof schema === "object" &&
|
||||||
Object.values(schema).every(rawColumn => {
|
Object.values<FieldSchema>(schema).every(column => {
|
||||||
const column = rawColumn as SchemaColumn
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
column !== null &&
|
column !== null &&
|
||||||
typeof column === "object" &&
|
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")
|
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 = {
|
const results: ValidationResults = {
|
||||||
schemaValidation: {},
|
schemaValidation: {},
|
||||||
allValid: false,
|
allValid: false,
|
||||||
|
@ -64,9 +50,11 @@ export function validate(rows: Rows, schema: Schema): ValidationResults {
|
||||||
|
|
||||||
rows.forEach(row => {
|
rows.forEach(row => {
|
||||||
Object.entries(row).forEach(([columnName, columnData]) => {
|
Object.entries(row).forEach(([columnName, columnData]) => {
|
||||||
const columnType = schema[columnName]?.type
|
const {
|
||||||
const columnSubtype = schema[columnName]?.subtype
|
type: columnType,
|
||||||
const isAutoColumn = schema[columnName]?.autocolumn
|
subtype: columnSubtype,
|
||||||
|
autocolumn: isAutoColumn,
|
||||||
|
} = schema[columnName]
|
||||||
|
|
||||||
// If the column had an invalid value we don't want to override it
|
// If the column had an invalid value we don't want to override it
|
||||||
if (results.schemaValidation[columnName] === false) {
|
if (results.schemaValidation[columnName] === false) {
|
||||||
|
@ -123,7 +111,7 @@ export function validate(rows: Rows, schema: Schema): ValidationResults {
|
||||||
return results
|
return results
|
||||||
}
|
}
|
||||||
|
|
||||||
export function parse(rows: Rows, schema: Schema): Rows {
|
export function parse(rows: Rows, schema: TableSchema): Rows {
|
||||||
return rows.map(row => {
|
return rows.map(row => {
|
||||||
const parsedRow: Row = {}
|
const parsedRow: Row = {}
|
||||||
|
|
||||||
|
@ -133,9 +121,7 @@ export function parse(rows: Rows, schema: Schema): Rows {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const columnType = schema[columnName].type
|
const { type: columnType, subtype: columnSubtype } = schema[columnName]
|
||||||
const columnSubtype = schema[columnName].subtype
|
|
||||||
|
|
||||||
if (columnType === FieldType.NUMBER) {
|
if (columnType === FieldType.NUMBER) {
|
||||||
// If provided must be a valid number
|
// If provided must be a valid number
|
||||||
parsedRow[columnName] = columnData ? Number(columnData) : columnData
|
parsedRow[columnName] = columnData ? Number(columnData) : columnData
|
||||||
|
@ -172,7 +158,7 @@ export function parse(rows: Rows, schema: Schema): Rows {
|
||||||
|
|
||||||
function isValidBBReference(
|
function isValidBBReference(
|
||||||
columnData: any,
|
columnData: any,
|
||||||
columnSubtype: FieldSubtype
|
columnSubtype: FieldSubtype.USER | FieldSubtype.USERS
|
||||||
): boolean {
|
): boolean {
|
||||||
switch (columnSubtype) {
|
switch (columnSubtype) {
|
||||||
case FieldSubtype.USER:
|
case FieldSubtype.USER:
|
||||||
|
|
|
@ -38,11 +38,16 @@ export interface Row extends Document {
|
||||||
export enum FieldSubtype {
|
export enum FieldSubtype {
|
||||||
USER = "user",
|
USER = "user",
|
||||||
USERS = "users",
|
USERS = "users",
|
||||||
|
SINGLE = "single",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The 'as' are required for typescript not to type the outputs as generic FieldSubtype
|
||||||
export const FieldTypeSubtypes = {
|
export const FieldTypeSubtypes = {
|
||||||
BB_REFERENCE: {
|
BB_REFERENCE: {
|
||||||
USER: FieldSubtype.USER,
|
USER: FieldSubtype.USER as FieldSubtype.USER,
|
||||||
USERS: FieldSubtype.USERS,
|
USERS: FieldSubtype.USERS as FieldSubtype.USERS,
|
||||||
|
},
|
||||||
|
ATTACHMENT: {
|
||||||
|
SINGLE: FieldSubtype.SINGLE as FieldSubtype.SINGLE,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -112,6 +112,12 @@ export interface BBReferenceFieldMetadata
|
||||||
relationshipType?: RelationshipType
|
relationshipType?: RelationshipType
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface AttachmentFieldMetadata
|
||||||
|
extends Omit<BaseFieldSchema, "subtype"> {
|
||||||
|
type: FieldType.ATTACHMENT
|
||||||
|
subtype?: FieldSubtype.SINGLE
|
||||||
|
}
|
||||||
|
|
||||||
export interface FieldConstraints {
|
export interface FieldConstraints {
|
||||||
type?: string
|
type?: string
|
||||||
email?: boolean
|
email?: boolean
|
||||||
|
@ -119,6 +125,7 @@ export interface FieldConstraints {
|
||||||
length?: {
|
length?: {
|
||||||
minimum?: string | number | null
|
minimum?: string | number | null
|
||||||
maximum?: string | number | null
|
maximum?: string | number | null
|
||||||
|
message?: string
|
||||||
}
|
}
|
||||||
numericality?: {
|
numericality?: {
|
||||||
greaterThanOrEqualTo: string | null
|
greaterThanOrEqualTo: string | null
|
||||||
|
@ -156,6 +163,8 @@ interface OtherFieldMetadata extends BaseFieldSchema {
|
||||||
| FieldType.FORMULA
|
| FieldType.FORMULA
|
||||||
| FieldType.NUMBER
|
| FieldType.NUMBER
|
||||||
| FieldType.LONGFORM
|
| FieldType.LONGFORM
|
||||||
|
| FieldType.BB_REFERENCE
|
||||||
|
| FieldType.ATTACHMENT
|
||||||
>
|
>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -169,6 +178,7 @@ export type FieldSchema =
|
||||||
| LongFormFieldMetadata
|
| LongFormFieldMetadata
|
||||||
| BBReferenceFieldMetadata
|
| BBReferenceFieldMetadata
|
||||||
| JsonFieldMetadata
|
| JsonFieldMetadata
|
||||||
|
| AttachmentFieldMetadata
|
||||||
|
|
||||||
export interface TableSchema {
|
export interface TableSchema {
|
||||||
[key: string]: FieldSchema
|
[key: string]: FieldSchema
|
||||||
|
@ -203,3 +213,9 @@ export function isBBReferenceField(
|
||||||
): field is BBReferenceFieldMetadata {
|
): field is BBReferenceFieldMetadata {
|
||||||
return field.type === FieldType.BB_REFERENCE
|
return field.type === FieldType.BB_REFERENCE
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function isAttachmentField(
|
||||||
|
field: FieldSchema
|
||||||
|
): field is AttachmentFieldMetadata {
|
||||||
|
return field.type === FieldType.ATTACHMENT
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue