import Alpine from 'alpinejs'
import {
FlexRender,
columnFacetingFeature,
columnFilteringFeature,
createFacetedRowModel,
createFacetedUniqueValues,
createFilteredRowModel,
createPaginatedRowModel,
createTable,
filterFn_includesString,
metaHelper,
rowPaginationFeature,
tableFeatures,
} from '@tanstack/alpine-table'
import { makeData } from './makeData'
import {
createBucketFilter,
formatBytes,
getBucket,
lastLoginBuckets,
storageBuckets,
} from './buckets'
import './index.css'
import type { Column, ColumnDef } from '@tanstack/alpine-table'
import type { Account } from './makeData'
import type { BucketColumnMeta, FacetKey } from './buckets'
const features = tableFeatures({
columnFilteringFeature,
columnFacetingFeature,
rowPaginationFeature,
facetedRowModel: createFacetedRowModel(),
facetedUniqueValues: createFacetedUniqueValues(),
filteredRowModel: createFilteredRowModel(),
paginatedRowModel: createPaginatedRowModel(),
filterFns: {
includesString: filterFn_includesString,
},
columnMeta: metaHelper<BucketColumnMeta>(),
})
const columns: Array<ColumnDef<typeof features, Account>> = [
{
accessorKey: 'name',
header: 'Account',
filterFn: 'includesString',
meta: { filterVariant: 'text' },
},
{
accessorKey: 'lastLogin',
header: 'Last login',
cell: (info) => (info.getValue() as Date).toLocaleString(),
getUniqueValues: (row) => [getBucket(row.lastLogin, lastLoginBuckets)],
filterFn: createBucketFilter(lastLoginBuckets),
meta: { filterVariant: 'facets', facetOptions: lastLoginBuckets },
},
{
accessorKey: 'storageBytes',
header: 'Storage',
cell: (info) => formatBytes(info.getValue() as number),
getUniqueValues: (row) => [getBucket(row.storageBytes, storageBuckets)],
filterFn: createBucketFilter(storageBuckets),
meta: { filterVariant: 'facets', facetOptions: storageBuckets },
},
{
accessorKey: 'files',
header: 'Files',
enableColumnFilter: false,
cell: (info) => (info.getValue() as number).toLocaleString(),
},
]
type AccountColumn = Column<typeof features, Account>
function debounce<TArgs extends Array<unknown>>(
fn: (...args: TArgs) => void,
wait: number,
) {
let timer: ReturnType<typeof setTimeout> | undefined
return (...args: TArgs) => {
clearTimeout(timer)
timer = setTimeout(() => fn(...args), wait)
}
}
Alpine.data('table', () => {
const local = Alpine.reactive({ data: makeData(5_000) })
const table = createTable({
features,
columns,
get data() {
return local.data
},
debugTable: true,
})
const setColumnFilter = debounce(
(column: AccountColumn, value: unknown) => column.setFilterValue(value),
500,
)
return {
table,
FlexRender,
isFacetColumn(column: AccountColumn) {
return column.columnDef.meta?.filterVariant === 'facets'
},
facetOptions(column: AccountColumn) {
return column.columnDef.meta?.facetOptions ?? []
},
facetCount(column: AccountColumn, value: FacetKey) {
return column.getFacetedUniqueValues().get(value) ?? 0
},
facetSelected(column: AccountColumn, value: FacetKey) {
return ((column.getFilterValue() ?? []) as Array<FacetKey>).includes(
value,
)
},
toggleFacet(column: AccountColumn, value: FacetKey) {
const selected = (column.getFilterValue() ?? []) as Array<FacetKey>
column.setFilterValue(
selected.includes(value)
? selected.filter((item) => item !== value)
: [...selected, value],
)
},
onTextFilter(column: AccountColumn, value: string) {
setColumnFilter(column, value)
},
goToPage(value: string) {
table.setPageIndex(value ? Number(value) - 1 : 0)
},
pageSizes: [10, 20, 30, 40, 50],
refreshData() {
local.data = makeData(5_000)
},
stressTest() {
local.data = makeData(1_000_000)
},
}
})
window.Alpine = Alpine
Alpine.start()