196 lines
4.6 KiB
Svelte
196 lines
4.6 KiB
Svelte
<script>
|
|
import { getContext } from "svelte"
|
|
import { Table } from "@budibase/bbui"
|
|
import SlotRenderer from "./SlotRenderer.svelte"
|
|
import { onDestroy } from "svelte"
|
|
import { canBeSortColumn } from "@budibase/shared-core"
|
|
|
|
export let dataProvider
|
|
export let columns
|
|
export let rowCount
|
|
export let quiet
|
|
export let size
|
|
export let allowSelectRows
|
|
export let compact
|
|
export let onClick
|
|
export let noRowsMessage
|
|
|
|
const component = getContext("component")
|
|
const { styleable, getAction, ActionTypes, 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 ?? {}
|
|
$: primaryDisplay = dataProvider?.primaryDisplay
|
|
$: fields = getFields(fullSchema, columns, false, primaryDisplay)
|
|
$: 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)
|
|
)
|
|
}
|
|
|
|
// If the data changes, double check that the selected elements are still present.
|
|
$: if (data) {
|
|
let rowIds = data.map(row => row._id)
|
|
if (rowIds.length) {
|
|
selectedRows = selectedRows.filter(row => rowIds.includes(row._id))
|
|
}
|
|
}
|
|
|
|
const getFields = (
|
|
schema,
|
|
customColumns,
|
|
showAutoColumns,
|
|
primaryDisplay
|
|
) => {
|
|
if (customColumns?.length) {
|
|
return customColumns
|
|
}
|
|
|
|
// Otherwise generate columns
|
|
let columns = []
|
|
let autoColumns = []
|
|
Object.entries(schema).forEach(([field, fieldSchema]) => {
|
|
if (fieldSchema.visible === false) {
|
|
return
|
|
}
|
|
if (!fieldSchema?.autocolumn) {
|
|
columns.push(field)
|
|
} else if (showAutoColumns) {
|
|
autoColumns.push(field)
|
|
}
|
|
})
|
|
|
|
// Sort columns to respect grid metadata
|
|
const allCols = columns.concat(autoColumns)
|
|
return allCols.sort((a, b) => {
|
|
if (a === primaryDisplay) {
|
|
return -1
|
|
}
|
|
if (b === primaryDisplay) {
|
|
return 1
|
|
}
|
|
const aOrder = schema[a].order
|
|
const bOrder = schema[b].order
|
|
if (aOrder === bOrder) {
|
|
return 0
|
|
}
|
|
if (aOrder == null) {
|
|
return 1
|
|
}
|
|
if (bOrder == null) {
|
|
return -1
|
|
}
|
|
return aOrder < bOrder ? -1 : 1
|
|
})
|
|
}
|
|
|
|
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 (!canBeSortColumn(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 handleClick = e => {
|
|
if (onClick) {
|
|
onClick({ row: e.detail })
|
|
}
|
|
}
|
|
|
|
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={handleClick}
|
|
placeholderText={noRowsMessage || "No rows found"}
|
|
>
|
|
<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>
|