Files
twenty/packages/twenty-front/src/modules/object-metadata/hooks/useColumnDefinitionsFromObjectMetadata.ts
T
Charles Bochet d5a7dec117 refactor: rename ObjectMetadataItem to EnrichedObjectMetadataItem and clean up metadata flows (#18830)
## Summary

- Renames `ObjectMetadataItem` to `EnrichedObjectMetadataItem` across
the entire frontend (~440 files) to clarify that this type includes
derived fields (`readableFields`, `updatableFields`, nested `fields[]`,
`indexMetadatas[]`) computed at read time from the metadata store
- Creates `splitObjectMetadataGqlResponse` that goes directly from a
GraphQL `ObjectMetadataItemsQuery` response to flat store items
(combining the old
`mapPaginatedObjectMetadataItemsToObjectMetadataItems` +
`splitObjectMetadataItemWithRelated` two-step flow into one call)
- Removes `ObjectMetadataItemWithRelated` type and all "WithRelated"
naming
- Renames `generatedMockObjectMetadataItems` to
`generateTestEnrichedObjectMetadataItemsMock` to make it clear this is
test-only enriched data
- Deletes `useLoadMockedObjectMetadataItems` hook (consolidated into
`useLoadMockedMinimalMetadata`)
- Ensures nothing destined for the metadata store computes
`readableFields`/`updatableFields` (preventing the localStorage bloat
from #18809)

## Type hierarchy (before → after)

**Before:**
```
ObjectMetadataItemsQuery → mapPaginated → ObjectMetadataItemWithRelated → enrich → ObjectMetadataItem
                                        → split → FlatObjectMetadataItem (store)
```

**After:**
```
ObjectMetadataItemsQuery → splitObjectMetadataGqlResponse → FlatObjectMetadataItem (store)
                         → mapPaginated + enrich (tests only) → EnrichedObjectMetadataItem
```

## Test plan

- [x] `npx nx typecheck twenty-front` passes
- [x] `npx nx test twenty-front` passes (767 suites, 4505 tests)
- [x] `npx nx lint twenty-front` passes
- [ ] CI checks pass


Made with [Cursor](https://cursor.com)
2026-03-22 15:53:47 +01:00

77 lines
2.9 KiB
TypeScript

import { type EnrichedObjectMetadataItem } from '@/object-metadata/types/EnrichedObjectMetadataItem';
import { isHiddenSystemField } from '@/object-metadata/utils/isHiddenSystemField';
import { type FieldMetadata } from '@/object-record/record-field/ui/types/FieldMetadata';
import { type ColumnDefinition } from '@/object-record/record-table/types/ColumnDefinition';
import { filterAvailableTableColumns } from '@/object-record/utils/filterAvailableTableColumns';
import { availableFieldMetadataItemsForFilterFamilySelector } from '@/object-metadata/states/availableFieldMetadataItemsForFilterFamilySelector';
import { availableFieldMetadataItemsForSortFamilySelector } from '@/object-metadata/states/availableFieldMetadataItemsForSortFamilySelector';
import { formatFieldMetadataItemAsColumnDefinition } from '@/object-metadata/utils/formatFieldMetadataItemAsColumnDefinition';
import { useAtomFamilySelectorValue } from '@/ui/utilities/state/jotai/hooks/useAtomFamilySelectorValue';
import { useMemo } from 'react';
export const useColumnDefinitionsFromObjectMetadata = (
objectMetadataItem: EnrichedObjectMetadataItem,
) => {
const filterableFieldMetadataItems = useAtomFamilySelectorValue(
availableFieldMetadataItemsForFilterFamilySelector,
{
objectMetadataItemId: objectMetadataItem.id,
},
);
const sortableFieldMetadataItems = useAtomFamilySelectorValue(
availableFieldMetadataItemsForSortFamilySelector,
{
objectMetadataItemId: objectMetadataItem.id,
},
);
const columnDefinitions: ColumnDefinition<FieldMetadata>[] = useMemo(() => {
const activeFieldMetadataItems = objectMetadataItem.readableFields.filter(
(field) =>
field.isActive &&
(!isHiddenSystemField(field) ||
field.id === objectMetadataItem.labelIdentifierFieldMetadataId),
);
return activeFieldMetadataItems
.map((field, index) =>
formatFieldMetadataItemAsColumnDefinition({
position: index,
field,
objectMetadataItem,
}),
)
.filter(filterAvailableTableColumns)
.filter((column) => {
const restrictedFieldMetadataIds: string[] = [];
return !restrictedFieldMetadataIds.includes(column.fieldMetadataId);
})
.map((column) => {
const existsInFilterDefinitions = filterableFieldMetadataItems.some(
(fieldMetadataItem) =>
fieldMetadataItem.id === column.fieldMetadataId,
);
const existsInSortDefinitions = sortableFieldMetadataItems.some(
(fieldMetadataItem) =>
fieldMetadataItem.id === column.fieldMetadataId,
);
return {
...column,
isFilterable: existsInFilterDefinitions,
isSortable: existsInSortDefinitions,
};
});
}, [
filterableFieldMetadataItems,
sortableFieldMetadataItems,
objectMetadataItem,
]);
return {
columnDefinitions,
};
};