Add option to customise which columns are exported in export data action

This commit is contained in:
Andrew Kingston 2022-06-20 12:32:13 +01:00
parent cdefcbafe2
commit 6845f86689
4 changed files with 66 additions and 24 deletions

View File

@ -1,27 +1,18 @@
<script> <script>
import { Label, Select, Body } from "@budibase/bbui" import { Label, Select, Body, Multiselect } from "@budibase/bbui"
import { findAllMatchingComponents } from "builderStore/componentUtils" import {
findAllMatchingComponents,
findComponent,
} from "builderStore/componentUtils"
import { currentAsset } from "builderStore" import { currentAsset } from "builderStore"
import { onMount } from "svelte" import { onMount } from "svelte"
import {
getDatasourceForProvider,
getSchemaForDatasource,
} from "builderStore/dataBinding"
export let parameters export let parameters
$: tables = findAllMatchingComponents($currentAsset?.props, component =>
component._component.endsWith("table")
).map(table => ({
label: table._instanceName,
value: table._id,
}))
$: tableBlocks = findAllMatchingComponents($currentAsset?.props, component =>
component._component.endsWith("tableblock")
).map(block => ({
label: block._instanceName,
value: `${block._id}-table`,
}))
$: componentOptions = tables.concat(tableBlocks)
const FORMATS = [ const FORMATS = [
{ {
label: "CSV", label: "CSV",
@ -33,6 +24,32 @@
}, },
] ]
$: tables = findAllMatchingComponents($currentAsset?.props, component =>
component._component.endsWith("table")
).map(table => ({
label: table._instanceName,
value: table._id,
}))
$: tableBlocks = findAllMatchingComponents($currentAsset?.props, component =>
component._component.endsWith("tableblock")
).map(block => ({
label: block._instanceName,
value: `${block._id}-table`,
}))
$: componentOptions = tables.concat(tableBlocks)
$: columnOptions = getColumnOptions(parameters.tableComponentId)
const getColumnOptions = tableId => {
// Strip block suffix if block component
if (tableId?.includes("-")) {
tableId = tableId.split("-")[0]
}
const selectedTable = findComponent($currentAsset?.props, tableId)
const datasource = getDatasourceForProvider($currentAsset, selectedTable)
const { schema } = getSchemaForDatasource($currentAsset, datasource)
return Object.keys(schema || {})
}
onMount(() => { onMount(() => {
if (!parameters.type) { if (!parameters.type) {
parameters.type = "csv" parameters.type = "csv"
@ -53,10 +70,16 @@
<Select <Select
bind:value={parameters.tableComponentId} bind:value={parameters.tableComponentId}
options={componentOptions} options={componentOptions}
on:change={() => (parameters.columns = [])}
/> />
<Label small>Export as</Label> <Label small>Export as</Label>
<Select bind:value={parameters.type} options={FORMATS} /> <Select bind:value={parameters.type} options={FORMATS} />
<Label small>Export columns</Label>
<Multiselect
placeholder="All columns"
bind:value={parameters.columns}
options={columnOptions}
/>
</div> </div>
</div> </div>
@ -80,7 +103,7 @@
display: grid; display: grid;
column-gap: var(--spacing-xs); column-gap: var(--spacing-xs);
row-gap: var(--spacing-s); row-gap: var(--spacing-s);
grid-template-columns: 70px 1fr; grid-template-columns: 90px 1fr;
align-items: center; align-items: center;
} }
</style> </style>

View File

@ -270,6 +270,7 @@ const exportDataHandler = async action => {
tableId: selection.tableId, tableId: selection.tableId,
rows: selection.selectedRows, rows: selection.selectedRows,
format: action.parameters.type, format: action.parameters.type,
columns: action.parameters.columns,
}) })
download(data, `${selection.tableId}.${action.parameters.type}`) download(data, `${selection.tableId}.${action.parameters.type}`)
} catch (error) { } catch (error) {

View File

@ -65,12 +65,15 @@ export const buildRowEndpoints = API => ({
* Exports rows. * Exports rows.
* @param tableId the table ID to export the rows from * @param tableId the table ID to export the rows from
* @param rows the array of rows to export * @param rows the array of rows to export
* @param format the format to export (csv or json)
* @param columns which columns to export (all if undefined)
*/ */
exportRows: async ({ tableId, rows, format }) => { exportRows: async ({ tableId, rows, format, columns }) => {
return await API.post({ return await API.post({
url: `/api/${tableId}/rows/exportRows?format=${format}`, url: `/api/${tableId}/rows/exportRows?format=${format}`,
body: { body: {
rows, rows,
columns,
}, },
parseResponse: async response => { parseResponse: async response => {
return await response.text() return await response.text()

View File

@ -157,7 +157,8 @@ exports.validate = async () => {
exports.exportRows = async ctx => { exports.exportRows = async ctx => {
const { datasourceId } = breakExternalTableId(ctx.params.tableId) const { datasourceId } = breakExternalTableId(ctx.params.tableId)
const db = getAppDB() const db = getAppDB()
let format = ctx.query.format const format = ctx.query.format
const { columns } = ctx.request.body
const datasource = await db.get(datasourceId) const datasource = await db.get(datasourceId)
if (!datasource || !datasource.entities) { if (!datasource || !datasource.entities) {
ctx.throw(400, "Datasource has not been configured for plus API.") ctx.throw(400, "Datasource has not been configured for plus API.")
@ -171,13 +172,27 @@ exports.exportRows = async ctx => {
} }
let result = await exports.search(ctx) let result = await exports.search(ctx)
let headers = Object.keys(result.rows[0]) let rows = []
// Filter data to only specified columns if required
if (columns && columns.length) {
for (let i = 0; i < result.rows.length; i++) {
rows[i] = {}
for (let column of columns) {
rows[i][column] = result.rows[i][column]
}
}
} else {
rows = result.rows
}
let headers = Object.keys(rows[0])
const exporter = exporters[format] const exporter = exporters[format]
const filename = `export.${format}` const filename = `export.${format}`
// send down the file // send down the file
ctx.attachment(filename) ctx.attachment(filename)
return apiFileReturn(exporter(headers, result.rows)) return apiFileReturn(exporter(headers, rows))
} }
exports.fetchEnrichedRow = async ctx => { exports.fetchEnrichedRow = async ctx => {