- Introduced `ColumnBrowserFixture` component for testing column visibility and interactions. - Created `entity-column-configuration.ts` to define types and utility functions for managing entity columns. - Implemented Playwright tests in `columns-ui.test.py` to validate column behavior and preferences. - Added `visual-audit-volume.py` script to enhance the visual audit setup with synthetic data.
67 lines
1.8 KiB
TypeScript
67 lines
1.8 KiB
TypeScript
export type EntityColumnMetadata = {
|
|
groupId?: string;
|
|
keywords?: readonly string[];
|
|
};
|
|
|
|
export type EntityColumnGroup = {
|
|
id: string;
|
|
label: string;
|
|
description?: string;
|
|
};
|
|
|
|
export type EntityColumnOption = EntityColumnMetadata & {
|
|
id: string;
|
|
label: string;
|
|
visible: boolean;
|
|
hideable: boolean;
|
|
};
|
|
|
|
/** Normaliza tildes sin equiparar ñ y n, incluidas sus representaciones Unicode descompuestas. */
|
|
export function normalizeColumnSearch(value: string): string {
|
|
return value
|
|
.trim()
|
|
.toLowerCase()
|
|
.normalize("NFD")
|
|
.replace(/n\u0303/g, "ñ")
|
|
.replace(/\p{M}/gu, "");
|
|
}
|
|
|
|
/** Los IDs conservan identidad; la primera declaración de un grupo u opción prevalece. */
|
|
export function groupColumnOptions(
|
|
options: readonly EntityColumnOption[],
|
|
groups: readonly EntityColumnGroup[],
|
|
search: string
|
|
) {
|
|
const term = normalizeColumnSearch(search);
|
|
const uniqueOptions = new Map<string, EntityColumnOption>();
|
|
const uniqueGroups = new Map<string, EntityColumnGroup>();
|
|
|
|
for (const group of groups) {
|
|
if (!uniqueGroups.has(group.id)) {
|
|
uniqueGroups.set(group.id, group);
|
|
}
|
|
}
|
|
for (const option of options) {
|
|
if (!uniqueOptions.has(option.id)) {
|
|
uniqueOptions.set(option.id, option);
|
|
}
|
|
}
|
|
const matches = [...uniqueOptions.values()].filter((option) =>
|
|
[option.label, ...(option.keywords ?? [])].some((value) =>
|
|
normalizeColumnSearch(value).includes(term)
|
|
)
|
|
);
|
|
const grouped = [...uniqueGroups.values()].map((group) => ({
|
|
group,
|
|
options: matches.filter((option) => option.groupId === group.id),
|
|
}));
|
|
const ungrouped = matches.filter(
|
|
(option) => !(option.groupId && uniqueGroups.has(option.groupId))
|
|
);
|
|
|
|
return [
|
|
...grouped.filter((group) => group.options.length > 0),
|
|
...(ungrouped.length ? [{ group: undefined, options: ungrouped }] : []),
|
|
];
|
|
}
|