137 lines
3.5 KiB
Svelte
137 lines
3.5 KiB
Svelte
<script lang="ts">
|
|
import type {
|
|
DataFetchDatasource,
|
|
FieldSchema,
|
|
GroupUserDatasource,
|
|
SortOrder,
|
|
TableSchema,
|
|
UISearchFilter,
|
|
UserDatasource,
|
|
} from "@budibase/types"
|
|
import { fetchData, QueryUtils, stringifyRow } from "@budibase/frontend-core"
|
|
import { getContext } from "svelte"
|
|
|
|
type ProviderDatasource = Exclude<
|
|
DataFetchDatasource,
|
|
UserDatasource | GroupUserDatasource
|
|
>
|
|
type ChosenColumns = Array<{ name: string; displayName?: string }> | undefined
|
|
type Schema = { [key: string]: FieldSchema & { displayName: string } }
|
|
|
|
export let datasource: ProviderDatasource
|
|
export let filter: UISearchFilter | undefined = undefined
|
|
export let sortColumn: string | undefined = undefined
|
|
export let sortOrder: SortOrder | undefined = undefined
|
|
export let columns: ChosenColumns = undefined
|
|
|
|
const component = getContext("component")
|
|
const { styleable, API } = getContext("sdk")
|
|
|
|
$: query = QueryUtils.buildQuery(filter)
|
|
$: fetch = createFetch(datasource)
|
|
$: fetch.update({
|
|
query,
|
|
sortColumn,
|
|
sortOrder,
|
|
limit: 100,
|
|
paginate: false,
|
|
})
|
|
$: schema = sanitizeSchema($fetch.schema, columns)
|
|
$: columnCount = Object.keys(schema).length
|
|
$: rowCount = $fetch.rows?.length || 0
|
|
$: stringifiedRows = ($fetch?.rows || []).map(row =>
|
|
stringifyRow(row, schema)
|
|
)
|
|
|
|
const createFetch = (datasource: ProviderDatasource) => {
|
|
return fetchData({
|
|
API,
|
|
datasource,
|
|
options: {
|
|
query,
|
|
sortColumn,
|
|
sortOrder,
|
|
},
|
|
})
|
|
}
|
|
|
|
const sanitizeSchema = (
|
|
schema: TableSchema | null,
|
|
columns: ChosenColumns
|
|
): Schema => {
|
|
if (!schema) {
|
|
return {}
|
|
}
|
|
let sanitized: Schema = {}
|
|
|
|
// Clean out hidden fields and ensure we have
|
|
Object.entries(schema).forEach(([field, fieldSchema]) => {
|
|
if (fieldSchema.visible !== false) {
|
|
sanitized[field] = {
|
|
...fieldSchema,
|
|
displayName: field,
|
|
}
|
|
}
|
|
})
|
|
|
|
// Clean out unselected columns
|
|
if (columns?.length) {
|
|
let pruned: Schema = {}
|
|
for (let col of columns) {
|
|
if (sanitized[col.name]) {
|
|
pruned[col.name] = {
|
|
...sanitized[col.name],
|
|
displayName: col.displayName || sanitized[col.name].displayName,
|
|
}
|
|
}
|
|
}
|
|
sanitized = pruned
|
|
}
|
|
|
|
return sanitized
|
|
}
|
|
</script>
|
|
|
|
<div class="vars" style="--cols:{columnCount}; --rows:{rowCount};">
|
|
<div class="table" class:valid={!!schema} use:styleable={$component.styles}>
|
|
{#if schema}
|
|
{#each Object.keys(schema) as col}
|
|
<div class="cell header">{schema[col].displayName}</div>
|
|
{/each}
|
|
{#each stringifiedRows as row}
|
|
{#each Object.keys(schema) as col}
|
|
<div class="cell">{row[col]}</div>
|
|
{/each}
|
|
{/each}
|
|
{/if}
|
|
</div>
|
|
</div>
|
|
|
|
<style>
|
|
.vars {
|
|
display: contents;
|
|
--border-color: var(--spectrum-global-color-gray-300);
|
|
}
|
|
.table {
|
|
display: grid;
|
|
grid-template-columns: repeat(var(--cols), minmax(20px, auto));
|
|
grid-template-rows: repeat(var(--rows), max-content);
|
|
overflow: hidden;
|
|
background: white;
|
|
}
|
|
.table.valid {
|
|
border-left: 1px solid var(--border-color);
|
|
border-top: 1px solid var(--border-color);
|
|
}
|
|
.cell {
|
|
border-right: 1px solid var(--border-color);
|
|
border-bottom: 1px solid var(--border-color);
|
|
padding: var(--spacing-xs) var(--spacing-s);
|
|
overflow: hidden;
|
|
word-break: break-word;
|
|
}
|
|
.cell.header {
|
|
font-weight: 600;
|
|
}
|
|
</style>
|