diff --git a/packages/client/src/utils/buttonActions.js b/packages/client/src/utils/buttonActions.js index 17121f3ee6..594bee6953 100644 --- a/packages/client/src/utils/buttonActions.js +++ b/packages/client/src/utils/buttonActions.js @@ -241,23 +241,6 @@ const s3UploadHandler = async action => { } } -const convertToCsv = (headers, rows) => { - let csv = headers.map(key => `"${key}"`).join(",") - - for (let row of rows) { - csv = `${csv}\n${headers - .map(header => { - let val = row[header] - val = - typeof val === "object" - ? `"${JSON.stringify(val).replace(/"/g, "'")}"` - : `"${val}"` - return val.trim() - }) - .join(",")}` - } - return csv -} const exportDataHandler = async action => { let selection = rowSelectionStore.actions.getSelection( @@ -268,16 +251,9 @@ const exportDataHandler = async action => { const data = await API.exportRows({ tableId: selection.tableId, rows: selection.selectedRows, + format: action.parameters.type, }) - - let dataToExport - const headers = Object.keys(data[0]) - if (action.parameters.type === "csv") { - dataToExport = convertToCsv(headers, data) - } else { - dataToExport = JSON.stringify(data) - } - download(dataToExport, `export.${action.parameters.type}`) + download(data, `${selection.tableId}.${action.parameters.type}`) } catch (error) { notificationStore.actions.error("There was an error exporting the data") } diff --git a/packages/frontend-core/src/api/rows.js b/packages/frontend-core/src/api/rows.js index 1b6efe624f..6a0d278cf7 100644 --- a/packages/frontend-core/src/api/rows.js +++ b/packages/frontend-core/src/api/rows.js @@ -66,12 +66,15 @@ export const buildRowEndpoints = API => ({ * @param tableId the table ID to export the rows from * @param rows the array of rows to export */ - exportRows: async ({ tableId, rows }) => { + exportRows: async ({ tableId, rows, format }) => { return await API.post({ - url: `/api/${tableId}/rows/exportRows`, + url: `/api/${tableId}/rows/exportRows?format=${format}`, body: { rows, }, + parseResponse: async response => { + return await response.text() + }, }) }, }) diff --git a/packages/server/src/api/controllers/row/external.js b/packages/server/src/api/controllers/row/external.js index aebcfce724..2f816e11a9 100644 --- a/packages/server/src/api/controllers/row/external.js +++ b/packages/server/src/api/controllers/row/external.js @@ -10,6 +10,8 @@ const { } = require("../../../integrations/utils") const ExternalRequest = require("./ExternalRequest") const { getAppDB } = require("@budibase/backend-core/context") +const exporters = require("../view/exporters") +const { apiFileReturn } = require("../../../utilities/fileSystem") async function handleRequest(operation, tableId, opts = {}) { // make sure the filters are cleaned up, no empty strings for equals, fuzzy or string @@ -155,6 +157,7 @@ exports.validate = async () => { exports.exportRows = async ctx => { const { datasourceId, tableName } = breakExternalTableId(ctx.params.tableId) const db = getAppDB() + let format = ctx.query.format const datasource = await db.get(datasourceId) if (!datasource || !datasource.entities) { ctx.throw(400, "Datasource has not been configured for plus API.") @@ -164,13 +167,22 @@ exports.exportRows = async ctx => { ctx.request.body = { query: { oneOf: { - [table.primaryDisplay]: ctx.request.body.map( + [table.primaryDisplay]: ctx.request.body.rows.map( id => breakRowIdField(id)[0] ), }, }, } - return exports.search(ctx) + + let result = await exports.search(ctx) + + let headers = Object.keys(result.rows[0]) + const exporter = exporters[format] + const filename = `export.${format}` + + // send down the file + ctx.attachment(filename) + return apiFileReturn(exporter(headers, result.rows)) } exports.fetchEnrichedRow = async ctx => { diff --git a/packages/server/src/api/controllers/row/internal.js b/packages/server/src/api/controllers/row/internal.js index 068a485a8a..4b57e09029 100644 --- a/packages/server/src/api/controllers/row/internal.js +++ b/packages/server/src/api/controllers/row/internal.js @@ -27,6 +27,8 @@ const { const { cloneDeep } = require("lodash/fp") const { getAppDB } = require("@budibase/backend-core/context") const { finaliseRow, updateRelatedFormula } = require("./staticFormula") +const exporters = require("../view/exporters") +const { apiFileReturn } = require("../../../utilities/fileSystem") const CALCULATION_TYPES = { SUM: "sum", @@ -366,6 +368,7 @@ exports.exportRows = async ctx => { const db = getAppDB() const table = await db.get(ctx.params.tableId) const rowIds = ctx.request.body.rows + let format = ctx.query.format let response = ( await db.allDocs({ include_docs: true, @@ -374,8 +377,14 @@ exports.exportRows = async ctx => { ).rows.map(row => row.doc) let rows = await outputProcessing(table, response) - - return rows + + let headers = Object.keys(rows[0]) + const exporter = exporters[format] + const filename = `export.${format}` + + // send down the file + ctx.attachment(filename) + return apiFileReturn(exporter(headers, rows)) } exports.fetchEnrichedRow = async ctx => {