import { normLabel } from './detailView' /** * Rich columns: several related record view columns shown as one cell — a * bold title line and a smaller line under it (e.g. name over employee code). * * A group is * { key, label, avatar?, title: [label…], subtitle: [label | { label, prefix }…] } * where each label names a view column by its output_label or field_key * ('first_name', 'Asset Brand'…, compared loosely). Title parts are joined * with a space, subtitle parts with ' · '; `prefix` goes before a value * ("Ends 12 Oct 2026"). `avatar` shows the title's initials. * * The member columns are replaced by the rich column, placed where its first * member was. A group none of whose columns the view has is skipped; columns * no group takes stay as they are. Rows are not changed — the cell reads each * member's own value. */ export function withRichColumns(res, groups) { const fields = res?.config?.fields ?? [] const matches = (col, label) => [col.output_label, col.field_key].some((l) => l && normLabel(l) === normLabel(label)) const taken = new Set() const take = (spec) => { const { label, prefix } = typeof spec === 'string' ? { label: spec } : spec const col = fields.find((c) => !taken.has(c) && matches(c, label)) if (!col) return [] taken.add(col) return [{ ...col, prefix }] } const richAt = new Map() for (const group of groups) { const title = group.title.flatMap(take) const subtitle = (group.subtitle ?? []).flatMap(take) const members = [...title, ...subtitle] if (!members.length) continue // Sorting by the column sorts by its first title field (or first member). const sortBy = title[0] ?? members[0] const first = fields.findIndex((c) => members.some((m) => m.field_key === c.field_key)) richAt.set(first, { type: 'rich', field_key: `rich_${group.key}`, output_label: group.label, data_type: 'rich', avatar: Boolean(group.avatar), title, subtitle, sort_key: sortBy.field_key, sortable: sortBy.sortable !== false && sortBy.type !== 'derived', }) } const next = fields.flatMap((c, i) => { if (richAt.has(i)) return [richAt.get(i)] return taken.has(c) ? [] : [c] }) return { ...res, config: { ...res?.config, fields: next } } }