budibase/packages/client/src/components/app/table/Table.svelte

176 lines
4.3 KiB
Svelte

<script>
import { getContext } from "svelte"
import { Table } from "@budibase/bbui"
import SlotRenderer from "./SlotRenderer.svelte"
import { UnsortableTypes } from "../../../constants"
import { onDestroy } from "svelte"
export let dataProvider
export let columns
export let showAutoColumns
export let rowCount
export let quiet
export let size
export let linkRows
export let linkURL
export let linkColumn
export let linkPeek
export let allowSelectRows
export let compact
const component = getContext("component")
const { styleable, getAction, ActionTypes, routeStore, rowSelectionStore } =
getContext("sdk")
const customColumnKey = `custom-${Math.random()}`
const customRenderers = [
{
column: customColumnKey,
component: SlotRenderer,
},
]
let selectedRows = []
$: hasChildren = $component.children
$: loading = dataProvider?.loading ?? false
$: data = dataProvider?.rows || []
$: fullSchema = dataProvider?.schema ?? {}
$: fields = getFields(fullSchema, columns, showAutoColumns)
$: schema = getFilteredSchema(fullSchema, fields, hasChildren)
$: setSorting = getAction(
dataProvider?.id,
ActionTypes.SetDataProviderSorting
)
$: table = dataProvider?.datasource?.type === "table"
$: {
rowSelectionStore.actions.updateSelection(
$component.id,
selectedRows.length ? selectedRows[0].tableId : "",
selectedRows.map(row => row._id)
)
}
const getFields = (schema, customColumns, showAutoColumns) => {
// Check for an invalid column selection
let invalid = false
customColumns?.forEach(column => {
const columnName = typeof column === "string" ? column : column.name
if (schema[columnName] == null) {
invalid = true
}
})
// Use column selection if it exists
if (!invalid && customColumns?.length) {
return customColumns
}
// Otherwise generate columns
let columns = []
let autoColumns = []
Object.entries(schema).forEach(([field, fieldSchema]) => {
if (!fieldSchema?.autocolumn) {
columns.push(field)
} else if (showAutoColumns) {
autoColumns.push(field)
}
})
return columns.concat(autoColumns)
}
const getFilteredSchema = (schema, fields, hasChildren) => {
let newSchema = {}
if (hasChildren) {
newSchema[customColumnKey] = {
displayName: null,
order: 0,
sortable: false,
divider: true,
width: "auto",
preventSelectRow: true,
}
}
fields.forEach(field => {
const columnName = typeof field === "string" ? field : field.name
if (!schema[columnName]) {
return
}
newSchema[columnName] = schema[columnName]
if (UnsortableTypes.includes(schema[columnName].type)) {
newSchema[columnName].sortable = false
}
// Add additional settings like width etc
if (typeof field === "object") {
newSchema[columnName] = {
...newSchema[columnName],
...field,
}
}
})
return newSchema
}
const onSort = e => {
setSorting({
column: e.detail.column,
order: e.detail.order,
})
}
const onClick = e => {
if (!linkRows || !linkURL) {
return
}
const col = linkColumn || "_id"
const id = e.detail?.[col]
if (!id) {
return
}
const split = linkURL.split("/:")
routeStore.actions.navigate(`${split[0]}/${id}`, linkPeek)
}
onDestroy(() => {
rowSelectionStore.actions.updateSelection($component.id, [])
})
</script>
<div use:styleable={$component.styles} class={size}>
<Table
{data}
{schema}
{loading}
{rowCount}
{quiet}
{compact}
{customRenderers}
allowSelectRows={allowSelectRows && table}
bind:selectedRows
allowEditRows={false}
allowEditColumns={false}
showAutoColumns={true}
disableSorting
autoSortColumns={!columns?.length}
on:sort={onSort}
on:click={onClick}
>
<slot />
</Table>
{#if allowSelectRows && selectedRows.length}
<div class="row-count">
{selectedRows.length} row{selectedRows.length === 1 ? "" : "s"} selected
</div>
{/if}
</div>
<style>
div {
background-color: var(--spectrum-alias-background-color-secondary);
}
.row-count {
margin-top: var(--spacing-l);
}
</style>