[Issue-5772] Add sort feature on settings tables (#5787)
## Proposed Changes - Introduce a new custom hook - useTableSort to sort table content - Add test cases for the new custom hook - Integrate useTableSort hook on to the table in settings object and settings object field pages ## Related Issue https://github.com/twentyhq/twenty/issues/5772 ## Evidence https://github.com/twentyhq/twenty/assets/87609792/8be456ce-2fa5-44ec-8bbd-70fb6c8fdb30 ## Evidence after addressing review comments https://github.com/twentyhq/twenty/assets/87609792/c267e3da-72f9-4c0e-8c94-a38122d6395e ## Further comments Apologies for the large PR. Looking forward for the review --------- Co-authored-by: Félix Malfait <felix.malfait@gmail.com> Co-authored-by: Lucas Bordeau <bordeau.lucas@gmail.com>
This commit is contained in:
committed by
GitHub
parent
0f75e14ab2
commit
59e14fabb4
@ -0,0 +1,119 @@
|
||||
import { renderHook } from '@testing-library/react';
|
||||
import React, { ReactNode } from 'react';
|
||||
import { MutableSnapshot, RecoilRoot } from 'recoil';
|
||||
|
||||
import {
|
||||
mockedTableMetadata,
|
||||
MockedTableType,
|
||||
mockedTableData as tableData,
|
||||
tableDataSortedByFieldsCountInAscendingOrder,
|
||||
tableDataSortedByFieldsCountInDescendingOrder,
|
||||
tableDataSortedBylabelInAscendingOrder,
|
||||
tableDataSortedBylabelInDescendingOrder,
|
||||
} from '~/testing/mock-data/tableData';
|
||||
|
||||
import { OrderBy } from '@/types/OrderBy';
|
||||
import { sortedFieldByTableFamilyState } from '@/ui/layout/table/states/sortedFieldByTableFamilyState';
|
||||
|
||||
import { useSortedArray } from '@/ui/layout/table/hooks/useSortedArray';
|
||||
|
||||
interface WrapperProps {
|
||||
children: ReactNode;
|
||||
initializeState?: (mutableSnapshot: MutableSnapshot) => void;
|
||||
}
|
||||
|
||||
const Wrapper: React.FC<WrapperProps> = ({ children, initializeState }) => (
|
||||
<RecoilRoot initializeState={initializeState}>{children}</RecoilRoot>
|
||||
);
|
||||
|
||||
describe('useSortedArray hook', () => {
|
||||
const initializeState =
|
||||
(fieldName: keyof MockedTableType, orderBy: OrderBy) =>
|
||||
({ set }: MutableSnapshot) => {
|
||||
set(
|
||||
sortedFieldByTableFamilyState({
|
||||
tableId: mockedTableMetadata.tableId,
|
||||
}),
|
||||
{
|
||||
fieldName,
|
||||
orderBy,
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
test('initial sorting behavior for string fields - Ascending', () => {
|
||||
const { result } = renderHook(
|
||||
() => useSortedArray(tableData, mockedTableMetadata),
|
||||
{
|
||||
wrapper: ({ children }: { children: ReactNode }) => (
|
||||
<Wrapper
|
||||
initializeState={initializeState('labelPlural', 'AscNullsLast')}
|
||||
>
|
||||
{children}
|
||||
</Wrapper>
|
||||
),
|
||||
},
|
||||
);
|
||||
|
||||
const sortedData = result.current;
|
||||
|
||||
expect(sortedData).toEqual(tableDataSortedBylabelInAscendingOrder);
|
||||
});
|
||||
|
||||
test('initial sorting behavior for string fields - Descending', () => {
|
||||
const { result } = renderHook(
|
||||
() => useSortedArray(tableData, mockedTableMetadata),
|
||||
{
|
||||
wrapper: ({ children }: { children: ReactNode }) => (
|
||||
<Wrapper
|
||||
initializeState={initializeState('labelPlural', 'DescNullsLast')}
|
||||
>
|
||||
{children}
|
||||
</Wrapper>
|
||||
),
|
||||
},
|
||||
);
|
||||
|
||||
const sortedData = result.current;
|
||||
|
||||
expect(sortedData).toEqual(tableDataSortedBylabelInDescendingOrder);
|
||||
});
|
||||
|
||||
test('initial sorting behavior for number fields - Ascending', () => {
|
||||
const { result } = renderHook(
|
||||
() => useSortedArray(tableData, mockedTableMetadata),
|
||||
{
|
||||
wrapper: ({ children }: { children: ReactNode }) => (
|
||||
<Wrapper
|
||||
initializeState={initializeState('fieldsCount', 'AscNullsLast')}
|
||||
>
|
||||
{children}
|
||||
</Wrapper>
|
||||
),
|
||||
},
|
||||
);
|
||||
|
||||
const sortedData = result.current;
|
||||
|
||||
expect(sortedData).toEqual(tableDataSortedByFieldsCountInAscendingOrder);
|
||||
});
|
||||
|
||||
test('initial sorting behavior for number fields - Descending', () => {
|
||||
const { result } = renderHook(
|
||||
() => useSortedArray(tableData, mockedTableMetadata),
|
||||
{
|
||||
wrapper: ({ children }: { children: ReactNode }) => (
|
||||
<Wrapper
|
||||
initializeState={initializeState('fieldsCount', 'DescNullsLast')}
|
||||
>
|
||||
{children}
|
||||
</Wrapper>
|
||||
),
|
||||
},
|
||||
);
|
||||
|
||||
const sortedData = result.current;
|
||||
|
||||
expect(sortedData).toEqual(tableDataSortedByFieldsCountInDescendingOrder);
|
||||
});
|
||||
});
|
||||
@ -0,0 +1,52 @@
|
||||
import { sortedFieldByTableFamilyState } from '@/ui/layout/table/states/sortedFieldByTableFamilyState';
|
||||
import { TableMetadata } from '@/ui/layout/table/types/TableMetadata';
|
||||
import { useMemo } from 'react';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import { isDefined } from 'twenty-ui';
|
||||
|
||||
export const useSortedArray = <T>(
|
||||
arrayToSort: T[],
|
||||
tableMetadata: TableMetadata<T>,
|
||||
): T[] => {
|
||||
const sortedFieldByTable = useRecoilValue(
|
||||
sortedFieldByTableFamilyState({ tableId: tableMetadata.tableId }),
|
||||
);
|
||||
|
||||
const initialSort = tableMetadata.initialSort;
|
||||
|
||||
const sortedArray = useMemo(() => {
|
||||
const sortValueToUse = isDefined(sortedFieldByTable)
|
||||
? sortedFieldByTable
|
||||
: initialSort;
|
||||
|
||||
if (!isDefined(sortValueToUse)) {
|
||||
return arrayToSort;
|
||||
}
|
||||
|
||||
const sortFieldName = sortValueToUse.fieldName as keyof T;
|
||||
const sortFieldType = tableMetadata.fields.find(
|
||||
(field) => field.fieldName === sortFieldName,
|
||||
)?.fieldType;
|
||||
const sortOrder = sortValueToUse.orderBy;
|
||||
|
||||
return [...arrayToSort].sort((a: T, b: T) => {
|
||||
if (sortFieldType === 'string') {
|
||||
return sortOrder === 'AscNullsLast' || sortOrder === 'AscNullsFirst'
|
||||
? (a[sortFieldName] as string)?.localeCompare(
|
||||
b[sortFieldName] as string,
|
||||
)
|
||||
: (b[sortFieldName] as string)?.localeCompare(
|
||||
a[sortFieldName] as string,
|
||||
);
|
||||
} else if (sortFieldType === 'number') {
|
||||
return sortOrder === 'AscNullsLast' || sortOrder === 'AscNullsFirst'
|
||||
? (a[sortFieldName] as number) - (b[sortFieldName] as number)
|
||||
: (b[sortFieldName] as number) - (a[sortFieldName] as number);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
});
|
||||
}, [arrayToSort, tableMetadata, initialSort, sortedFieldByTable]);
|
||||
|
||||
return sortedArray;
|
||||
};
|
||||
Reference in New Issue
Block a user