Reduce frequency of column formatter invocation by caching formatted display values into rows

This commit is contained in:
Andrew Kingston 2025-01-30 15:11:21 +00:00
parent d37fedaae7
commit 12f9d7efb6
No known key found for this signature in database
5 changed files with 45 additions and 25 deletions

View File

@ -115,12 +115,10 @@
} }
const createFormatter = column => { const createFormatter = column => {
if (!column.format?.length) { if (typeof column.format !== "string" || !column.format.trim().length) {
return null return null
} }
return row => { return row => processStringSync(column.format, { [id]: row })
return processStringSync(column.format, { [id]: row })
}
} }
const enrichButtons = buttons => { const enrichButtons = buttons => {

View File

@ -40,7 +40,7 @@
// Get the appropriate cell renderer and value // Get the appropriate cell renderer and value
$: hasCustomFormat = column.format && !row._isNewRow $: hasCustomFormat = column.format && !row._isNewRow
$: renderer = hasCustomFormat ? TextCell : getCellRenderer(column) $: renderer = hasCustomFormat ? TextCell : getCellRenderer(column)
$: value = hasCustomFormat ? column.format(row) : row[column.name] $: value = hasCustomFormat ? row.__formatted?.[column.name] : row[column.name]
// Get the error for this cell if the cell is focused or selected // Get the error for this cell if the cell is focused or selected
$: error = getErrorStore(rowFocused, cellId) $: error = getErrorStore(rowFocused, cellId)

View File

@ -16,6 +16,7 @@ import { Store as StoreContext } from "."
interface IndexedUIRow extends UIRow { interface IndexedUIRow extends UIRow {
__idx: number __idx: number
__formatted: Record<string, any>
} }
interface RowStore { interface RowStore {
@ -114,26 +115,44 @@ export const createStores = (): RowStore => {
export const deriveStores = (context: StoreContext): RowDerivedStore => { export const deriveStores = (context: StoreContext): RowDerivedStore => {
const { rows, enrichedSchema } = context const { rows, enrichedSchema } = context
// Enrich rows with an index property and any pending changes // Enrich rows with an index property and additional values
const enrichedRows = derived( const enrichedRows = derived(
[rows, enrichedSchema], [rows, enrichedSchema],
([$rows, $enrichedSchema]) => { ([$rows, $enrichedSchema]) => {
const customColumns = Object.values($enrichedSchema || {}).filter( // Find columns which require additional processing
f => f.related const cols = Object.values($enrichedSchema || {})
) const relatedColumns = cols.filter(col => col.related)
return $rows.map<IndexedUIRow>((row, idx) => ({ const formattedColumns = cols.filter(col => col.format)
...row,
__idx: idx, return $rows.map<IndexedUIRow>((row, idx) => {
...customColumns.reduce<Record<string, string>>((map, column) => { // Derive any values that need enriched from related rows
const fromField = $enrichedSchema![column.related!.field] const relatedValues = relatedColumns.reduce<Record<string, string>>(
map[column.name] = getRelatedTableValues( (map, column) => {
row, const fromField = $enrichedSchema![column.related!.field]
{ ...column, related: column.related! }, map[column.name] = getRelatedTableValues(
fromField row,
) { ...column, related: column.related! },
return map fromField
}, {}), )
})) return map
},
{}
)
// Derive any display-only formatted values for this row
const formattedValues = formattedColumns.reduce<Record<string, any>>(
(map, column) => {
map[column.name] = column.format!(row)
return map
},
{}
)
return {
...row,
...relatedValues,
__formatted: formattedValues,
__idx: idx,
}
})
} }
) )
@ -791,6 +810,7 @@ export const createActions = (context: StoreContext): RowActionStore => {
let clone: Row = { ...row } let clone: Row = { ...row }
delete clone.__idx delete clone.__idx
delete clone.__metadata delete clone.__metadata
delete clone.__formatted
if (!get(hasBudibaseIdentifiers) && isGeneratedRowID(clone._id!)) { if (!get(hasBudibaseIdentifiers) && isGeneratedRowID(clone._id!)) {
delete clone._id delete clone._id
} }

View File

@ -1,10 +1,10 @@
import { CalculationType, FieldSchema, FieldType } from "@budibase/types" import { CalculationType, FieldSchema, FieldType, UIRow } from "@budibase/types"
export type UIColumn = FieldSchema & { export type UIColumn = FieldSchema & {
label: string label: string
readonly: boolean readonly: boolean
conditions: any conditions: any
format?: () => any format?: (row: UIRow) => any
related?: { related?: {
field: string field: string
subField: string subField: string

View File

@ -5,6 +5,7 @@ import {
RelationSchemaField, RelationSchemaField,
SortOrder, SortOrder,
Table, Table,
UIRow,
UISearchFilter, UISearchFilter,
} from "@budibase/types" } from "@budibase/types"
@ -24,9 +25,10 @@ export interface UITable extends Table {
export type UIFieldSchema = FieldSchema & export type UIFieldSchema = FieldSchema &
BasicViewFieldMetadata & { BasicViewFieldMetadata & {
related?: { field: string; subField: string } related?: { field: string; subField: string }
columns?: Record<string, UIRelationSchemaField> columns?: Record<string, UIRelationSchFemaField>
cellRenderType?: string cellRenderType?: string
disabled?: boolean disabled?: boolean
format?: (row: UIRow) => any
} }
interface UIRelationSchemaField extends RelationSchemaField { interface UIRelationSchemaField extends RelationSchemaField {