Files
twenty_crm/packages/twenty-front/src/pages/settings/data-model/SettingsObjectFieldTable.tsx
Anand Krishnan M J 59e14fabb4 [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>
2024-08-14 17:11:17 +02:00

195 lines
6.1 KiB
TypeScript

import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
import {
SettingsObjectFieldItemTableRow,
StyledObjectFieldTableRow,
} from '@/settings/data-model/object-details/components/SettingsObjectFieldItemTableRow';
import { settingsObjectFieldsFamilyState } from '@/settings/data-model/object-details/states/settingsObjectFieldsFamilyState';
import { SortableTableHeader } from '@/ui/layout/table/components/SortableTableHeader';
import { Table } from '@/ui/layout/table/components/Table';
import { TableHeader } from '@/ui/layout/table/components/TableHeader';
import { TableSection } from '@/ui/layout/table/components/TableSection';
import { useSortedArray } from '@/ui/layout/table/hooks/useSortedArray';
import { TableMetadata } from '@/ui/layout/table/types/TableMetadata';
import { isNonEmptyArray } from '@sniptt/guards';
import { useEffect, useMemo } from 'react';
import { useRecoilState } from 'recoil';
import { useMapFieldMetadataItemToSettingsObjectDetailTableItem } from '~/pages/settings/data-model/hooks/useMapFieldMetadataItemToSettingsObjectDetailTableItem';
import { SettingsObjectDetailTableItem } from '~/pages/settings/data-model/types/SettingsObjectDetailTableItem';
const SETTINGS_OBJECT_DETAIL_TABLE_METADATA_STANDARD: TableMetadata<SettingsObjectDetailTableItem> =
{
tableId: 'settingsObjectDetail',
fields: [
{
fieldLabel: 'Name',
fieldName: 'label',
fieldType: 'string',
align: 'left',
},
{
fieldLabel: 'Field type',
fieldName: 'fieldType',
fieldType: 'string',
align: 'left',
},
{
fieldLabel: 'Data type',
fieldName: 'dataType',
fieldType: 'string',
align: 'left',
},
],
initialSort: {
fieldName: 'label',
orderBy: 'AscNullsLast',
},
};
const SETTINGS_OBJECT_DETAIL_TABLE_METADATA_CUSTOM: TableMetadata<SettingsObjectDetailTableItem> =
{
tableId: 'settingsObjectDetail',
fields: [
{
fieldLabel: 'Name',
fieldName: 'label',
fieldType: 'string',
align: 'left',
},
{
fieldLabel: 'Identifier',
fieldName: 'identifierType',
fieldType: 'string',
align: 'left',
},
{
fieldLabel: 'Data type',
fieldName: 'dataType',
fieldType: 'string',
align: 'left',
},
],
initialSort: {
fieldName: 'label',
orderBy: 'AscNullsLast',
},
};
export type SettingsObjectFieldTableProps = {
objectMetadataItem: ObjectMetadataItem;
mode: 'view' | 'new-field';
};
// TODO: find another way than using mode which feels like it could be replaced by another pattern
export const SettingsObjectFieldTable = ({
objectMetadataItem,
mode,
}: SettingsObjectFieldTableProps) => {
const tableMetadata = objectMetadataItem.isCustom
? SETTINGS_OBJECT_DETAIL_TABLE_METADATA_CUSTOM
: SETTINGS_OBJECT_DETAIL_TABLE_METADATA_STANDARD;
const { mapFieldMetadataItemToSettingsObjectDetailTableItem } =
useMapFieldMetadataItemToSettingsObjectDetailTableItem(objectMetadataItem);
const [settingsObjectFields, setSettingsObjectFields] = useRecoilState(
settingsObjectFieldsFamilyState({
objectMetadataItemId: objectMetadataItem.id,
}),
);
useEffect(() => {
setSettingsObjectFields(objectMetadataItem.fields);
}, [objectMetadataItem, setSettingsObjectFields]);
const activeObjectSettingsDetailItems = useMemo(() => {
const activeMetadataFields = settingsObjectFields?.filter(
(fieldMetadataItem) =>
fieldMetadataItem.isActive && !fieldMetadataItem.isSystem,
);
return (
activeMetadataFields?.map(
mapFieldMetadataItemToSettingsObjectDetailTableItem,
) ?? []
);
}, [
settingsObjectFields,
mapFieldMetadataItemToSettingsObjectDetailTableItem,
]);
const disabledObjectSettingsDetailItems = useMemo(() => {
const disabledFieldMetadataItems = settingsObjectFields?.filter(
(fieldMetadataItem) =>
!fieldMetadataItem.isActive && !fieldMetadataItem.isSystem,
);
return (
disabledFieldMetadataItems?.map(
mapFieldMetadataItemToSettingsObjectDetailTableItem,
) ?? []
);
}, [
settingsObjectFields,
mapFieldMetadataItemToSettingsObjectDetailTableItem,
]);
const sortedActiveObjectSettingsDetailItems = useSortedArray(
activeObjectSettingsDetailItems,
tableMetadata,
);
const sortedDisabledObjectSettingsDetailItems = useSortedArray(
disabledObjectSettingsDetailItems,
tableMetadata,
);
return (
<Table>
<StyledObjectFieldTableRow>
{tableMetadata.fields.map((item) => (
<SortableTableHeader
key={item.fieldName}
fieldName={item.fieldName}
label={item.fieldLabel}
tableId={tableMetadata.tableId}
initialSort={tableMetadata.initialSort}
/>
))}
<TableHeader></TableHeader>
</StyledObjectFieldTableRow>
{isNonEmptyArray(sortedActiveObjectSettingsDetailItems) && (
<TableSection title="Active">
{sortedActiveObjectSettingsDetailItems.map(
(objectSettingsDetailItem) => (
<SettingsObjectFieldItemTableRow
key={objectSettingsDetailItem.fieldMetadataItem.id}
settingsObjectDetailTableItem={objectSettingsDetailItem}
status="active"
mode={mode}
/>
),
)}
</TableSection>
)}
{isNonEmptyArray(sortedDisabledObjectSettingsDetailItems) && (
<TableSection
isInitiallyExpanded={mode === 'new-field' ? true : false}
title="Inactive"
>
{sortedDisabledObjectSettingsDetailItems.map(
(objectSettingsDetailItem) => (
<SettingsObjectFieldItemTableRow
key={objectSettingsDetailItem.fieldMetadataItem.id}
settingsObjectDetailTableItem={objectSettingsDetailItem}
status="disabled"
mode={mode}
/>
),
)}
</TableSection>
)}
</Table>
);
};