Revert "Single attachment column type"

This commit is contained in:
Michael Drury 2024-04-03 16:01:45 +01:00 committed by GitHub
parent d8afb0f58c
commit 1cfe4da027
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
29 changed files with 73 additions and 200 deletions

View File

@ -67,7 +67,7 @@
}
$: showDropzone =
(!maximum || (maximum && (value?.length || 0) < maximum)) && !disabled
(!maximum || (maximum && value?.length < maximum)) && !disabled
async function processFileList(fileList) {
if (

View File

@ -9,7 +9,7 @@ const MAX_DEPTH = 1
const TYPES_TO_SKIP = [
FieldType.FORMULA,
FieldType.LONGFORM,
FieldType.ATTACHMENTS,
FieldType.ATTACHMENT,
//https://github.com/Budibase/budibase/issues/3030
FieldType.INTERNAL,
]

View File

@ -394,8 +394,7 @@
FIELDS.BIGINT,
FIELDS.BOOLEAN,
FIELDS.DATETIME,
FIELDS.ATTACHMENT_SINGLE,
FIELDS.ATTACHMENTS,
FIELDS.ATTACHMENT,
FIELDS.LINK,
FIELDS.FORMULA,
FIELDS.JSON,

View File

@ -41,8 +41,7 @@ export const FieldTypeToComponentMap = {
[FieldType.BOOLEAN]: "booleanfield",
[FieldType.LONGFORM]: "longformfield",
[FieldType.DATETIME]: "datetimefield",
[FieldType.ATTACHMENTS]: "attachmentfield",
[FieldType.ATTACHMENT_SINGLE]: "attachmentsinglefield",
[FieldType.ATTACHMENT]: "attachmentfield",
[FieldType.LINK]: "relationshipfield",
[FieldType.JSON]: "jsonfield",
[FieldType.BARCODEQR]: "codescanner",

View File

@ -107,18 +107,10 @@ export const FIELDS = {
},
},
},
ATTACHMENT_SINGLE: {
ATTACHMENT: {
name: "Attachment",
type: FieldType.ATTACHMENT_SINGLE,
icon: "Document",
constraints: {
presence: false,
},
},
ATTACHMENTS: {
name: "Attachment List",
type: FieldType.ATTACHMENTS,
icon: "AppleFiles",
type: FieldType.ATTACHMENT,
icon: "Folder",
constraints: {
type: "array",
presence: false,
@ -307,7 +299,7 @@ export const PaginationLocations = [
export const BannedSearchTypes = [
FieldType.LINK,
FieldType.ATTACHMENTS,
FieldType.ATTACHMENT,
FieldType.FORMULA,
FieldType.JSON,
"jsonarray",

View File

@ -1,6 +1,9 @@
{
"extends": "./tsconfig.build.json",
"compilerOptions": {
"composite": true,
"declaration": true,
"sourceMap": true,
"baseUrl": ".",
"paths": {
"assets/*": ["./assets/*"],

View File

@ -4226,7 +4226,7 @@
]
},
"attachmentfield": {
"name": "Attachment list",
"name": "Attachment",
"icon": "Attach",
"styles": ["size"],
"requiredAncestors": ["form"],
@ -4322,103 +4322,6 @@
}
]
},
"attachmentsinglefield": {
"name": "Single Attachment",
"icon": "Attach",
"styles": ["size"],
"requiredAncestors": ["form"],
"editable": true,
"size": {
"width": 400,
"height": 200
},
"settings": [
{
"type": "field/attachment_single",
"label": "Field",
"key": "field",
"required": true
},
{
"type": "text",
"label": "Label",
"key": "label"
},
{
"type": "text",
"label": "Help text",
"key": "helpText"
},
{
"type": "text",
"label": "Extensions",
"key": "extensions"
},
{
"type": "number",
"label": "Max attachments",
"key": "maximum",
"min": 1
},
{
"type": "event",
"label": "On change",
"key": "onChange",
"context": [
{
"label": "Field Value",
"key": "value"
}
]
},
{
"type": "boolean",
"label": "Compact",
"key": "compact",
"defaultValue": false
},
{
"type": "boolean",
"label": "Read only",
"key": "disabled",
"defaultValue": false
},
{
"type": "validation/attachment",
"label": "Validation",
"key": "validation"
},
{
"type": "select",
"label": "Layout",
"key": "span",
"defaultValue": 6,
"hidden": true,
"showInBar": true,
"barStyle": "buttons",
"options": [
{
"label": "1 column",
"value": 6,
"barIcon": "Stop",
"barTitle": "1 column"
},
{
"label": "2 columns",
"value": 3,
"barIcon": "ColumnTwoA",
"barTitle": "2 columns"
},
{
"label": "3 columns",
"value": 2,
"barIcon": "ViewColumn",
"barTitle": "3 columns"
}
]
}
]
},
"relationshipfield": {
"name": "Relationship Picker",
"icon": "TaskList",

View File

@ -15,8 +15,7 @@
[FieldType.BOOLEAN]: "booleanfield",
[FieldType.LONGFORM]: "longformfield",
[FieldType.DATETIME]: "datetimefield",
[FieldType.ATTACHMENTS]: "attachmentfield",
[FieldType.ATTACHMENT_SINGLE]: "attachmentsinglefield",
[FieldType.ATTACHMENT]: "attachmentfield",
[FieldType.LINK]: "relationshipfield",
[FieldType.JSON]: "jsonfield",
[FieldType.BARCODEQR]: "codescanner",
@ -61,7 +60,7 @@
function getPropsByType(field) {
const propsMapByType = {
[FieldType.ATTACHMENTS]: (_field, schema) => {
[FieldType.ATTACHMENT]: (_field, schema) => {
return {
maximum: schema?.constraints?.length?.maximum,
}

View File

@ -1,7 +1,6 @@
<script>
import Field from "./Field.svelte"
import { CoreDropzone } from "@budibase/bbui"
import { FieldType } from "@budibase/types"
import { getContext } from "svelte"
export let field
@ -15,11 +14,6 @@
export let maximum = undefined
export let span
export let helpText = null
export let type = FieldType.ATTACHMENTS
export let fieldApiMapper = {
get: value => value,
set: value => value,
}
let fieldState
let fieldApi
@ -69,10 +63,9 @@
}
const handleChange = e => {
const value = fieldApiMapper.set(e.detail)
const changed = fieldApi.setValue(value)
const changed = fieldApi.setValue(e.detail)
if (onChange && changed) {
onChange({ value })
onChange({ value: e.detail })
}
}
</script>
@ -85,14 +78,14 @@
{validation}
{span}
{helpText}
{type}
type="attachment"
bind:fieldState
bind:fieldApi
defaultValue={[]}
>
{#if fieldState}
<CoreDropzone
value={fieldApiMapper.get(fieldState.value)}
value={fieldState.value}
disabled={fieldState.disabled || fieldState.readonly}
error={fieldState.error}
on:change={handleChange}

View File

@ -1,16 +0,0 @@
<script>
import { FieldType } from "@budibase/types"
import AttachmentField from "./AttachmentField.svelte"
const fieldApiMapper = {
get: value => (!Array.isArray(value) && value ? [value] : value) || [],
set: value => value[0] || null,
}
</script>
<AttachmentField
{...$$restProps}
type={FieldType.ATTACHMENT_SINGLE}
maximum={1}
{fieldApiMapper}
/>

View File

@ -9,7 +9,6 @@ export { default as booleanfield } from "./BooleanField.svelte"
export { default as longformfield } from "./LongFormField.svelte"
export { default as datetimefield } from "./DateTimeField.svelte"
export { default as attachmentfield } from "./AttachmentField.svelte"
export { default as attachmentsinglefield } from "./AttachmentSingleField.svelte"
export { default as relationshipfield } from "./RelationshipField.svelte"
export { default as passwordfield } from "./PasswordField.svelte"
export { default as formstep } from "./FormStep.svelte"

View File

@ -192,7 +192,7 @@ const parseType = (value, type) => {
}
// Parse attachments, treating no elements as null
if (type === FieldTypes.ATTACHMENTS) {
if (type === FieldTypes.ATTACHMENT) {
if (!Array.isArray(value) || !value.length) {
return null
}

View File

@ -10,7 +10,6 @@
export let invertX = false
export let invertY = false
export let schema
export let maximum
const { API, notifications } = getContext("grid")
const imageExtensions = ["png", "tiff", "gif", "raw", "jpg", "jpeg"]
@ -99,7 +98,7 @@
{value}
compact
on:change={e => onChange(e.detail)}
maximum={maximum || schema.constraints?.length?.maximum}
maximum={schema.constraints?.length?.maximum}
{processFiles}
{deleteAttachments}
{handleFileTooLarge}

View File

@ -1,20 +0,0 @@
<script>
import AttachmentCell from "./AttachmentCell.svelte"
export let value
export let onChange
$: arrayValue = (!Array.isArray(value) && value ? [value] : value) || []
$: onFileChange = value => {
value = value[0] || null
onChange(value)
}
</script>
<AttachmentCell
{...$$restProps}
maximum={1}
value={arrayValue}
onChange={onFileChange}
/>

View File

@ -11,7 +11,6 @@ import BooleanCell from "../cells/BooleanCell.svelte"
import FormulaCell from "../cells/FormulaCell.svelte"
import JSONCell from "../cells/JSONCell.svelte"
import AttachmentCell from "../cells/AttachmentCell.svelte"
import AttachmentSingleCell from "../cells/AttachmentSingleCell.svelte"
import BBReferenceCell from "../cells/BBReferenceCell.svelte"
const TypeComponentMap = {
@ -23,8 +22,7 @@ const TypeComponentMap = {
[FieldType.ARRAY]: MultiSelectCell,
[FieldType.NUMBER]: NumberCell,
[FieldType.BOOLEAN]: BooleanCell,
[FieldType.ATTACHMENTS]: AttachmentCell,
[FieldType.ATTACHMENT_SINGLE]: AttachmentSingleCell,
[FieldType.ATTACHMENT]: AttachmentCell,
[FieldType.LINK]: RelationshipCell,
[FieldType.FORMULA]: FormulaCell,
[FieldType.JSON]: JSONCell,

View File

@ -16,8 +16,7 @@ const TypeIconMap = {
[FieldType.ARRAY]: "Dropdown",
[FieldType.NUMBER]: "123",
[FieldType.BOOLEAN]: "Boolean",
[FieldType.ATTACHMENTS]: "AppleFiles",
[FieldType.ATTACHMENT_SINGLE]: "Document",
[FieldType.ATTACHMENT]: "AppleFiles",
[FieldType.LINK]: "DataCorrelated",
[FieldType.FORMULA]: "Calculator",
[FieldType.JSON]: "Brackets",

View File

@ -30,6 +30,8 @@ import {
View,
RelationshipFieldMetadata,
FieldType,
FieldTypeSubtypes,
AttachmentFieldMetadata,
} from "@budibase/types"
export async function clearColumns(table: Table, columnNames: string[]) {
@ -89,6 +91,26 @@ export async function checkForColumnUpdates(
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 }
}

View File

@ -234,7 +234,7 @@ describe.each([
constraints: { type: "string", presence: false },
}
const attachment: FieldSchema = {
type: FieldType.ATTACHMENTS,
type: FieldType.ATTACHMENT,
name: "attachment",
constraints: { type: "array", presence: false },
}
@ -790,7 +790,7 @@ describe.each([
defaultTable({
schema: {
attachment: {
type: FieldType.ATTACHMENTS,
type: FieldType.ATTACHMENT,
name: "attachment",
constraints: { type: "array", presence: false },
},

View File

@ -299,7 +299,7 @@ export const DEFAULT_EMPLOYEE_TABLE_SCHEMA: Table = {
sortable: false,
},
"Badge Photo": {
type: FieldType.ATTACHMENTS,
type: FieldType.ATTACHMENT,
constraints: {
type: FieldType.ARRAY,
presence: false,
@ -607,7 +607,7 @@ export const DEFAULT_EXPENSES_TABLE_SCHEMA: Table = {
ignoreTimezones: true,
},
Attachment: {
type: FieldType.ATTACHMENTS,
type: FieldType.ATTACHMENT,
constraints: {
type: FieldType.ARRAY,
presence: false,

View File

@ -30,7 +30,7 @@ export async function getRowsWithAttachments(appId: string, table: Table) {
const db = dbCore.getDB(appId)
const attachmentCols: string[] = []
for (let [key, column] of Object.entries(table.schema)) {
if (column.type === FieldType.ATTACHMENTS) {
if (column.type === FieldType.ATTACHMENT) {
attachmentCols.push(key)
}
}

View File

@ -175,13 +175,13 @@ export async function validate({
errors[fieldName] = [`${fieldName} is required`]
}
} else if (
(type === FieldType.ATTACHMENTS || type === FieldType.JSON) &&
(type === FieldType.ATTACHMENT || type === FieldType.JSON) &&
typeof row[fieldName] === "string"
) {
// this should only happen if there is an error
try {
const json = JSON.parse(row[fieldName])
if (type === FieldType.ATTACHMENTS) {
if (type === FieldType.ATTACHMENT) {
if (Array.isArray(json)) {
row[fieldName] = json
} else {

View File

@ -34,7 +34,7 @@ export class AttachmentCleanup {
let files: string[] = []
const tableSchema = opts.oldTable?.schema || table.schema
for (let [key, schema] of Object.entries(tableSchema)) {
if (schema.type !== FieldType.ATTACHMENTS) {
if (schema.type !== FieldType.ATTACHMENT) {
continue
}
const columnRemoved = opts.oldTable && !table.schema[key]
@ -68,7 +68,7 @@ export class AttachmentCleanup {
return AttachmentCleanup.coreCleanup(() => {
let files: string[] = []
for (let [key, schema] of Object.entries(table.schema)) {
if (schema.type !== FieldType.ATTACHMENTS) {
if (schema.type !== FieldType.ATTACHMENT) {
continue
}
rows.forEach(row => {
@ -88,7 +88,7 @@ export class AttachmentCleanup {
return AttachmentCleanup.coreCleanup(() => {
let files: string[] = []
for (let [key, schema] of Object.entries(table.schema)) {
if (schema.type !== FieldType.ATTACHMENTS) {
if (schema.type !== FieldType.ATTACHMENT) {
continue
}
const oldKeys =

View File

@ -148,7 +148,7 @@ export async function inputProcessing(
}
// remove any attachment urls, they are generated on read
if (field.type === FieldType.ATTACHMENTS) {
if (field.type === FieldType.ATTACHMENT) {
const attachments = clonedRow[key]
if (attachments?.length) {
attachments.forEach((attachment: RowAttachment) => {
@ -216,7 +216,7 @@ export async function outputProcessing<T extends Row[] | Row>(
// process complex types: attachements, bb references...
for (let [property, column] of Object.entries(table.schema)) {
if (column.type === FieldType.ATTACHMENTS) {
if (column.type === FieldType.ATTACHMENT) {
for (let row of enriched) {
if (row[property] == null || !Array.isArray(row[property])) {
continue

View File

@ -106,7 +106,7 @@ export const TYPE_TRANSFORM_MAP: any = {
return date
},
},
[FieldType.ATTACHMENTS]: {
[FieldType.ATTACHMENT]: {
//@ts-ignore
[null]: [],
//@ts-ignore

View File

@ -34,7 +34,7 @@ function table(): Table {
schema: {
attach: {
name: "attach",
type: FieldType.ATTACHMENTS,
type: FieldType.ATTACHMENT,
constraints: {},
},
},

View File

@ -82,7 +82,7 @@ describe("rowProcessor - outputProcessing", () => {
sourceType: TableSourceType.INTERNAL,
schema: {
attach: {
type: FieldType.ATTACHMENTS,
type: FieldType.ATTACHMENT,
name: "attach",
constraints: {},
},

View File

@ -11,10 +11,10 @@ const allowDisplayColumnByType: Record<FieldType, boolean> = {
[FieldType.INTERNAL]: true,
[FieldType.BARCODEQR]: true,
[FieldType.BIGINT]: true,
[FieldType.BOOLEAN]: false,
[FieldType.ARRAY]: false,
[FieldType.ATTACHMENTS]: false,
[FieldType.ATTACHMENT_SINGLE]: false,
[FieldType.ATTACHMENT]: false,
[FieldType.LINK]: false,
[FieldType.JSON]: false,
[FieldType.BB_REFERENCE]: false,
@ -34,8 +34,7 @@ const allowSortColumnByType: Record<FieldType, boolean> = {
[FieldType.JSON]: true,
[FieldType.FORMULA]: false,
[FieldType.ATTACHMENTS]: false,
[FieldType.ATTACHMENT_SINGLE]: false,
[FieldType.ATTACHMENT]: false,
[FieldType.ARRAY]: false,
[FieldType.LINK]: false,
[FieldType.BB_REFERENCE]: false,

View File

@ -8,8 +8,7 @@ export enum FieldType {
BOOLEAN = "boolean",
ARRAY = "array",
DATETIME = "datetime",
ATTACHMENTS = "attachment",
ATTACHMENT_SINGLE = "attachment_single",
ATTACHMENT = "attachment",
LINK = "link",
FORMULA = "formula",
AUTO = "auto",
@ -39,6 +38,7 @@ 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
@ -47,4 +47,7 @@ export const FieldTypeSubtypes = {
USER: FieldSubtype.USER as FieldSubtype.USER,
USERS: FieldSubtype.USERS as FieldSubtype.USERS,
},
ATTACHMENT: {
SINGLE: FieldSubtype.SINGLE as FieldSubtype.SINGLE,
},
}

View File

@ -112,8 +112,10 @@ export interface BBReferenceFieldMetadata
relationshipType?: RelationshipType
}
export interface AttachmentFieldMetadata extends BaseFieldSchema {
type: FieldType.ATTACHMENTS
export interface AttachmentFieldMetadata
extends Omit<BaseFieldSchema, "subtype"> {
type: FieldType.ATTACHMENT
subtype?: FieldSubtype.SINGLE
}
export interface FieldConstraints {
@ -162,7 +164,7 @@ interface OtherFieldMetadata extends BaseFieldSchema {
| FieldType.NUMBER
| FieldType.LONGFORM
| FieldType.BB_REFERENCE
| FieldType.ATTACHMENTS
| FieldType.ATTACHMENT
>
}
@ -215,5 +217,5 @@ export function isBBReferenceField(
export function isAttachmentField(
field: FieldSchema
): field is AttachmentFieldMetadata {
return field.type === FieldType.ATTACHMENTS
return field.type === FieldType.ATTACHMENT
}