Removed use-context-selector completely (#12139)
This PR removes use-context-selector completely, so that any bug associated with state synchronization between recoil and use-context-selector disappears. There might be a slight performance decrease on the table, but since we have already improved the average performance per line by a lot, and that the performance bottleneck right now is the fetch more logic and the windowing solution we use, it is not relevant. Also the DX has become so hindered by this parallel state logic recently (think [cache invalidation](https://martinfowler.com/bliki/TwoHardThings.html)), that the main benefit we gain from this removal is the DX improvement. Fixes https://github.com/twentyhq/twenty/issues/12123 Fixes https://github.com/twentyhq/twenty/issues/12109
This commit is contained in:
@ -11,7 +11,6 @@ import { RecordShowContainer } from '@/object-record/record-show/components/Reco
|
||||
import { RecordShowEffect } from '@/object-record/record-show/components/RecordShowEffect';
|
||||
import { useRecordShowPage } from '@/object-record/record-show/hooks/useRecordShowPage';
|
||||
import { RecordSortsComponentInstanceContext } from '@/object-record/record-sort/states/context/RecordSortsComponentInstanceContext';
|
||||
import { RecordFieldValueSelectorContextProvider } from '@/object-record/record-store/contexts/RecordFieldValueSelectorContext';
|
||||
import { PageHeaderToggleCommandMenuButton } from '@/ui/layout/page-header/components/PageHeaderToggleCommandMenuButton';
|
||||
import { PageBody } from '@/ui/layout/page/components/PageBody';
|
||||
import { PageContainer } from '@/ui/layout/page/components/PageContainer';
|
||||
@ -30,57 +29,55 @@ export const RecordShowPage = () => {
|
||||
);
|
||||
|
||||
return (
|
||||
<RecordFieldValueSelectorContextProvider>
|
||||
<RecordFilterGroupsComponentInstanceContext.Provider
|
||||
<RecordFilterGroupsComponentInstanceContext.Provider
|
||||
value={{ instanceId: `record-show-${objectRecordId}` }}
|
||||
>
|
||||
<RecordFiltersComponentInstanceContext.Provider
|
||||
value={{ instanceId: `record-show-${objectRecordId}` }}
|
||||
>
|
||||
<RecordFiltersComponentInstanceContext.Provider
|
||||
<RecordSortsComponentInstanceContext.Provider
|
||||
value={{ instanceId: `record-show-${objectRecordId}` }}
|
||||
>
|
||||
<RecordSortsComponentInstanceContext.Provider
|
||||
value={{ instanceId: `record-show-${objectRecordId}` }}
|
||||
<ContextStoreComponentInstanceContext.Provider
|
||||
value={{ instanceId: MAIN_CONTEXT_STORE_INSTANCE_ID }}
|
||||
>
|
||||
<ContextStoreComponentInstanceContext.Provider
|
||||
value={{ instanceId: MAIN_CONTEXT_STORE_INSTANCE_ID }}
|
||||
<ActionMenuComponentInstanceContext.Provider
|
||||
value={{ instanceId: `record-show-${objectRecordId}` }}
|
||||
>
|
||||
<ActionMenuComponentInstanceContext.Provider
|
||||
value={{ instanceId: `record-show-${objectRecordId}` }}
|
||||
>
|
||||
<PageContainer>
|
||||
<RecordShowPageTitle
|
||||
objectNameSingular={objectNameSingular}
|
||||
objectRecordId={objectRecordId}
|
||||
/>
|
||||
<RecordShowPageHeader
|
||||
objectNameSingular={objectNameSingular}
|
||||
objectRecordId={objectRecordId}
|
||||
<PageContainer>
|
||||
<RecordShowPageTitle
|
||||
objectNameSingular={objectNameSingular}
|
||||
objectRecordId={objectRecordId}
|
||||
/>
|
||||
<RecordShowPageHeader
|
||||
objectNameSingular={objectNameSingular}
|
||||
objectRecordId={objectRecordId}
|
||||
>
|
||||
<RecordShowActionMenu />
|
||||
<PageHeaderToggleCommandMenuButton />
|
||||
</RecordShowPageHeader>
|
||||
<PageBody>
|
||||
<TimelineActivityContext.Provider
|
||||
value={{
|
||||
recordId: objectRecordId,
|
||||
}}
|
||||
>
|
||||
<RecordShowActionMenu />
|
||||
<PageHeaderToggleCommandMenuButton />
|
||||
</RecordShowPageHeader>
|
||||
<PageBody>
|
||||
<TimelineActivityContext.Provider
|
||||
value={{
|
||||
recordId: objectRecordId,
|
||||
}}
|
||||
>
|
||||
<RecordShowEffect
|
||||
objectNameSingular={objectNameSingular}
|
||||
recordId={objectRecordId}
|
||||
/>
|
||||
<RecordShowContainer
|
||||
objectNameSingular={objectNameSingular}
|
||||
objectRecordId={objectRecordId}
|
||||
loading={false}
|
||||
/>
|
||||
</TimelineActivityContext.Provider>
|
||||
</PageBody>
|
||||
</PageContainer>
|
||||
</ActionMenuComponentInstanceContext.Provider>
|
||||
</ContextStoreComponentInstanceContext.Provider>
|
||||
</RecordSortsComponentInstanceContext.Provider>
|
||||
</RecordFiltersComponentInstanceContext.Provider>
|
||||
</RecordFilterGroupsComponentInstanceContext.Provider>
|
||||
</RecordFieldValueSelectorContextProvider>
|
||||
<RecordShowEffect
|
||||
objectNameSingular={objectNameSingular}
|
||||
recordId={objectRecordId}
|
||||
/>
|
||||
<RecordShowContainer
|
||||
objectNameSingular={objectNameSingular}
|
||||
objectRecordId={objectRecordId}
|
||||
loading={false}
|
||||
/>
|
||||
</TimelineActivityContext.Provider>
|
||||
</PageBody>
|
||||
</PageContainer>
|
||||
</ActionMenuComponentInstanceContext.Provider>
|
||||
</ContextStoreComponentInstanceContext.Provider>
|
||||
</RecordSortsComponentInstanceContext.Provider>
|
||||
</RecordFiltersComponentInstanceContext.Provider>
|
||||
</RecordFilterGroupsComponentInstanceContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
@ -12,7 +12,6 @@ import { useGetRelationMetadata } from '@/object-metadata/hooks/useGetRelationMe
|
||||
import { useUpdateOneFieldMetadataItem } from '@/object-metadata/hooks/useUpdateOneFieldMetadataItem';
|
||||
import { formatFieldMetadataItemInput } from '@/object-metadata/utils/formatFieldMetadataItemInput';
|
||||
import { isLabelIdentifierField } from '@/object-metadata/utils/isLabelIdentifierField';
|
||||
import { RecordFieldValueSelectorContextProvider } from '@/object-record/record-store/contexts/RecordFieldValueSelectorContext';
|
||||
import { SaveAndCancelButtons } from '@/settings/components/SaveAndCancelButtons/SaveAndCancelButtons';
|
||||
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
|
||||
import { FIELD_NAME_MAXIMUM_LENGTH } from '@/settings/data-model/constants/FieldNameMaximumLength';
|
||||
@ -161,7 +160,7 @@ export const SettingsObjectFieldEdit = () => {
|
||||
};
|
||||
|
||||
return (
|
||||
<RecordFieldValueSelectorContextProvider>
|
||||
<>
|
||||
{/* eslint-disable-next-line react/jsx-props-no-spreading */}
|
||||
<FormProvider {...formConfig}>
|
||||
<SubMenuTopBarContainer
|
||||
@ -265,6 +264,6 @@ export const SettingsObjectFieldEdit = () => {
|
||||
</SettingsPageContainer>
|
||||
</SubMenuTopBarContainer>
|
||||
</FormProvider>
|
||||
</RecordFieldValueSelectorContextProvider>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@ -3,7 +3,6 @@ import { useFieldMetadataItem } from '@/object-metadata/hooks/useFieldMetadataIt
|
||||
import { useFilteredObjectMetadataItems } from '@/object-metadata/hooks/useFilteredObjectMetadataItems';
|
||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||
import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords';
|
||||
import { RecordFieldValueSelectorContextProvider } from '@/object-record/record-store/contexts/RecordFieldValueSelectorContext';
|
||||
import { SaveAndCancelButtons } from '@/settings/components/SaveAndCancelButtons/SaveAndCancelButtons';
|
||||
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
|
||||
import { SettingsDataModelNewFieldBreadcrumbDropDown } from '@/settings/data-model/components/SettingsDataModelNewFieldBreadcrumbDropDown';
|
||||
@ -27,6 +26,8 @@ import pick from 'lodash.pick';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { FormProvider, useForm } from 'react-hook-form';
|
||||
import { useParams, useSearchParams } from 'react-router-dom';
|
||||
import { H2Title } from 'twenty-ui/display';
|
||||
import { Section } from 'twenty-ui/layout';
|
||||
import { z } from 'zod';
|
||||
import { FieldMetadataType } from '~/generated-metadata/graphql';
|
||||
import { useNavigateApp } from '~/hooks/useNavigateApp';
|
||||
@ -35,8 +36,6 @@ import { DEFAULT_ICONS_BY_FIELD_TYPE } from '~/pages/settings/data-model/constan
|
||||
import { computeMetadataNameFromLabel } from '~/pages/settings/data-model/utils/compute-metadata-name-from-label.utils';
|
||||
import { isUndefinedOrNull } from '~/utils/isUndefinedOrNull';
|
||||
import { getSettingsPath } from '~/utils/navigation/getSettingsPath';
|
||||
import { H2Title } from 'twenty-ui/display';
|
||||
import { Section } from 'twenty-ui/layout';
|
||||
|
||||
type SettingsDataModelNewFieldFormValues = z.infer<
|
||||
ReturnType<typeof settingsFieldFormSchema>
|
||||
@ -200,87 +199,85 @@ export const SettingsObjectNewFieldConfigure = () => {
|
||||
if (!activeObjectMetadataItem) return null;
|
||||
|
||||
return (
|
||||
<RecordFieldValueSelectorContextProvider>
|
||||
<FormProvider // eslint-disable-next-line react/jsx-props-no-spreading
|
||||
{...formConfig}
|
||||
>
|
||||
<SubMenuTopBarContainer
|
||||
title={t`2. Configure field`}
|
||||
links={[
|
||||
{
|
||||
children: t`Workspace`,
|
||||
href: getSettingsPath(SettingsPath.Workspace),
|
||||
},
|
||||
{
|
||||
children: t`Objects`,
|
||||
href: getSettingsPath(SettingsPath.Objects),
|
||||
},
|
||||
{
|
||||
children: activeObjectMetadataItem.labelPlural,
|
||||
href: getSettingsPath(SettingsPath.ObjectDetail, {
|
||||
objectNamePlural,
|
||||
}),
|
||||
},
|
||||
<FormProvider // eslint-disable-next-line react/jsx-props-no-spreading
|
||||
{...formConfig}
|
||||
>
|
||||
<SubMenuTopBarContainer
|
||||
title={t`2. Configure field`}
|
||||
links={[
|
||||
{
|
||||
children: t`Workspace`,
|
||||
href: getSettingsPath(SettingsPath.Workspace),
|
||||
},
|
||||
{
|
||||
children: t`Objects`,
|
||||
href: getSettingsPath(SettingsPath.Objects),
|
||||
},
|
||||
{
|
||||
children: activeObjectMetadataItem.labelPlural,
|
||||
href: getSettingsPath(SettingsPath.ObjectDetail, {
|
||||
objectNamePlural,
|
||||
}),
|
||||
},
|
||||
|
||||
{ children: <SettingsDataModelNewFieldBreadcrumbDropDown /> },
|
||||
]}
|
||||
actionButton={
|
||||
<SaveAndCancelButtons
|
||||
isSaveDisabled={!canSave}
|
||||
isCancelDisabled={isSubmitting}
|
||||
onCancel={() =>
|
||||
navigate(
|
||||
SettingsPath.ObjectNewFieldSelect,
|
||||
{
|
||||
objectNamePlural,
|
||||
},
|
||||
{
|
||||
fieldType,
|
||||
},
|
||||
)
|
||||
}
|
||||
onSave={formConfig.handleSubmit(handleSave)}
|
||||
{ children: <SettingsDataModelNewFieldBreadcrumbDropDown /> },
|
||||
]}
|
||||
actionButton={
|
||||
<SaveAndCancelButtons
|
||||
isSaveDisabled={!canSave}
|
||||
isCancelDisabled={isSubmitting}
|
||||
onCancel={() =>
|
||||
navigate(
|
||||
SettingsPath.ObjectNewFieldSelect,
|
||||
{
|
||||
objectNamePlural,
|
||||
},
|
||||
{
|
||||
fieldType,
|
||||
},
|
||||
)
|
||||
}
|
||||
onSave={formConfig.handleSubmit(handleSave)}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<SettingsPageContainer>
|
||||
<Section>
|
||||
<H2Title
|
||||
title={t`Icon and Name`}
|
||||
description={t`The name and icon of this field`}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<SettingsPageContainer>
|
||||
<Section>
|
||||
<H2Title
|
||||
title={t`Icon and Name`}
|
||||
description={t`The name and icon of this field`}
|
||||
/>
|
||||
<SettingsDataModelFieldIconLabelForm
|
||||
maxLength={FIELD_NAME_MAXIMUM_LENGTH}
|
||||
canToggleSyncLabelWithName={
|
||||
fieldType !== FieldMetadataType.RELATION
|
||||
}
|
||||
/>
|
||||
</Section>
|
||||
<Section>
|
||||
<H2Title
|
||||
title={t`Values`}
|
||||
description={t`The values of this field`}
|
||||
/>
|
||||
<SettingsDataModelFieldSettingsFormCard
|
||||
fieldMetadataItem={{
|
||||
icon: formConfig.watch('icon'),
|
||||
label: formConfig.watch('label') || 'New Field',
|
||||
settings: formConfig.watch('settings') || null,
|
||||
type: fieldType as FieldMetadataType,
|
||||
}}
|
||||
objectMetadataItem={activeObjectMetadataItem}
|
||||
/>
|
||||
</Section>
|
||||
<Section>
|
||||
<H2Title
|
||||
title={t`Description`}
|
||||
description={t`The description of this field`}
|
||||
/>
|
||||
<SettingsDataModelFieldDescriptionForm />
|
||||
</Section>
|
||||
</SettingsPageContainer>
|
||||
</SubMenuTopBarContainer>
|
||||
</FormProvider>
|
||||
</RecordFieldValueSelectorContextProvider>
|
||||
<SettingsDataModelFieldIconLabelForm
|
||||
maxLength={FIELD_NAME_MAXIMUM_LENGTH}
|
||||
canToggleSyncLabelWithName={
|
||||
fieldType !== FieldMetadataType.RELATION
|
||||
}
|
||||
/>
|
||||
</Section>
|
||||
<Section>
|
||||
<H2Title
|
||||
title={t`Values`}
|
||||
description={t`The values of this field`}
|
||||
/>
|
||||
<SettingsDataModelFieldSettingsFormCard
|
||||
fieldMetadataItem={{
|
||||
icon: formConfig.watch('icon'),
|
||||
label: formConfig.watch('label') || 'New Field',
|
||||
settings: formConfig.watch('settings') || null,
|
||||
type: fieldType as FieldMetadataType,
|
||||
}}
|
||||
objectMetadataItem={activeObjectMetadataItem}
|
||||
/>
|
||||
</Section>
|
||||
<Section>
|
||||
<H2Title
|
||||
title={t`Description`}
|
||||
description={t`The description of this field`}
|
||||
/>
|
||||
<SettingsDataModelFieldDescriptionForm />
|
||||
</Section>
|
||||
</SettingsPageContainer>
|
||||
</SubMenuTopBarContainer>
|
||||
</FormProvider>
|
||||
);
|
||||
};
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
import { useFilteredObjectMetadataItems } from '@/object-metadata/hooks/useFilteredObjectMetadataItems';
|
||||
import { RecordFieldValueSelectorContextProvider } from '@/object-record/record-store/contexts/RecordFieldValueSelectorContext';
|
||||
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
|
||||
import { SettingsDataModelNewFieldBreadcrumbDropDown } from '@/settings/data-model/components/SettingsDataModelNewFieldBreadcrumbDropDown';
|
||||
import { SETTINGS_FIELD_TYPE_CONFIGS } from '@/settings/data-model/constants/SettingsFieldTypeConfigs';
|
||||
@ -10,15 +9,15 @@ import { AppPath } from '@/types/AppPath';
|
||||
import { SettingsPath } from '@/types/SettingsPath';
|
||||
import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { t } from '@lingui/core/macro';
|
||||
import { useEffect } from 'react';
|
||||
import { FormProvider, useForm } from 'react-hook-form';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { z } from 'zod';
|
||||
import { FieldMetadataType } from '~/generated-metadata/graphql';
|
||||
import { useNavigateApp } from '~/hooks/useNavigateApp';
|
||||
import { getSettingsPath } from '~/utils/navigation/getSettingsPath';
|
||||
import { t } from '@lingui/core/macro';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
export const settingsDataModelFieldTypeFormSchema = z.object({
|
||||
type: z.enum(
|
||||
@ -64,32 +63,30 @@ export const SettingsObjectNewFieldSelect = () => {
|
||||
if (!activeObjectMetadataItem) return null;
|
||||
|
||||
return (
|
||||
<RecordFieldValueSelectorContextProvider>
|
||||
<FormProvider // eslint-disable-next-line react/jsx-props-no-spreading
|
||||
{...formMethods}
|
||||
<FormProvider // eslint-disable-next-line react/jsx-props-no-spreading
|
||||
{...formMethods}
|
||||
>
|
||||
<SubMenuTopBarContainer
|
||||
title={t`1. Select a field type`}
|
||||
links={[
|
||||
{ children: t`Workspace`, href: '/settings/workspace' },
|
||||
{ children: t`Objects`, href: '/settings/objects' },
|
||||
{
|
||||
children: activeObjectMetadataItem.labelPlural,
|
||||
href: getSettingsPath(SettingsPath.ObjectDetail, {
|
||||
objectNamePlural,
|
||||
}),
|
||||
},
|
||||
{ children: <SettingsDataModelNewFieldBreadcrumbDropDown /> },
|
||||
]}
|
||||
>
|
||||
<SubMenuTopBarContainer
|
||||
title={t`1. Select a field type`}
|
||||
links={[
|
||||
{ children: t`Workspace`, href: '/settings/workspace' },
|
||||
{ children: t`Objects`, href: '/settings/objects' },
|
||||
{
|
||||
children: activeObjectMetadataItem.labelPlural,
|
||||
href: getSettingsPath(SettingsPath.ObjectDetail, {
|
||||
objectNamePlural,
|
||||
}),
|
||||
},
|
||||
{ children: <SettingsDataModelNewFieldBreadcrumbDropDown /> },
|
||||
]}
|
||||
>
|
||||
<SettingsPageContainer>
|
||||
<SettingsObjectNewFieldSelector
|
||||
objectNamePlural={objectNamePlural}
|
||||
excludedFieldTypes={excludedFieldTypes}
|
||||
/>
|
||||
</SettingsPageContainer>
|
||||
</SubMenuTopBarContainer>
|
||||
</FormProvider>
|
||||
</RecordFieldValueSelectorContextProvider>
|
||||
<SettingsPageContainer>
|
||||
<SettingsObjectNewFieldSelector
|
||||
objectNamePlural={objectNamePlural}
|
||||
excludedFieldTypes={excludedFieldTypes}
|
||||
/>
|
||||
</SettingsPageContainer>
|
||||
</SubMenuTopBarContainer>
|
||||
</FormProvider>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user