Fixing some issues with updating rows with attachments, there were some UI bugs that had been raised (undefined being displayed) and the uploading from a URL was not working as expected, due to the stream not matching the expected format of the S3 SDK - this has been fixed by converting the stream to a true readable stream with .
This commit is contained in:
parent
9c312826ca
commit
5b5e7e47a2
7 changed files with 70 additions and 54 deletions
|
@ -9,6 +9,9 @@ import {
|
||||||
AutomationAttachmentContent,
|
AutomationAttachmentContent,
|
||||||
BucketedContent,
|
BucketedContent,
|
||||||
} from "@budibase/types"
|
} from "@budibase/types"
|
||||||
|
import stream from "stream"
|
||||||
|
import streamWeb from "node:stream/web"
|
||||||
|
|
||||||
/****************************************************
|
/****************************************************
|
||||||
* NOTE: When adding a new bucket - name *
|
* NOTE: When adding a new bucket - name *
|
||||||
* sure that S3 usages (like budibase-infra) *
|
* sure that S3 usages (like budibase-infra) *
|
||||||
|
@ -53,12 +56,10 @@ export const bucketTTLConfig = (
|
||||||
Rules: [lifecycleRule],
|
Rules: [lifecycleRule],
|
||||||
}
|
}
|
||||||
|
|
||||||
const params = {
|
return {
|
||||||
Bucket: bucketName,
|
Bucket: bucketName,
|
||||||
LifecycleConfiguration: lifecycleConfiguration,
|
LifecycleConfiguration: lifecycleConfiguration,
|
||||||
}
|
}
|
||||||
|
|
||||||
return params
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function processUrlAttachment(
|
async function processUrlAttachment(
|
||||||
|
@ -71,7 +72,7 @@ async function processUrlAttachment(
|
||||||
const fallbackFilename = path.basename(new URL(attachment.url).pathname)
|
const fallbackFilename = path.basename(new URL(attachment.url).pathname)
|
||||||
return {
|
return {
|
||||||
filename: attachment.filename || fallbackFilename,
|
filename: attachment.filename || fallbackFilename,
|
||||||
content: response.body,
|
content: stream.Readable.fromWeb(response.body as streamWeb.ReadableStream),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -374,6 +374,16 @@
|
||||||
return `${value.title || (key === "row" ? "Table" : key)} ${requiredSuffix}`
|
return `${value.title || (key === "row" ? "Table" : key)} ${requiredSuffix}`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleAttachmentParams(keyValueObj) {
|
||||||
|
let params = {}
|
||||||
|
if (keyValueObj?.length) {
|
||||||
|
for (let param of keyValueObj) {
|
||||||
|
params[param.url] = param.filename
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return params
|
||||||
|
}
|
||||||
|
|
||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
try {
|
try {
|
||||||
await environment.loadVariables()
|
await environment.loadVariables()
|
||||||
|
@ -381,15 +391,6 @@
|
||||||
console.error(error)
|
console.error(error)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
const handleAttachmentParams = keyValuObj => {
|
|
||||||
let params = {}
|
|
||||||
if (keyValuObj?.length) {
|
|
||||||
for (let param of keyValuObj) {
|
|
||||||
params[param.url] = param.filename
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return params
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="fields">
|
<div class="fields">
|
||||||
|
|
|
@ -25,21 +25,21 @@
|
||||||
return !!schema.constraints?.inclusion?.length
|
return !!schema.constraints?.inclusion?.length
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleAttachmentParams = keyValuObj => {
|
function handleAttachmentParams(keyValueObj) {
|
||||||
let params = {}
|
let params = {}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
schema.type === FieldType.ATTACHMENT_SINGLE &&
|
schema.type === FieldType.ATTACHMENT_SINGLE &&
|
||||||
Object.keys(keyValuObj).length === 0
|
Object.keys(keyValueObj).length === 0
|
||||||
) {
|
) {
|
||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
if (!Array.isArray(keyValuObj)) {
|
if (!Array.isArray(keyValueObj) && keyValueObj) {
|
||||||
keyValuObj = [keyValuObj]
|
keyValueObj = [keyValueObj]
|
||||||
}
|
}
|
||||||
|
|
||||||
if (keyValuObj.length) {
|
if (keyValueObj.length) {
|
||||||
for (let param of keyValuObj) {
|
for (let param of keyValueObj) {
|
||||||
params[param.url] = param.filename
|
params[param.url] = param.filename
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -163,7 +163,7 @@ async function generateAttachmentRow(attachment: AutomationAttachment) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const { filename } = attachment
|
const { filename } = attachment
|
||||||
const extension = path.extname(filename)
|
const extension = path.extname(filename).replaceAll(".", "")
|
||||||
const attachmentResult = await objectStore.processAutomationAttachment(
|
const attachmentResult = await objectStore.processAutomationAttachment(
|
||||||
attachment
|
attachment
|
||||||
)
|
)
|
||||||
|
@ -183,7 +183,7 @@ async function generateAttachmentRow(attachment: AutomationAttachment) {
|
||||||
return {
|
return {
|
||||||
size,
|
size,
|
||||||
name: filename,
|
name: filename,
|
||||||
extension,
|
extension: extension,
|
||||||
key: s3Key,
|
key: s3Key,
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|
|
@ -94,18 +94,6 @@ export async function run({ inputs, appId, emitter }: AutomationStepInput) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// have to clean up the row, remove the table from it
|
|
||||||
const ctx: any = buildCtx(appId, emitter, {
|
|
||||||
body: {
|
|
||||||
...inputs.row,
|
|
||||||
_id: inputs.rowId,
|
|
||||||
},
|
|
||||||
params: {
|
|
||||||
rowId: inputs.rowId,
|
|
||||||
tableId: tableId,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (tableId) {
|
if (tableId) {
|
||||||
inputs.row = await automationUtils.cleanUpRow(
|
inputs.row = await automationUtils.cleanUpRow(
|
||||||
|
@ -118,6 +106,17 @@ export async function run({ inputs, appId, emitter }: AutomationStepInput) {
|
||||||
inputs.row
|
inputs.row
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
// have to clean up the row, remove the table from it
|
||||||
|
const ctx: any = buildCtx(appId, emitter, {
|
||||||
|
body: {
|
||||||
|
...inputs.row,
|
||||||
|
_id: inputs.rowId,
|
||||||
|
},
|
||||||
|
params: {
|
||||||
|
rowId: inputs.rowId,
|
||||||
|
tableId: tableId,
|
||||||
|
},
|
||||||
|
})
|
||||||
await rowController.patch(ctx)
|
await rowController.patch(ctx)
|
||||||
return {
|
return {
|
||||||
row: ctx.body,
|
row: ctx.body,
|
||||||
|
|
|
@ -1,6 +1,12 @@
|
||||||
import { ObjectStoreBuckets } from "../../constants"
|
import { ObjectStoreBuckets } from "../../constants"
|
||||||
import { context, db as dbCore, objectStore } from "@budibase/backend-core"
|
import { context, db as dbCore, objectStore } from "@budibase/backend-core"
|
||||||
import { FieldType, RenameColumn, Row, Table } from "@budibase/types"
|
import {
|
||||||
|
FieldType,
|
||||||
|
RenameColumn,
|
||||||
|
Row,
|
||||||
|
RowAttachment,
|
||||||
|
Table,
|
||||||
|
} from "@budibase/types"
|
||||||
|
|
||||||
export class AttachmentCleanup {
|
export class AttachmentCleanup {
|
||||||
static async coreCleanup(fileListFn: () => string[]): Promise<void> {
|
static async coreCleanup(fileListFn: () => string[]): Promise<void> {
|
||||||
|
@ -21,7 +27,7 @@ export class AttachmentCleanup {
|
||||||
|
|
||||||
private static extractAttachmentKeys(
|
private static extractAttachmentKeys(
|
||||||
type: FieldType,
|
type: FieldType,
|
||||||
rowData: any
|
rowData: RowAttachment[] | RowAttachment
|
||||||
): string[] {
|
): string[] {
|
||||||
if (
|
if (
|
||||||
type !== FieldType.ATTACHMENTS &&
|
type !== FieldType.ATTACHMENTS &&
|
||||||
|
@ -34,10 +40,15 @@ export class AttachmentCleanup {
|
||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type === FieldType.ATTACHMENTS) {
|
if (type === FieldType.ATTACHMENTS && Array.isArray(rowData)) {
|
||||||
return rowData.map((attachment: any) => attachment.key)
|
return rowData
|
||||||
|
.filter(attachment => attachment.key)
|
||||||
|
.map(attachment => attachment.key)
|
||||||
|
} else if ("key" in rowData) {
|
||||||
|
return [rowData.key]
|
||||||
}
|
}
|
||||||
return [rowData.key]
|
|
||||||
|
return []
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async tableChange(
|
private static async tableChange(
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
import * as linkRows from "../../db/linkedRows"
|
import * as linkRows from "../../db/linkedRows"
|
||||||
import { processFormulas, fixAutoColumnSubType } from "./utils"
|
import { fixAutoColumnSubType, processFormulas } from "./utils"
|
||||||
import { objectStore, utils } from "@budibase/backend-core"
|
import { objectStore, utils } from "@budibase/backend-core"
|
||||||
import { InternalTables } from "../../db/utils"
|
import { InternalTables } from "../../db/utils"
|
||||||
import { TYPE_TRANSFORM_MAP } from "./map"
|
import { TYPE_TRANSFORM_MAP } from "./map"
|
||||||
import {
|
import {
|
||||||
FieldType,
|
|
||||||
AutoFieldSubType,
|
AutoFieldSubType,
|
||||||
|
FieldType,
|
||||||
Row,
|
Row,
|
||||||
RowAttachment,
|
RowAttachment,
|
||||||
Table,
|
Table,
|
||||||
|
@ -221,27 +221,31 @@ export async function outputProcessing<T extends Row[] | Row>(
|
||||||
opts.squash = true
|
opts.squash = true
|
||||||
}
|
}
|
||||||
|
|
||||||
// process complex types: attachements, bb references...
|
// process complex types: attachments, bb references...
|
||||||
for (let [property, column] of Object.entries(table.schema)) {
|
for (let [property, column] of Object.entries(table.schema)) {
|
||||||
if (column.type === FieldType.ATTACHMENTS) {
|
if (
|
||||||
|
column.type === FieldType.ATTACHMENTS ||
|
||||||
|
column.type === FieldType.ATTACHMENT_SINGLE
|
||||||
|
) {
|
||||||
for (let row of enriched) {
|
for (let row of enriched) {
|
||||||
if (row[property] == null || !Array.isArray(row[property])) {
|
if (row[property] == null) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
row[property].forEach((attachment: RowAttachment) => {
|
const process = (attachment: RowAttachment) => {
|
||||||
if (!attachment.url) {
|
if (!attachment.url && attachment.key) {
|
||||||
attachment.url = objectStore.getAppFileUrl(attachment.key)
|
attachment.url = objectStore.getAppFileUrl(attachment.key)
|
||||||
}
|
}
|
||||||
})
|
return attachment
|
||||||
}
|
|
||||||
} else if (column.type === FieldType.ATTACHMENT_SINGLE) {
|
|
||||||
for (let row of enriched) {
|
|
||||||
if (!row[property] || Object.keys(row[property]).length === 0) {
|
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
|
if (typeof row[property] === "string") {
|
||||||
if (!row[property].url) {
|
row[property] = JSON.parse(row[property])
|
||||||
row[property].url = objectStore.getAppFileUrl(row[property].key)
|
}
|
||||||
|
if (Array.isArray(row[property])) {
|
||||||
|
row[property].forEach((attachment: RowAttachment) => {
|
||||||
|
process(attachment)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
process(row[property])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (
|
} else if (
|
||||||
|
|
Loading…
Reference in a new issue