[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,194 @@
|
||||
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>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user