[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
@ -1,27 +1,22 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useNavigate, useParams } from 'react-router-dom';
|
||||
import styled from '@emotion/styled';
|
||||
import { H2Title, IconMinus, IconPlus, IconSettings } from 'twenty-ui';
|
||||
import { useEffect } from 'react';
|
||||
import { useNavigate, useParams } from 'react-router-dom';
|
||||
import { H2Title, IconPlus, IconSettings } from 'twenty-ui';
|
||||
|
||||
import { useFieldMetadataItem } from '@/object-metadata/hooks/useFieldMetadataItem';
|
||||
import { useFilteredObjectMetadataItems } from '@/object-metadata/hooks/useFilteredObjectMetadataItems';
|
||||
import { isLabelIdentifierField } from '@/object-metadata/utils/isLabelIdentifierField';
|
||||
import { SaveAndCancelButtons } from '@/settings/components/SaveAndCancelButtons/SaveAndCancelButtons';
|
||||
import { SettingsHeaderContainer } from '@/settings/components/SettingsHeaderContainer';
|
||||
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
|
||||
import {
|
||||
SettingsObjectFieldItemTableRow,
|
||||
StyledObjectFieldTableRow,
|
||||
} from '@/settings/data-model/object-details/components/SettingsObjectFieldItemTableRow';
|
||||
|
||||
import { useFieldMetadataItem } from '@/object-metadata/hooks/useFieldMetadataItem';
|
||||
import { settingsObjectFieldsFamilyState } from '@/settings/data-model/object-details/states/settingsObjectFieldsFamilyState';
|
||||
import { AppPath } from '@/types/AppPath';
|
||||
import { Button } from '@/ui/input/button/components/Button';
|
||||
import { LightIconButton } from '@/ui/input/button/components/LightIconButton';
|
||||
import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer';
|
||||
import { Section } from '@/ui/layout/section/components/Section';
|
||||
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 { Breadcrumb } from '@/ui/navigation/bread-crumb/components/Breadcrumb';
|
||||
import { useRecoilState } from 'recoil';
|
||||
import { SettingsObjectFieldTable } from '~/pages/settings/data-model/SettingsObjectFieldTable';
|
||||
|
||||
const StyledSection = styled(Section)`
|
||||
display: flex;
|
||||
@ -43,62 +38,52 @@ export const SettingsObjectNewFieldStep1 = () => {
|
||||
const activeObjectMetadataItem =
|
||||
findActiveObjectMetadataItemBySlug(objectSlug);
|
||||
|
||||
const [settingsObjectFields] = useRecoilState(
|
||||
settingsObjectFieldsFamilyState({
|
||||
objectMetadataItemId: activeObjectMetadataItem?.id,
|
||||
}),
|
||||
);
|
||||
|
||||
const { activateMetadataField, deactivateMetadataField } =
|
||||
useFieldMetadataItem();
|
||||
const [metadataFields, setMetadataFields] = useState(
|
||||
activeObjectMetadataItem?.fields ?? [],
|
||||
);
|
||||
|
||||
const activeMetadataFields = metadataFields.filter((field) => field.isActive);
|
||||
const deactivatedMetadataFields = metadataFields.filter(
|
||||
(field) => !field.isActive,
|
||||
);
|
||||
|
||||
const canSave = metadataFields.some(
|
||||
const canSave = settingsObjectFields?.some(
|
||||
(field, index) =>
|
||||
field.isActive !== activeObjectMetadataItem?.fields[index].isActive,
|
||||
);
|
||||
|
||||
const handleSave = async () => {
|
||||
if (!activeObjectMetadataItem || !settingsObjectFields) {
|
||||
return;
|
||||
}
|
||||
|
||||
await Promise.all(
|
||||
settingsObjectFields.map((fieldMetadataItem, index) => {
|
||||
if (
|
||||
fieldMetadataItem.isActive ===
|
||||
activeObjectMetadataItem.fields[index].isActive
|
||||
) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return fieldMetadataItem.isActive
|
||||
? activateMetadataField(fieldMetadataItem)
|
||||
: deactivateMetadataField(fieldMetadataItem);
|
||||
}),
|
||||
);
|
||||
|
||||
navigate(`/settings/objects/${objectSlug}`);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (!activeObjectMetadataItem) {
|
||||
navigate(AppPath.NotFound);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!metadataFields.length)
|
||||
setMetadataFields(activeObjectMetadataItem.fields);
|
||||
}, [activeObjectMetadataItem, metadataFields.length, navigate]);
|
||||
}, [activeObjectMetadataItem, navigate]);
|
||||
|
||||
if (!activeObjectMetadataItem) return null;
|
||||
|
||||
const handleToggleField = (fieldMetadataId: string) =>
|
||||
setMetadataFields((previousFields) =>
|
||||
previousFields.map((field) =>
|
||||
field.id === fieldMetadataId
|
||||
? { ...field, isActive: !field.isActive }
|
||||
: field,
|
||||
),
|
||||
);
|
||||
|
||||
const handleSave = async () => {
|
||||
await Promise.all(
|
||||
metadataFields.map((metadataField, index) => {
|
||||
if (
|
||||
metadataField.isActive ===
|
||||
activeObjectMetadataItem.fields[index].isActive
|
||||
) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return metadataField.isActive
|
||||
? activateMetadataField(metadataField)
|
||||
: deactivateMetadataField(metadataField);
|
||||
}),
|
||||
);
|
||||
|
||||
navigate(`/settings/objects/${objectSlug}`);
|
||||
};
|
||||
|
||||
return (
|
||||
<SubMenuTopBarContainer Icon={IconSettings} title="Settings">
|
||||
<SettingsPageContainer>
|
||||
@ -126,58 +111,10 @@ export const SettingsObjectNewFieldStep1 = () => {
|
||||
title="Check deactivated fields"
|
||||
description="Before creating a custom field, check if it already exists in the deactivated section."
|
||||
/>
|
||||
<Table>
|
||||
<StyledObjectFieldTableRow>
|
||||
<TableHeader>Name</TableHeader>
|
||||
<TableHeader>Field type</TableHeader>
|
||||
<TableHeader>Data type</TableHeader>
|
||||
<TableHeader></TableHeader>
|
||||
</StyledObjectFieldTableRow>
|
||||
{!!activeMetadataFields.length && (
|
||||
<TableSection isInitiallyExpanded={false} title="Active">
|
||||
{activeMetadataFields.map((activeMetadataField) => (
|
||||
<SettingsObjectFieldItemTableRow
|
||||
key={activeMetadataField.id}
|
||||
fieldMetadataItem={activeMetadataField}
|
||||
isRemoteObjectField={activeObjectMetadataItem.isRemote}
|
||||
ActionIcon={
|
||||
isLabelIdentifierField({
|
||||
fieldMetadataItem: activeMetadataField,
|
||||
objectMetadataItem: activeObjectMetadataItem,
|
||||
}) ? undefined : (
|
||||
<LightIconButton
|
||||
Icon={IconMinus}
|
||||
accent="tertiary"
|
||||
onClick={() =>
|
||||
handleToggleField(activeMetadataField.id)
|
||||
}
|
||||
/>
|
||||
)
|
||||
}
|
||||
/>
|
||||
))}
|
||||
</TableSection>
|
||||
)}
|
||||
{!!deactivatedMetadataFields.length && (
|
||||
<TableSection title="Disabled">
|
||||
{deactivatedMetadataFields.map((deactivatedMetadataField) => (
|
||||
<SettingsObjectFieldItemTableRow
|
||||
key={deactivatedMetadataField.name}
|
||||
fieldMetadataItem={deactivatedMetadataField}
|
||||
ActionIcon={
|
||||
<LightIconButton
|
||||
Icon={IconPlus}
|
||||
accent="tertiary"
|
||||
onClick={() =>
|
||||
handleToggleField(deactivatedMetadataField.id)
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
))}
|
||||
</TableSection>
|
||||
)}
|
||||
</Table>
|
||||
<SettingsObjectFieldTable
|
||||
objectMetadataItem={activeObjectMetadataItem}
|
||||
mode="new-field"
|
||||
/>
|
||||
<StyledAddCustomFieldButton
|
||||
Icon={IconPlus}
|
||||
title="Add Custom Field"
|
||||
|
||||
Reference in New Issue
Block a user