77 lines
2.8 KiB
TypeScript
77 lines
2.8 KiB
TypeScript
/**
|
|
* Resolves column types from backend attribute definitions.
|
|
*
|
|
* Pages define column configs with UI metadata (label, width, formatter, etc.)
|
|
* but omit the `type` field. This utility merges the backend-provided attribute
|
|
* type into each column, ensuring a single source of truth for column types.
|
|
*/
|
|
|
|
import type { ColumnConfig } from '../components/FormGenerator/FormGeneratorTable';
|
|
import type { AttributeType } from './attributeTypeMapper';
|
|
|
|
export interface AttributeLike {
|
|
name: string;
|
|
type?: string;
|
|
label?: string;
|
|
displayField?: string;
|
|
frontendFormat?: string;
|
|
frontendFormatLabels?: string[];
|
|
/** Backend-provided options. Accepts the canonical `{value,label}` array
|
|
* (preferred), a legacy plain `string[]` (treated as value==label), or a
|
|
* string reference (e.g. `"user.role"`) — only the array forms are merged
|
|
* into `ColumnConfig.options`; references are ignored here. */
|
|
options?: Array<{ value: string | number; label: string }> | string[] | string;
|
|
}
|
|
|
|
/**
|
|
* Merge backend attribute metadata into page-defined column configs.
|
|
*
|
|
* For each column, the following fields are resolved from the matching backend
|
|
* attribute (by `key === attr.name`) when the column does not already define
|
|
* them: `type`, `label`, `displayField`, `frontendFormat`, `frontendFormatLabels`.
|
|
*
|
|
* Pages must NOT hardcode display data (labels, value translations) — they
|
|
* declare which columns to show, the backend declares the metadata.
|
|
*/
|
|
export function resolveColumnTypes(
|
|
columns: ColumnConfig[],
|
|
attributes: AttributeLike[],
|
|
): ColumnConfig[] {
|
|
if (!attributes || attributes.length === 0) return columns;
|
|
|
|
const attrMap = new Map<string, AttributeLike>();
|
|
for (const attr of attributes) {
|
|
attrMap.set(attr.name, attr);
|
|
}
|
|
|
|
return columns.map((col) => {
|
|
const attr = attrMap.get(col.key);
|
|
if (!attr) return col;
|
|
|
|
const merged: ColumnConfig = { ...col };
|
|
if (attr.type) {
|
|
merged.type = attr.type as AttributeType;
|
|
}
|
|
if (attr.label && !col.label) {
|
|
merged.label = attr.label;
|
|
}
|
|
if (attr.displayField && !col.displayField) {
|
|
merged.displayField = attr.displayField;
|
|
}
|
|
if (attr.frontendFormat && !col.frontendFormat) {
|
|
merged.frontendFormat = attr.frontendFormat;
|
|
}
|
|
if (attr.frontendFormatLabels && !col.frontendFormatLabels) {
|
|
merged.frontendFormatLabels = attr.frontendFormatLabels;
|
|
}
|
|
if (Array.isArray(attr.options) && !col.options) {
|
|
// Normalise legacy `string[]` to the canonical `{value,label}` shape.
|
|
const opts = attr.options as Array<string | { value: string | number; label: string }>;
|
|
const normalised = opts.map((o) =>
|
|
typeof o === 'string' ? { value: o, label: o } : o,
|
|
);
|
|
merged.options = normalised;
|
|
}
|
|
return merged;
|
|
});
|
|
}
|