Fix export CSV not using right columns (#15752)

Fixes https://github.com/twentyhq/twenty/issues/15575
This commit is contained in:
Charles Bochet
2025-11-10 22:00:39 +01:00
committed by GitHub
parent 194a579a03
commit 7099b1c174
10 changed files with 58 additions and 31 deletions
@@ -1,7 +1,7 @@
import { renderHook } from '@testing-library/react';
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
import { useColumnDefinitionsFromFieldMetadata } from '@/object-metadata/hooks/useColumnDefinitionsFromFieldMetadata';
import { useColumnDefinitionsFromObjectMetadata } from '@/object-metadata/hooks/useColumnDefinitionsFromObjectMetadata';
import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
import {
SubscriptionInterval,
@@ -59,7 +59,7 @@ const Wrapper = getJestMetadataAndApolloMocksAndActionMenuWrapper({
},
});
describe('useColumnDefinitionsFromFieldMetadata', () => {
describe('useColumnDefinitionsFromObjectMetadata', () => {
it('should return expected definitions', () => {
const companyObjectMetadata = generatedMockObjectMetadataItems.find(
(item) => item.nameSingular === 'company',
@@ -67,7 +67,7 @@ describe('useColumnDefinitionsFromFieldMetadata', () => {
const { result } = renderHook(
(objectMetadataItem: ObjectMetadataItem) => {
return useColumnDefinitionsFromFieldMetadata(objectMetadataItem);
return useColumnDefinitionsFromObjectMetadata(objectMetadataItem);
},
{
initialProps: companyObjectMetadata,
@@ -8,7 +8,7 @@ import { availableFieldMetadataItemsForSortFamilySelector } from '@/object-metad
import { useRecoilValue } from 'recoil';
import { formatFieldMetadataItemAsColumnDefinition } from '../utils/formatFieldMetadataItemAsColumnDefinition';
export const useColumnDefinitionsFromFieldMetadata = (
export const useColumnDefinitionsFromObjectMetadata = (
objectMetadataItem: ObjectMetadataItem,
) => {
const activeFieldMetadataItems = objectMetadataItem.readableFields.filter(
@@ -2,7 +2,7 @@ import { type OnDragEndResponder } from '@hello-pangea/dnd';
import { useCallback, useMemo } from 'react';
import { useRecoilState } from 'recoil';
import { useColumnDefinitionsFromFieldMetadata } from '@/object-metadata/hooks/useColumnDefinitionsFromFieldMetadata';
import { useColumnDefinitionsFromObjectMetadata } from '@/object-metadata/hooks/useColumnDefinitionsFromObjectMetadata';
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
import { useReorderVisibleRecordFields } from '@/object-record/record-field/hooks/useReorderVisibleRecordFields';
import { useUpdateRecordField } from '@/object-record/record-field/hooks/useUpdateRecordField';
@@ -41,7 +41,7 @@ export const useObjectOptionsForBoard = ({
});
const { columnDefinitions } =
useColumnDefinitionsFromFieldMetadata(objectMetadataItem);
useColumnDefinitionsFromObjectMetadata(objectMetadataItem);
const availableColumnDefinitions = useMemo(
() =>
@@ -1,6 +1,6 @@
import { useEffect } from 'react';
import { useColumnDefinitionsFromFieldMetadata } from '@/object-metadata/hooks/useColumnDefinitionsFromFieldMetadata';
import { useColumnDefinitionsFromObjectMetadata } from '@/object-metadata/hooks/useColumnDefinitionsFromObjectMetadata';
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext';
import { viewFieldAggregateOperationState } from '@/object-record/record-table/record-table-footer/states/viewFieldAggregateOperationState';
@@ -18,7 +18,7 @@ export const RecordIndexTableContainerEffect = () => {
});
const { columnDefinitions } =
useColumnDefinitionsFromFieldMetadata(objectMetadataItem);
useColumnDefinitionsFromObjectMetadata(objectMetadataItem);
const { currentView } = useGetCurrentViewOnly();
@@ -1,6 +1,6 @@
import { useEffect } from 'react';
import { useColumnDefinitionsFromFieldMetadata } from '@/object-metadata/hooks/useColumnDefinitionsFromFieldMetadata';
import { useColumnDefinitionsFromObjectMetadata } from '@/object-metadata/hooks/useColumnDefinitionsFromObjectMetadata';
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
import { useObjectNameSingularFromPlural } from '@/object-metadata/hooks/useObjectNameSingularFromPlural';
import { useInitViewBar } from '@/views/hooks/useInitViewBar';
@@ -24,7 +24,7 @@ export const RecordIndexViewBarEffect = ({
});
const { columnDefinitions } =
useColumnDefinitionsFromFieldMetadata(objectMetadataItem);
useColumnDefinitionsFromObjectMetadata(objectMetadataItem);
const { setViewObjectMetadataId, setAvailableFieldDefinitions } =
useInitViewBar(viewBarId);
@@ -6,7 +6,6 @@ import {
useRecordIndexLazyFetchRecords,
} from '../useRecordIndexLazyFetchRecords';
import { useColumnDefinitionsFromFieldMetadata } from '@/object-metadata/hooks/useColumnDefinitionsFromFieldMetadata';
import { useLazyFetchAllRecords } from '@/object-record/hooks/useLazyFetchAllRecords';
import { ViewType } from '@/views/types/ViewType';
import { getJestMetadataAndApolloMocksAndActionMenuWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksAndActionMenuWrapper';
@@ -132,9 +131,6 @@ describe('useRecordData', () => {
const { result } = renderHook(
() => {
const { columnDefinitions } =
useColumnDefinitionsFromFieldMetadata(objectMetadataItem);
const lazyFetchResult = useRecordIndexLazyFetchRecords({
recordIndexId,
objectMetadataItem,
@@ -144,7 +140,6 @@ describe('useRecordData', () => {
});
return {
columnDefinitions,
lazyFetchResult,
};
},
@@ -156,10 +151,7 @@ describe('useRecordData', () => {
});
await waitFor(() => {
expect(callback).toHaveBeenCalledWith(
[mockPerson],
result.current.columnDefinitions,
);
expect(callback).toHaveBeenCalledWith([mockPerson], []);
});
});
});
@@ -23,7 +23,7 @@ import { isUndefinedOrNull } from '~/utils/isUndefinedOrNull';
type GenerateExportOptions = {
columns: Pick<
ColumnDefinition<FieldMetadata>,
'size' | 'label' | 'type' | 'metadata'
'label' | 'type' | 'metadata'
>[];
rows: Record<string, any>[];
};
@@ -169,7 +169,13 @@ export const useRecordIndexExportRecords = ({
const downloadCsv = useMemo(
() =>
(records: ObjectRecord[], columns: ColumnDefinition<FieldMetadata>[]) => {
(
records: ObjectRecord[],
columns: Pick<
ColumnDefinition<FieldMetadata>,
'label' | 'type' | 'metadata'
>[],
) => {
const recordsProcessedForExport = processRecordsForCSVExport(records);
csvDownloader(filename, { rows: recordsProcessedForExport, columns });
@@ -7,16 +7,18 @@ import { contextStoreFilterGroupsComponentState } from '@/context-store/states/c
import { contextStoreFiltersComponentState } from '@/context-store/states/contextStoreFiltersComponentState';
import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState';
import { computeContextStoreFilters } from '@/context-store/utils/computeContextStoreFilters';
import { useColumnDefinitionsFromFieldMetadata } from '@/object-metadata/hooks/useColumnDefinitionsFromFieldMetadata';
import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
import { useLazyFetchAllRecords } from '@/object-record/hooks/useLazyFetchAllRecords';
import { EXPORT_TABLE_DATA_DEFAULT_PAGE_SIZE } from '@/object-record/object-options-dropdown/constants/ExportTableDataDefaultPageSize';
import { useObjectOptionsForBoard } from '@/object-record/object-options-dropdown/hooks/useObjectOptionsForBoard';
import { visibleRecordFieldsComponentSelector } from '@/object-record/record-field/states/visibleRecordFieldsComponentSelector';
import { type RecordField } from '@/object-record/record-field/types/RecordField';
import { useFilterValueDependencies } from '@/object-record/record-filter/hooks/useFilterValueDependencies';
import { recordGroupFieldMetadataComponentState } from '@/object-record/record-group/states/recordGroupFieldMetadataComponentState';
import { useFindManyRecordIndexTableParams } from '@/object-record/record-index/hooks/useFindManyRecordIndexTableParams';
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
import { ViewType } from '@/views/types/ViewType';
import { isDefined } from 'twenty-shared/utils';
export const sleep = (ms: number) =>
new Promise((resolve) => setTimeout(resolve, ms));
@@ -33,7 +35,10 @@ export type UseRecordDataOptions = {
recordIndexId: string;
callback: (
rows: ObjectRecord[],
columns: ColumnDefinition<FieldMetadata>[],
columns: Pick<
ColumnDefinition<FieldMetadata>,
'label' | 'type' | 'metadata'
>[],
) => void | Promise<void>;
viewType?: ViewType;
};
@@ -93,11 +98,35 @@ export const useRecordIndexLazyFetchRecords = ({
contextStoreAnyFieldFilterValue,
});
const { columnDefinitions } =
useColumnDefinitionsFromFieldMetadata(objectMetadataItem);
const visibleRecordFields = useRecoilComponentValue(
visibleRecordFieldsComponentSelector,
);
const finalColumns = [
...columnDefinitions,
const finalColumns: Pick<
ColumnDefinition<FieldMetadata>,
'label' | 'type' | 'metadata'
>[] = [
...visibleRecordFields
.map((field: RecordField) => {
const fieldMetadataItem = objectMetadataItem.fields.find(
(fieldMetadataItem) =>
fieldMetadataItem.id === field.fieldMetadataItemId,
);
if (!fieldMetadataItem) {
return null;
}
return {
label: fieldMetadataItem.label,
type: fieldMetadataItem.type,
metadata: {
fieldName: fieldMetadataItem.name,
relationType: fieldMetadataItem.relation?.type,
},
};
})
.filter(isDefined),
...(hiddenKanbanFieldColumn && viewType === ViewType.Kanban
? [hiddenKanbanFieldColumn]
: []),
@@ -1,6 +1,6 @@
import { useCallback } from 'react';
import { useColumnDefinitionsFromFieldMetadata } from '@/object-metadata/hooks/useColumnDefinitionsFromFieldMetadata';
import { useColumnDefinitionsFromObjectMetadata } from '@/object-metadata/hooks/useColumnDefinitionsFromObjectMetadata';
import { useObjectMetadataItemById } from '@/object-metadata/hooks/useObjectMetadataItemById';
import { useUpsertRecordSort } from '@/object-record/record-sort/hooks/useUpsertRecordSort';
import { type RecordSort } from '@/object-record/record-sort/types/RecordSort';
@@ -20,7 +20,7 @@ export const useHandleToggleColumnSort = ({
});
const { columnDefinitions } =
useColumnDefinitionsFromFieldMetadata(objectMetadataItem);
useColumnDefinitionsFromObjectMetadata(objectMetadataItem);
const { upsertRecordSort } = useUpsertRecordSort();
@@ -1,7 +1,7 @@
import { useCallback } from 'react';
import { v4 } from 'uuid';
import { useColumnDefinitionsFromFieldMetadata } from '@/object-metadata/hooks/useColumnDefinitionsFromFieldMetadata';
import { useColumnDefinitionsFromObjectMetadata } from '@/object-metadata/hooks/useColumnDefinitionsFromObjectMetadata';
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
import { useUpsertRecordFilter } from '@/object-record/record-filter/hooks/useUpsertRecordFilter';
import { type RecordFilter } from '@/object-record/record-filter/types/RecordFilter';
@@ -26,7 +26,7 @@ export const useHandleToggleTrashColumnFilter = ({
});
const { columnDefinitions } =
useColumnDefinitionsFromFieldMetadata(objectMetadataItem);
useColumnDefinitionsFromObjectMetadata(objectMetadataItem);
const isSoftDeleteFilterActiveComponentRecoilState =
useRecoilComponentCallbackState(