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:
@ -191,7 +191,6 @@
|
||||
"tsup": "^8.2.4",
|
||||
"type-fest": "4.10.1",
|
||||
"typescript": "5.3.3",
|
||||
"use-context-selector": "^2.0.0",
|
||||
"use-debounce": "^10.0.0",
|
||||
"uuid": "^9.0.0",
|
||||
"vite-tsconfig-paths": "^4.2.1",
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
import { CalendarEvent } from '@/activities/calendar/types/CalendarEvent';
|
||||
import { useSetRecordValue } from '@/object-record/record-store/contexts/RecordFieldValueSelectorContext';
|
||||
import { useUpsertRecordsInStore } from '@/object-record/record-store/hooks/useUpsertRecordsInStore';
|
||||
import { useEffect } from 'react';
|
||||
|
||||
@ -11,7 +10,6 @@ export const CalendarEventDetailsEffect = ({
|
||||
record,
|
||||
}: CalendarEventDetailsEffectProps) => {
|
||||
const { upsertRecords } = useUpsertRecordsInStore();
|
||||
const setRecordValueInContextSelector = useSetRecordValue();
|
||||
|
||||
useEffect(() => {
|
||||
if (!record) {
|
||||
@ -19,8 +17,7 @@ export const CalendarEventDetailsEffect = ({
|
||||
}
|
||||
|
||||
upsertRecords([record]);
|
||||
setRecordValueInContextSelector(record.id, record);
|
||||
}, [record, upsertRecords, setRecordValueInContextSelector]);
|
||||
}, [record, upsertRecords]);
|
||||
|
||||
return <></>;
|
||||
};
|
||||
|
||||
@ -5,7 +5,6 @@ import { EventFieldDiffValue } from '@/activities/timeline-activities/rows/main-
|
||||
import { EventFieldDiffValueEffect } from '@/activities/timeline-activities/rows/main-object/components/EventFieldDiffValueEffect';
|
||||
import { FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
|
||||
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||
import { RecordFieldValueSelectorContextProvider } from '@/object-record/record-store/contexts/RecordFieldValueSelectorContext';
|
||||
import { Trans } from '@lingui/react/macro';
|
||||
|
||||
type EventFieldDiffProps = {
|
||||
@ -54,29 +53,27 @@ export const EventFieldDiff = ({
|
||||
isObjectEmpty(diffRecord));
|
||||
|
||||
return (
|
||||
<RecordFieldValueSelectorContextProvider>
|
||||
<StyledEventFieldDiffContainer>
|
||||
<EventFieldDiffLabel fieldMetadataItem={fieldMetadataItem} />→
|
||||
{isUpdatedToEmpty ? (
|
||||
<StyledEmptyValue>
|
||||
<Trans>Empty</Trans>
|
||||
</StyledEmptyValue>
|
||||
) : (
|
||||
<>
|
||||
<EventFieldDiffValueEffect
|
||||
diffArtificialRecordStoreId={diffArtificialRecordStoreId}
|
||||
mainObjectMetadataItem={mainObjectMetadataItem}
|
||||
fieldMetadataItem={fieldMetadataItem}
|
||||
diffRecord={diffRecord}
|
||||
/>
|
||||
<EventFieldDiffValue
|
||||
diffArtificialRecordStoreId={diffArtificialRecordStoreId}
|
||||
mainObjectMetadataItem={mainObjectMetadataItem}
|
||||
fieldMetadataItem={fieldMetadataItem}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</StyledEventFieldDiffContainer>
|
||||
</RecordFieldValueSelectorContextProvider>
|
||||
<StyledEventFieldDiffContainer>
|
||||
<EventFieldDiffLabel fieldMetadataItem={fieldMetadataItem} />→
|
||||
{isUpdatedToEmpty ? (
|
||||
<StyledEmptyValue>
|
||||
<Trans>Empty</Trans>
|
||||
</StyledEmptyValue>
|
||||
) : (
|
||||
<>
|
||||
<EventFieldDiffValueEffect
|
||||
diffArtificialRecordStoreId={diffArtificialRecordStoreId}
|
||||
mainObjectMetadataItem={mainObjectMetadataItem}
|
||||
fieldMetadataItem={fieldMetadataItem}
|
||||
diffRecord={diffRecord}
|
||||
/>
|
||||
<EventFieldDiffValue
|
||||
diffArtificialRecordStoreId={diffArtificialRecordStoreId}
|
||||
mainObjectMetadataItem={mainObjectMetadataItem}
|
||||
fieldMetadataItem={fieldMetadataItem}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</StyledEventFieldDiffContainer>
|
||||
);
|
||||
};
|
||||
|
||||
@ -3,7 +3,6 @@ import { useSetRecoilState } from 'recoil';
|
||||
|
||||
import { FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
|
||||
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||
import { useSetRecordValue } from '@/object-record/record-store/contexts/RecordFieldValueSelectorContext';
|
||||
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
@ -21,7 +20,6 @@ export const EventFieldDiffValueEffect = ({
|
||||
const setEntity = useSetRecoilState(
|
||||
recordStoreFamilyState(diffArtificialRecordStoreId),
|
||||
);
|
||||
const setRecordValue = useSetRecordValue();
|
||||
|
||||
useEffect(() => {
|
||||
if (!isDefined(diffRecord)) return;
|
||||
@ -33,14 +31,12 @@ export const EventFieldDiffValueEffect = ({
|
||||
};
|
||||
|
||||
setEntity(forgedObjectRecord);
|
||||
setRecordValue(forgedObjectRecord.id, forgedObjectRecord);
|
||||
}, [
|
||||
diffRecord,
|
||||
diffArtificialRecordStoreId,
|
||||
fieldMetadataItem.name,
|
||||
mainObjectMetadataItem.nameSingular,
|
||||
setEntity,
|
||||
setRecordValue,
|
||||
]);
|
||||
|
||||
return <></>;
|
||||
|
||||
@ -4,10 +4,6 @@ import { FIND_ONE_CALENDAR_EVENT_OPERATION_SIGNATURE } from '@/activities/calend
|
||||
import { CalendarEvent } from '@/activities/calendar/types/CalendarEvent';
|
||||
import { viewableRecordIdComponentState } from '@/command-menu/pages/record-page/states/viewableRecordIdComponentState';
|
||||
import { useFindOneRecord } from '@/object-record/hooks/useFindOneRecord';
|
||||
import {
|
||||
RecordFieldValueSelectorContextProvider,
|
||||
useSetRecordValue,
|
||||
} from '@/object-record/record-store/contexts/RecordFieldValueSelectorContext';
|
||||
import { useUpsertRecordsInStore } from '@/object-record/record-store/hooks/useUpsertRecordsInStore';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
|
||||
@ -16,7 +12,6 @@ export const CommandMenuCalendarEventPage = () => {
|
||||
const viewableRecordId = useRecoilComponentValueV2(
|
||||
viewableRecordIdComponentState,
|
||||
);
|
||||
const setRecordValueInContextSelector = useSetRecordValue();
|
||||
|
||||
const { record: calendarEvent } = useFindOneRecord<CalendarEvent>({
|
||||
objectNameSingular:
|
||||
@ -26,7 +21,6 @@ export const CommandMenuCalendarEventPage = () => {
|
||||
// TODO: this is not executed on sub-sequent runs, make sure that it is intended
|
||||
onCompleted: (record) => {
|
||||
upsertRecords([record]);
|
||||
setRecordValueInContextSelector(record.id, record);
|
||||
},
|
||||
});
|
||||
|
||||
@ -35,9 +29,9 @@ export const CommandMenuCalendarEventPage = () => {
|
||||
}
|
||||
|
||||
return (
|
||||
<RecordFieldValueSelectorContextProvider>
|
||||
<>
|
||||
<CalendarEventDetailsEffect record={calendarEvent} />
|
||||
<CalendarEventDetails calendarEvent={calendarEvent} />
|
||||
</RecordFieldValueSelectorContextProvider>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@ -10,7 +10,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 { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';
|
||||
import { useComponentInstanceStateContext } from '@/ui/utilities/state/component-state/hooks/useComponentInstanceStateContext';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
@ -72,24 +71,22 @@ export const CommandMenuRecordPage = () => {
|
||||
value={{ instanceId: commandMenuPageInstanceId }}
|
||||
>
|
||||
<StyledRightDrawerRecord isMobile={isMobile}>
|
||||
<RecordFieldValueSelectorContextProvider>
|
||||
<TimelineActivityContext.Provider
|
||||
value={{
|
||||
recordId: objectRecordId,
|
||||
}}
|
||||
>
|
||||
<RecordShowEffect
|
||||
objectNameSingular={objectNameSingular}
|
||||
recordId={objectRecordId}
|
||||
/>
|
||||
<RecordShowContainer
|
||||
objectNameSingular={objectNameSingular}
|
||||
objectRecordId={objectRecordId}
|
||||
loading={false}
|
||||
isInRightDrawer={true}
|
||||
/>
|
||||
</TimelineActivityContext.Provider>
|
||||
</RecordFieldValueSelectorContextProvider>
|
||||
<TimelineActivityContext.Provider
|
||||
value={{
|
||||
recordId: objectRecordId,
|
||||
}}
|
||||
>
|
||||
<RecordShowEffect
|
||||
objectNameSingular={objectNameSingular}
|
||||
recordId={objectRecordId}
|
||||
/>
|
||||
<RecordShowContainer
|
||||
objectNameSingular={objectNameSingular}
|
||||
objectRecordId={objectRecordId}
|
||||
loading={false}
|
||||
isInRightDrawer={true}
|
||||
/>
|
||||
</TimelineActivityContext.Provider>
|
||||
</StyledRightDrawerRecord>
|
||||
</ActionMenuComponentInstanceContext.Provider>
|
||||
</ContextStoreComponentInstanceContext.Provider>
|
||||
|
||||
@ -2,7 +2,6 @@ import { useContext } from 'react';
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
|
||||
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
||||
import { useSetRecordFieldValue } from '@/object-record/record-store/contexts/RecordFieldValueSelectorContext';
|
||||
import { recordStoreFamilySelector } from '@/object-record/record-store/states/selectors/recordStoreFamilySelector';
|
||||
import { generateEmptyFieldValue } from '@/object-record/utils/generateEmptyFieldValue';
|
||||
|
||||
@ -17,8 +16,6 @@ export const useClearField = () => {
|
||||
|
||||
const [updateRecord] = useUpdateRecord();
|
||||
|
||||
const setRecordFieldValue = useSetRecordFieldValue();
|
||||
|
||||
const clearField = useRecoilCallback(
|
||||
({ snapshot, set }) =>
|
||||
() => {
|
||||
@ -51,8 +48,6 @@ export const useClearField = () => {
|
||||
emptyFieldValue,
|
||||
);
|
||||
|
||||
setRecordFieldValue(recordId, fieldName, emptyFieldValue);
|
||||
|
||||
updateRecord?.({
|
||||
variables: {
|
||||
where: { id: recordId },
|
||||
@ -62,7 +57,7 @@ export const useClearField = () => {
|
||||
},
|
||||
});
|
||||
},
|
||||
[recordId, fieldDefinition, updateRecord, setRecordFieldValue],
|
||||
[recordId, fieldDefinition, updateRecord],
|
||||
);
|
||||
|
||||
return clearField;
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
import { useContext } from 'react';
|
||||
|
||||
import { isFieldValueEmpty } from '@/object-record/record-field/utils/isFieldValueEmpty';
|
||||
import { useRecordFieldValue } from '@/object-record/record-store/contexts/RecordFieldValueSelectorContext';
|
||||
|
||||
import { FieldContext } from '../contexts/FieldContext';
|
||||
import { useRecordFieldValue } from '@/object-record/record-store/contexts/RecordFieldValueSelectorContext';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { FieldContext } from '../contexts/FieldContext';
|
||||
|
||||
export const useIsFieldEmpty = () => {
|
||||
const { recordId, fieldDefinition, overridenIsFieldEmpty } =
|
||||
|
||||
@ -1,102 +0,0 @@
|
||||
import { Meta, StoryObj } from '@storybook/react';
|
||||
import { useEffect } from 'react';
|
||||
import { useSetRecoilState } from 'recoil';
|
||||
|
||||
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
|
||||
import { RelationFromManyFieldDisplay } from '@/object-record/record-field/meta-types/display/components/RelationFromManyFieldDisplay';
|
||||
import { FieldDefinition } from '@/object-record/record-field/types/FieldDefinition';
|
||||
import { FieldMetadata } from '@/object-record/record-field/types/FieldMetadata';
|
||||
import {
|
||||
RecordFieldValueSelectorContextProvider,
|
||||
useSetRecordFieldValue,
|
||||
} from '@/object-record/record-store/contexts/RecordFieldValueSelectorContext';
|
||||
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
|
||||
import { ChipGeneratorsDecorator } from '~/testing/decorators/ChipGeneratorsDecorator';
|
||||
import { MemoryRouterDecorator } from '~/testing/decorators/MemoryRouterDecorator';
|
||||
import { getProfilingStory } from '~/testing/profiling/utils/getProfilingStory';
|
||||
|
||||
import { ComponentDecorator } from 'twenty-ui/testing';
|
||||
import {
|
||||
fieldValue,
|
||||
otherPersonMock,
|
||||
relationFromManyFieldDisplayMock,
|
||||
} from './relationFromManyFieldDisplayMock';
|
||||
|
||||
const RelationFieldValueSetterEffect = () => {
|
||||
const setEntity = useSetRecoilState(
|
||||
recordStoreFamilyState(relationFromManyFieldDisplayMock.recordId),
|
||||
);
|
||||
|
||||
const setRelationEntity = useSetRecoilState(
|
||||
recordStoreFamilyState(relationFromManyFieldDisplayMock.relationRecordId),
|
||||
);
|
||||
|
||||
const setRecordFieldValue = useSetRecordFieldValue();
|
||||
|
||||
useEffect(() => {
|
||||
setEntity(relationFromManyFieldDisplayMock.entityValue);
|
||||
setRelationEntity(relationFromManyFieldDisplayMock.relationFieldValue);
|
||||
|
||||
setRecordFieldValue(
|
||||
relationFromManyFieldDisplayMock.entityValue.id,
|
||||
'company',
|
||||
[relationFromManyFieldDisplayMock.entityValue],
|
||||
);
|
||||
setRecordFieldValue(otherPersonMock.entityValue.id, 'company', [
|
||||
relationFromManyFieldDisplayMock.entityValue,
|
||||
]);
|
||||
setRecordFieldValue(
|
||||
relationFromManyFieldDisplayMock.relationFieldValue.id,
|
||||
'company',
|
||||
relationFromManyFieldDisplayMock.relationFieldValue,
|
||||
);
|
||||
}, [setEntity, setRelationEntity, setRecordFieldValue]);
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
const meta: Meta = {
|
||||
title: 'UI/Data/Field/Display/RelationFromManyFieldDisplay',
|
||||
decorators: [
|
||||
MemoryRouterDecorator,
|
||||
ChipGeneratorsDecorator,
|
||||
(Story) => (
|
||||
<RecordFieldValueSelectorContextProvider>
|
||||
<FieldContext.Provider
|
||||
value={{
|
||||
recordId: relationFromManyFieldDisplayMock.recordId,
|
||||
isLabelIdentifier: false,
|
||||
fieldDefinition: {
|
||||
...relationFromManyFieldDisplayMock.fieldDefinition,
|
||||
} as unknown as FieldDefinition<FieldMetadata>,
|
||||
isReadOnly: false,
|
||||
}}
|
||||
>
|
||||
<RelationFieldValueSetterEffect />
|
||||
<Story />
|
||||
</FieldContext.Provider>
|
||||
</RecordFieldValueSelectorContextProvider>
|
||||
),
|
||||
ComponentDecorator,
|
||||
],
|
||||
component: RelationFromManyFieldDisplay,
|
||||
argTypes: { value: { control: 'date' } },
|
||||
args: { fieldValue: fieldValue },
|
||||
parameters: {
|
||||
chromatic: { disableSnapshot: true },
|
||||
},
|
||||
};
|
||||
|
||||
export default meta;
|
||||
|
||||
type Story = StoryObj<typeof RelationFromManyFieldDisplay>;
|
||||
|
||||
export const Default: Story = {};
|
||||
|
||||
// TODO: optimize this component once we have morph many
|
||||
export const Performance = getProfilingStory({
|
||||
componentName: 'RelationFromManyFieldDisplay',
|
||||
averageThresholdInMs: 1,
|
||||
numberOfRuns: 20,
|
||||
numberOfTestsPerRun: 100,
|
||||
});
|
||||
@ -1,13 +1,13 @@
|
||||
import { isNonEmptyString } from '@sniptt/guards';
|
||||
import { useContext } from 'react';
|
||||
|
||||
import { PreComputedChipGeneratorsContext } from '@/object-metadata/contexts/PreComputedChipGeneratorsContext';
|
||||
import { isFieldFullName } from '@/object-record/record-field/types/guards/isFieldFullName';
|
||||
import { isFieldNumber } from '@/object-record/record-field/types/guards/isFieldNumber';
|
||||
import { isFieldText } from '@/object-record/record-field/types/guards/isFieldText';
|
||||
import { useRecordValue } from '@/object-record/record-store/contexts/RecordFieldValueSelectorContext';
|
||||
import { isNonEmptyString } from '@sniptt/guards';
|
||||
import { useContext } from 'react';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
|
||||
import { isFieldActor } from '@/object-record/record-field/types/guards/isFieldActor';
|
||||
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { FieldContext } from '../../contexts/FieldContext';
|
||||
|
||||
@ -38,7 +38,7 @@ export const useChipFieldDisplay = () => {
|
||||
? fieldDefinition.metadata.objectMetadataNameSingular
|
||||
: undefined;
|
||||
|
||||
const recordValue = useRecordValue(recordId);
|
||||
const recordValue = useRecoilValue(recordStoreFamilyState(recordId));
|
||||
|
||||
if (!isNonEmptyString(objectNameSingular)) {
|
||||
throw new Error('Object metadata name singular is not a non-empty string');
|
||||
|
||||
@ -11,7 +11,6 @@ import { recordIndexViewTypeState } from '@/object-record/record-index/states/re
|
||||
|
||||
import { InformationBannerWrapper } from '@/information-banner/components/InformationBannerWrapper';
|
||||
import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext';
|
||||
import { RecordFieldValueSelectorContextProvider } from '@/object-record/record-store/contexts/RecordFieldValueSelectorContext';
|
||||
import { SpreadsheetImportProvider } from '@/spreadsheet-import/provider/components/SpreadsheetImportProvider';
|
||||
|
||||
import { RecordIndexFiltersToContextStoreEffect } from '@/object-record/record-index/components/RecordIndexFiltersToContextStoreEffect';
|
||||
@ -48,48 +47,46 @@ export const RecordIndexContainer = () => {
|
||||
<>
|
||||
<StyledContainer>
|
||||
<InformationBannerWrapper />
|
||||
<RecordFieldValueSelectorContextProvider>
|
||||
<SpreadsheetImportProvider>
|
||||
<ViewBar
|
||||
viewBarId={recordIndexId}
|
||||
optionsDropdownButton={
|
||||
<ObjectOptionsDropdown
|
||||
recordIndexId={recordIndexId}
|
||||
objectMetadataItem={objectMetadataItem}
|
||||
viewType={recordIndexViewType ?? ViewType.Table}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<RecordIndexViewBarEffect
|
||||
objectNamePlural={objectNamePlural}
|
||||
<SpreadsheetImportProvider>
|
||||
<ViewBar
|
||||
viewBarId={recordIndexId}
|
||||
optionsDropdownButton={
|
||||
<ObjectOptionsDropdown
|
||||
recordIndexId={recordIndexId}
|
||||
objectMetadataItem={objectMetadataItem}
|
||||
viewType={recordIndexViewType ?? ViewType.Table}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<RecordIndexViewBarEffect
|
||||
objectNamePlural={objectNamePlural}
|
||||
viewBarId={recordIndexId}
|
||||
/>
|
||||
</SpreadsheetImportProvider>
|
||||
<RecordIndexFiltersToContextStoreEffect />
|
||||
{recordIndexViewType === ViewType.Table && (
|
||||
<>
|
||||
<RecordIndexTableContainer
|
||||
recordTableId={recordIndexId}
|
||||
viewBarId={recordIndexId}
|
||||
/>
|
||||
</SpreadsheetImportProvider>
|
||||
<RecordIndexFiltersToContextStoreEffect />
|
||||
{recordIndexViewType === ViewType.Table && (
|
||||
<>
|
||||
<RecordIndexTableContainer
|
||||
recordTableId={recordIndexId}
|
||||
viewBarId={recordIndexId}
|
||||
/>
|
||||
<RecordIndexTableContainerEffect />
|
||||
</>
|
||||
)}
|
||||
{recordIndexViewType === ViewType.Kanban && (
|
||||
<StyledContainerWithPadding>
|
||||
<RecordIndexBoardContainer
|
||||
recordBoardId={recordIndexId}
|
||||
viewBarId={recordIndexId}
|
||||
objectNameSingular={objectNameSingular}
|
||||
/>
|
||||
<RecordIndexBoardDataLoader
|
||||
objectNameSingular={objectNameSingular}
|
||||
recordBoardId={recordIndexId}
|
||||
/>
|
||||
<RecordIndexBoardDataLoaderEffect recordBoardId={recordIndexId} />
|
||||
</StyledContainerWithPadding>
|
||||
)}
|
||||
</RecordFieldValueSelectorContextProvider>
|
||||
<RecordIndexTableContainerEffect />
|
||||
</>
|
||||
)}
|
||||
{recordIndexViewType === ViewType.Kanban && (
|
||||
<StyledContainerWithPadding>
|
||||
<RecordIndexBoardContainer
|
||||
recordBoardId={recordIndexId}
|
||||
viewBarId={recordIndexId}
|
||||
objectNameSingular={objectNameSingular}
|
||||
/>
|
||||
<RecordIndexBoardDataLoader
|
||||
objectNameSingular={objectNameSingular}
|
||||
recordBoardId={recordIndexId}
|
||||
/>
|
||||
<RecordIndexBoardDataLoaderEffect recordBoardId={recordIndexId} />
|
||||
</StyledContainerWithPadding>
|
||||
)}
|
||||
</StyledContainer>
|
||||
</>
|
||||
);
|
||||
|
||||
@ -14,7 +14,7 @@ import { useRecordBoardRecordGqlFields } from '@/object-record/record-index/hook
|
||||
|
||||
import { FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
|
||||
import { currentRecordSortsComponentState } from '@/object-record/record-sort/states/currentRecordSortsComponentState';
|
||||
import { useSetRecordValue } from '@/object-record/record-store/contexts/RecordFieldValueSelectorContext';
|
||||
|
||||
import { useUpsertRecordsInStore } from '@/object-record/record-store/hooks/useUpsertRecordsInStore';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
@ -32,7 +32,6 @@ export const useLoadRecordIndexBoardColumn = ({
|
||||
recordBoardId,
|
||||
columnId,
|
||||
}: UseLoadRecordIndexBoardProps) => {
|
||||
const setRecordValueInContextSelector = useSetRecordValue();
|
||||
const { objectMetadataItem } = useObjectMetadataItem({
|
||||
objectNameSingular,
|
||||
});
|
||||
@ -102,10 +101,7 @@ export const useLoadRecordIndexBoardColumn = ({
|
||||
|
||||
useEffect(() => {
|
||||
upsertRecordsInStore(records);
|
||||
for (const record of records) {
|
||||
setRecordValueInContextSelector(record.id, record);
|
||||
}
|
||||
}, [records, upsertRecordsInStore, setRecordValueInContextSelector]);
|
||||
}, [records, upsertRecordsInStore]);
|
||||
|
||||
return {
|
||||
records,
|
||||
|
||||
@ -2,7 +2,6 @@ import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadata
|
||||
import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems';
|
||||
import { useFindOneRecord } from '@/object-record/hooks/useFindOneRecord';
|
||||
import { buildFindOneRecordForShowPageOperationSignature } from '@/object-record/record-show/graphql/operations/factories/findOneRecordForShowPageOperationSignatureFactory';
|
||||
import { useSetRecordValue } from '@/object-record/record-store/contexts/RecordFieldValueSelectorContext';
|
||||
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
|
||||
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
|
||||
import { useEffect } from 'react';
|
||||
@ -19,7 +18,6 @@ export const RecordShowEffect = ({
|
||||
}: RecordShowEffectProps) => {
|
||||
const { objectMetadataItem } = useObjectMetadataItem({ objectNameSingular });
|
||||
const { objectMetadataItems } = useObjectMetadataItems();
|
||||
const setRecordValueInContextSelector = useSetRecordValue();
|
||||
|
||||
const FIND_ONE_RECORD_FOR_SHOW_PAGE_OPERATION_SIGNATURE =
|
||||
buildFindOneRecordForShowPageOperationSignature({
|
||||
@ -44,10 +42,8 @@ export const RecordShowEffect = ({
|
||||
if (JSON.stringify(previousRecordValue) !== JSON.stringify(newRecord)) {
|
||||
set(recordStoreFamilyState(recordId), newRecord);
|
||||
}
|
||||
|
||||
setRecordValueInContextSelector(recordId, newRecord);
|
||||
},
|
||||
[recordId, setRecordValueInContextSelector],
|
||||
[recordId],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
@ -3,7 +3,7 @@ import { useContext, useEffect } from 'react';
|
||||
import { useFindOneRecord } from '@/object-record/hooks/useFindOneRecord';
|
||||
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
|
||||
import { FieldRelationMetadata } from '@/object-record/record-field/types/FieldMetadata';
|
||||
import { useSetRecordValue } from '@/object-record/record-store/contexts/RecordFieldValueSelectorContext';
|
||||
|
||||
import { useUpsertRecordsInStore } from '@/object-record/record-store/hooks/useUpsertRecordsInStore';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
@ -14,8 +14,6 @@ type RecordDetailRelationRecordsListItemEffectProps = {
|
||||
export const RecordDetailRelationRecordsListItemEffect = ({
|
||||
relationRecordId,
|
||||
}: RecordDetailRelationRecordsListItemEffectProps) => {
|
||||
const setRecordValueInContextSelector = useSetRecordValue();
|
||||
|
||||
const { fieldDefinition } = useContext(FieldContext);
|
||||
|
||||
const { relationObjectMetadataNameSingular } =
|
||||
@ -31,9 +29,8 @@ export const RecordDetailRelationRecordsListItemEffect = ({
|
||||
useEffect(() => {
|
||||
if (isDefined(record)) {
|
||||
upsertRecords([record]);
|
||||
setRecordValueInContextSelector(record.id, record);
|
||||
}
|
||||
}, [record, upsertRecords, setRecordValueInContextSelector]);
|
||||
}, [record, upsertRecords]);
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
@ -1,78 +1,16 @@
|
||||
import { Dispatch, SetStateAction, useState } from 'react';
|
||||
import { createContext, useContextSelector } from 'use-context-selector';
|
||||
|
||||
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
|
||||
|
||||
export type RecordFieldValue = {
|
||||
[recordId: string]: {
|
||||
[fieldName: string]: any;
|
||||
};
|
||||
};
|
||||
|
||||
export const RecordFieldValueSelectorContext = createContext<
|
||||
[RecordFieldValue, Dispatch<SetStateAction<RecordFieldValue>>]
|
||||
>([{}, () => {}]);
|
||||
|
||||
export const useSetRecordValue = () => {
|
||||
const setTableValue = useContextSelector(
|
||||
RecordFieldValueSelectorContext,
|
||||
(value) => value[1],
|
||||
);
|
||||
|
||||
return (recordId: string, newRecord: any) => {
|
||||
setTableValue((currentTable) => ({
|
||||
...currentTable,
|
||||
[recordId]: newRecord,
|
||||
}));
|
||||
};
|
||||
};
|
||||
|
||||
export const useRecordValue = (recordId: string) => {
|
||||
const tableValue = useContextSelector(
|
||||
RecordFieldValueSelectorContext,
|
||||
(value) => value[0]?.[recordId],
|
||||
);
|
||||
|
||||
return tableValue as ObjectRecord | undefined;
|
||||
};
|
||||
import { recordStoreFamilySelector } from '@/object-record/record-store/states/selectors/recordStoreFamilySelector';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
|
||||
export const useRecordFieldValue = <T,>(
|
||||
recordId: string,
|
||||
fieldName: string,
|
||||
) => {
|
||||
const recordFieldValue = useContextSelector(
|
||||
RecordFieldValueSelectorContext,
|
||||
(value) => value[0]?.[recordId]?.[fieldName],
|
||||
const recordFieldValue = useRecoilValue(
|
||||
recordStoreFamilySelector({
|
||||
recordId,
|
||||
fieldName,
|
||||
}),
|
||||
);
|
||||
|
||||
return recordFieldValue as T | undefined;
|
||||
};
|
||||
|
||||
export const useSetRecordFieldValue = () => {
|
||||
const setTableValue = useContextSelector(
|
||||
RecordFieldValueSelectorContext,
|
||||
(value) => value[1],
|
||||
);
|
||||
|
||||
return (recordId: string, fieldName: string, newValue: any) => {
|
||||
setTableValue((currentTable) => ({
|
||||
...currentTable,
|
||||
[recordId]: {
|
||||
...currentTable[recordId],
|
||||
[fieldName]: newValue,
|
||||
},
|
||||
}));
|
||||
};
|
||||
};
|
||||
|
||||
export const RecordFieldValueSelectorContextProvider = ({
|
||||
children,
|
||||
}: {
|
||||
children: any;
|
||||
}) => (
|
||||
<RecordFieldValueSelectorContext.Provider
|
||||
value={useState<RecordFieldValue>({})}
|
||||
>
|
||||
{children}
|
||||
</RecordFieldValueSelectorContext.Provider>
|
||||
);
|
||||
|
||||
@ -6,10 +6,6 @@ import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadat
|
||||
import { getBasePathToShowPage } from '@/object-metadata/utils/getBasePathToShowPage';
|
||||
|
||||
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
|
||||
import {
|
||||
RecordFieldValueSelectorContextProvider,
|
||||
useSetRecordValue,
|
||||
} from '@/object-record/record-store/contexts/RecordFieldValueSelectorContext';
|
||||
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
|
||||
import { RecordTableComponentInstance } from '@/object-record/record-table/components/RecordTableComponentInstance';
|
||||
import { RecordTableCellContext } from '@/object-record/record-table/contexts/RecordTableCellContext';
|
||||
@ -36,22 +32,14 @@ const RelationFieldValueSetterEffect = () => {
|
||||
recordStoreFamilyState(mockPerformance.relationRecordId),
|
||||
);
|
||||
|
||||
const setRecordValue = useSetRecordValue();
|
||||
|
||||
const [, setObjectMetadataItems] = useRecoilState(objectMetadataItemsState);
|
||||
|
||||
useEffect(() => {
|
||||
setEntity(mockPerformance.entityValue);
|
||||
setRelationEntity(mockPerformance.relationFieldValue);
|
||||
|
||||
setRecordValue(mockPerformance.entityValue.id, mockPerformance.entityValue);
|
||||
setRecordValue(
|
||||
mockPerformance.relationFieldValue.id,
|
||||
mockPerformance.relationFieldValue,
|
||||
);
|
||||
|
||||
setObjectMetadataItems(generatedMockObjectMetadataItems);
|
||||
}, [setEntity, setRelationEntity, setRecordValue, setObjectMetadataItems]);
|
||||
}, [setEntity, setRelationEntity, setObjectMetadataItems]);
|
||||
|
||||
return null;
|
||||
};
|
||||
@ -63,95 +51,93 @@ const meta: Meta = {
|
||||
ChipGeneratorsDecorator,
|
||||
(Story) => {
|
||||
return (
|
||||
<RecordFieldValueSelectorContextProvider>
|
||||
<RecordIndexContextProvider
|
||||
<RecordIndexContextProvider
|
||||
value={{
|
||||
indexIdentifierUrl: (_recordId: string) => '',
|
||||
onIndexRecordsLoaded: () => {},
|
||||
objectNamePlural: 'companies',
|
||||
objectNameSingular: 'company',
|
||||
objectMetadataItem: mockPerformance.objectMetadataItem as any,
|
||||
recordIndexId: 'recordIndexId',
|
||||
}}
|
||||
>
|
||||
<RecordTableContextProvider
|
||||
value={{
|
||||
indexIdentifierUrl: (_recordId: string) => '',
|
||||
onIndexRecordsLoaded: () => {},
|
||||
objectNamePlural: 'companies',
|
||||
objectNameSingular: 'company',
|
||||
recordTableId: 'recordTableId',
|
||||
viewBarId: mockPerformance.recordId,
|
||||
objectMetadataItem: mockPerformance.objectMetadataItem as any,
|
||||
recordIndexId: 'recordIndexId',
|
||||
visibleTableColumns: mockPerformance.visibleTableColumns as any,
|
||||
objectNameSingular:
|
||||
mockPerformance.objectMetadataItem.nameSingular,
|
||||
}}
|
||||
>
|
||||
<RecordTableContextProvider
|
||||
value={{
|
||||
recordTableId: 'recordTableId',
|
||||
viewBarId: mockPerformance.recordId,
|
||||
objectMetadataItem: mockPerformance.objectMetadataItem as any,
|
||||
visibleTableColumns: mockPerformance.visibleTableColumns as any,
|
||||
objectNameSingular:
|
||||
mockPerformance.objectMetadataItem.nameSingular,
|
||||
}}
|
||||
<RecordTableComponentInstance
|
||||
recordTableId="asd"
|
||||
onColumnsChange={() => {}}
|
||||
>
|
||||
<RecordTableComponentInstance
|
||||
recordTableId="asd"
|
||||
onColumnsChange={() => {}}
|
||||
<RecordTableBodyContextProvider
|
||||
value={{
|
||||
onOpenTableCell: () => {},
|
||||
onMoveFocus: () => {},
|
||||
onCloseTableCell: () => {},
|
||||
onMoveHoverToCurrentCell: () => {},
|
||||
onActionMenuDropdownOpened: () => {},
|
||||
onCellMouseEnter: () => {},
|
||||
}}
|
||||
>
|
||||
<RecordTableBodyContextProvider
|
||||
<RecordTableRowContextProvider
|
||||
value={{
|
||||
onOpenTableCell: () => {},
|
||||
onMoveFocus: () => {},
|
||||
onCloseTableCell: () => {},
|
||||
onMoveHoverToCurrentCell: () => {},
|
||||
onActionMenuDropdownOpened: () => {},
|
||||
onCellMouseEnter: () => {},
|
||||
objectNameSingular:
|
||||
mockPerformance.entityValue.__typename.toLocaleLowerCase(),
|
||||
recordId: mockPerformance.recordId,
|
||||
rowIndex: 0,
|
||||
pathToShowPage:
|
||||
getBasePathToShowPage({
|
||||
objectNameSingular:
|
||||
mockPerformance.entityValue.__typename.toLocaleLowerCase(),
|
||||
}) + mockPerformance.recordId,
|
||||
isSelected: false,
|
||||
inView: true,
|
||||
}}
|
||||
>
|
||||
<RecordTableRowContextProvider
|
||||
<RecordTableRowDraggableContextProvider
|
||||
value={{
|
||||
objectNameSingular:
|
||||
mockPerformance.entityValue.__typename.toLocaleLowerCase(),
|
||||
recordId: mockPerformance.recordId,
|
||||
rowIndex: 0,
|
||||
pathToShowPage:
|
||||
getBasePathToShowPage({
|
||||
objectNameSingular:
|
||||
mockPerformance.entityValue.__typename.toLocaleLowerCase(),
|
||||
}) + mockPerformance.recordId,
|
||||
isSelected: false,
|
||||
inView: true,
|
||||
isDragging: false,
|
||||
dragHandleProps: null,
|
||||
}}
|
||||
>
|
||||
<RecordTableRowDraggableContextProvider
|
||||
<RecordTableCellContext.Provider
|
||||
value={{
|
||||
isDragging: false,
|
||||
dragHandleProps: null,
|
||||
columnDefinition: mockPerformance.fieldDefinition,
|
||||
cellPosition: { row: 0, column: 0 },
|
||||
}}
|
||||
>
|
||||
<RecordTableCellContext.Provider
|
||||
<FieldContext.Provider
|
||||
value={{
|
||||
columnDefinition: mockPerformance.fieldDefinition,
|
||||
cellPosition: { row: 0, column: 0 },
|
||||
recordId: mockPerformance.recordId,
|
||||
isLabelIdentifier: false,
|
||||
fieldDefinition: {
|
||||
...mockPerformance.fieldDefinition,
|
||||
},
|
||||
isReadOnly: false,
|
||||
}}
|
||||
>
|
||||
<FieldContext.Provider
|
||||
value={{
|
||||
recordId: mockPerformance.recordId,
|
||||
isLabelIdentifier: false,
|
||||
fieldDefinition: {
|
||||
...mockPerformance.fieldDefinition,
|
||||
},
|
||||
isReadOnly: false,
|
||||
}}
|
||||
>
|
||||
<RelationFieldValueSetterEffect />
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<Story />
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</FieldContext.Provider>
|
||||
</RecordTableCellContext.Provider>
|
||||
</RecordTableRowDraggableContextProvider>
|
||||
</RecordTableRowContextProvider>
|
||||
</RecordTableBodyContextProvider>
|
||||
</RecordTableComponentInstance>
|
||||
</RecordTableContextProvider>
|
||||
</RecordIndexContextProvider>
|
||||
</RecordFieldValueSelectorContextProvider>
|
||||
<RelationFieldValueSetterEffect />
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<Story />
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</FieldContext.Provider>
|
||||
</RecordTableCellContext.Provider>
|
||||
</RecordTableRowDraggableContextProvider>
|
||||
</RecordTableRowContextProvider>
|
||||
</RecordTableBodyContextProvider>
|
||||
</RecordTableComponentInstance>
|
||||
</RecordTableContextProvider>
|
||||
</RecordIndexContextProvider>
|
||||
);
|
||||
},
|
||||
ComponentDecorator,
|
||||
|
||||
@ -2,7 +2,7 @@ import { useRecoilCallback } from 'recoil';
|
||||
|
||||
import { recordIndexRecordIdsByGroupComponentFamilyState } from '@/object-record/record-index/states/recordIndexRecordIdsByGroupComponentFamilyState';
|
||||
import { recordIndexAllRecordIdsComponentSelector } from '@/object-record/record-index/states/selectors/recordIndexAllRecordIdsComponentSelector';
|
||||
import { useSetRecordValue } from '@/object-record/record-store/contexts/RecordFieldValueSelectorContext';
|
||||
|
||||
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
|
||||
import { useSetIsRecordTableFocusActive } from '@/object-record/record-table/record-table-cell/hooks/useSetIsRecordTableFocusActive';
|
||||
import { hasUserSelectedAllRowsComponentState } from '@/object-record/record-table/record-table-row/states/hasUserSelectedAllRowsFamilyState';
|
||||
@ -27,8 +27,6 @@ export const useSetRecordTableData = ({
|
||||
recordTableId,
|
||||
onEntityCountChange,
|
||||
}: useSetRecordTableDataProps) => {
|
||||
const setRecordValueInContextSelector = useSetRecordValue();
|
||||
|
||||
const recordIndexRecordIdsByGroupFamilyState =
|
||||
useRecoilComponentCallbackStateV2(
|
||||
recordIndexRecordIdsByGroupComponentFamilyState,
|
||||
@ -82,7 +80,6 @@ export const useSetRecordTableData = ({
|
||||
};
|
||||
|
||||
set(recordStoreFamilyState(record.id), newRecord);
|
||||
setRecordValueInContextSelector(record.id, newRecord);
|
||||
}
|
||||
}
|
||||
|
||||
@ -130,7 +127,6 @@ export const useSetRecordTableData = ({
|
||||
setRecordTableHoverPosition,
|
||||
onEntityCountChange,
|
||||
isRowSelectedFamilyState,
|
||||
setRecordValueInContextSelector,
|
||||
],
|
||||
);
|
||||
};
|
||||
|
||||
@ -1,12 +1,13 @@
|
||||
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
|
||||
import { INLINE_CELL_HOTKEY_SCOPE_MEMOIZE_KEY } from '@/object-record/record-inline-cell/constants/InlineCellHotkeyScopeMemoizeKey';
|
||||
import { useInlineCell } from '@/object-record/record-inline-cell/hooks/useInlineCell';
|
||||
import { useRecordValue } from '@/object-record/record-store/contexts/RecordFieldValueSelectorContext';
|
||||
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
|
||||
import { TitleInputHotkeyScope } from '@/ui/input/types/TitleInputHotkeyScope';
|
||||
import { usePreviousHotkeyScope } from '@/ui/utilities/hotkey/hooks/usePreviousHotkeyScope';
|
||||
import { Theme, withTheme } from '@emotion/react';
|
||||
import styled from '@emotion/styled';
|
||||
import { useContext } from 'react';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import { OverflowingTextWithTooltip } from 'twenty-ui/display';
|
||||
|
||||
const StyledDiv = styled.div`
|
||||
@ -33,7 +34,9 @@ const StyledEmptyText = withTheme(styled.div<{ theme: Theme }>`
|
||||
|
||||
export const RecordTitleCellSingleTextDisplayMode = () => {
|
||||
const { recordId, fieldDefinition } = useContext(FieldContext);
|
||||
const recordValue = useRecordValue(recordId);
|
||||
|
||||
const recordValue = useRecoilValue(recordStoreFamilyState(recordId));
|
||||
|
||||
const isEmpty =
|
||||
recordValue?.[fieldDefinition.metadata.fieldName]?.trim() === '';
|
||||
|
||||
|
||||
@ -112,10 +112,7 @@ export const SettingsDataModelFieldPreview = ({
|
||||
}}
|
||||
>
|
||||
{isDefined(previewRecord) ? (
|
||||
<SettingsDataModelSetPreviewRecordEffect
|
||||
fieldName={fieldName}
|
||||
record={previewRecord}
|
||||
/>
|
||||
<SettingsDataModelSetPreviewRecordEffect record={previewRecord} />
|
||||
) : (
|
||||
<SettingsDataModelSetFieldValueEffect
|
||||
recordId={recordId}
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
import { useSetRecordFieldValue } from '@/object-record/record-store/contexts/RecordFieldValueSelectorContext';
|
||||
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
|
||||
import { recordStoreFamilySelector } from '@/object-record/record-store/states/selectors/recordStoreFamilySelector';
|
||||
import { settingsPreviewRecordIdState } from '@/settings/data-model/fields/preview/states/settingsPreviewRecordIdState';
|
||||
@ -29,7 +28,6 @@ export const SettingsDataModelSetFieldValueEffect = ({
|
||||
fieldName,
|
||||
}),
|
||||
);
|
||||
const setRecordFieldValue = useSetRecordFieldValue();
|
||||
|
||||
useEffect(() => {
|
||||
if (
|
||||
@ -37,23 +35,10 @@ export const SettingsDataModelSetFieldValueEffect = ({
|
||||
!!upsertedPreviewRecord[fieldName]
|
||||
) {
|
||||
setFieldValue(upsertedPreviewRecord[fieldName]);
|
||||
setRecordFieldValue(
|
||||
recordId,
|
||||
fieldName,
|
||||
upsertedPreviewRecord[fieldName],
|
||||
);
|
||||
} else {
|
||||
setFieldValue(value);
|
||||
setRecordFieldValue(recordId, fieldName, value);
|
||||
}
|
||||
}, [
|
||||
value,
|
||||
setFieldValue,
|
||||
setRecordFieldValue,
|
||||
recordId,
|
||||
fieldName,
|
||||
upsertedPreviewRecord,
|
||||
]);
|
||||
}, [value, setFieldValue, recordId, fieldName, upsertedPreviewRecord]);
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
import { useSetRecordFieldValue } from '@/object-record/record-store/contexts/RecordFieldValueSelectorContext';
|
||||
import { useUpsertRecordsInStore } from '@/object-record/record-store/hooks/useUpsertRecordsInStore';
|
||||
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
|
||||
import { settingsPreviewRecordIdState } from '@/settings/data-model/fields/preview/states/settingsPreviewRecordIdState';
|
||||
@ -7,15 +6,12 @@ import { useSetRecoilState } from 'recoil';
|
||||
|
||||
type SettingsDataModelSetPreviewRecordEffectProps = {
|
||||
record: ObjectRecord;
|
||||
fieldName: string;
|
||||
};
|
||||
|
||||
export const SettingsDataModelSetPreviewRecordEffect = ({
|
||||
record,
|
||||
fieldName,
|
||||
}: SettingsDataModelSetPreviewRecordEffectProps) => {
|
||||
const { upsertRecords: upsertRecordsInStore } = useUpsertRecordsInStore();
|
||||
const setRecordFieldValue = useSetRecordFieldValue();
|
||||
|
||||
const setSettingsPreviewRecordId = useSetRecoilState(
|
||||
settingsPreviewRecordIdState,
|
||||
@ -23,15 +19,8 @@ export const SettingsDataModelSetPreviewRecordEffect = ({
|
||||
|
||||
useEffect(() => {
|
||||
upsertRecordsInStore([record]);
|
||||
setRecordFieldValue(record.id, fieldName, record[fieldName]);
|
||||
setSettingsPreviewRecordId(record.id);
|
||||
}, [
|
||||
record,
|
||||
upsertRecordsInStore,
|
||||
setRecordFieldValue,
|
||||
fieldName,
|
||||
setSettingsPreviewRecordId,
|
||||
]);
|
||||
}, [record, upsertRecordsInStore, setSettingsPreviewRecordId]);
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
@ -1,16 +1,15 @@
|
||||
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||
|
||||
import { useUpdateOneObjectMetadataItem } from '@/object-metadata/hooks/useUpdateOneObjectMetadataItem';
|
||||
import { RecordFieldValueSelectorContextProvider } from '@/object-record/record-store/contexts/RecordFieldValueSelectorContext';
|
||||
import { SettingsUpdateDataModelObjectAboutForm } from '@/settings/data-model/object-details/components/SettingsUpdateDataModelObjectAboutForm';
|
||||
import { SettingsDataModelObjectSettingsFormCard } from '@/settings/data-model/objects/forms/components/SettingsDataModelObjectSettingsFormCard';
|
||||
import { SettingsPath } from '@/types/SettingsPath';
|
||||
import styled from '@emotion/styled';
|
||||
import { useLingui } from '@lingui/react/macro';
|
||||
import { useNavigateSettings } from '~/hooks/useNavigateSettings';
|
||||
import { Button } from 'twenty-ui/input';
|
||||
import { H2Title, IconArchive } from 'twenty-ui/display';
|
||||
import { Button } from 'twenty-ui/input';
|
||||
import { Section } from 'twenty-ui/layout';
|
||||
import { useNavigateSettings } from '~/hooks/useNavigateSettings';
|
||||
|
||||
type ObjectSettingsProps = {
|
||||
objectMetadataItem: ObjectMetadataItem;
|
||||
@ -39,43 +38,38 @@ export const ObjectSettings = ({ objectMetadataItem }: ObjectSettingsProps) => {
|
||||
};
|
||||
|
||||
return (
|
||||
<RecordFieldValueSelectorContextProvider>
|
||||
<StyledContentContainer>
|
||||
<StyledFormSection>
|
||||
<StyledContentContainer>
|
||||
<StyledFormSection>
|
||||
<H2Title
|
||||
title={t`About`}
|
||||
description={t`Name in both singular (e.g., 'Invoice') and plural (e.g., 'Invoices') forms.`}
|
||||
/>
|
||||
<SettingsUpdateDataModelObjectAboutForm
|
||||
objectMetadataItem={objectMetadataItem}
|
||||
/>
|
||||
</StyledFormSection>
|
||||
<StyledFormSection>
|
||||
<Section>
|
||||
<H2Title
|
||||
title={t`About`}
|
||||
description={t`Name in both singular (e.g., 'Invoice') and plural (e.g., 'Invoices') forms.`}
|
||||
title={t`Options`}
|
||||
description={t`Choose the fields that will identify your records`}
|
||||
/>
|
||||
<SettingsUpdateDataModelObjectAboutForm
|
||||
<SettingsDataModelObjectSettingsFormCard
|
||||
objectMetadataItem={objectMetadataItem}
|
||||
/>
|
||||
</StyledFormSection>
|
||||
<StyledFormSection>
|
||||
<Section>
|
||||
<H2Title
|
||||
title={t`Options`}
|
||||
description={t`Choose the fields that will identify your records`}
|
||||
/>
|
||||
<SettingsDataModelObjectSettingsFormCard
|
||||
objectMetadataItem={objectMetadataItem}
|
||||
/>
|
||||
</Section>
|
||||
</StyledFormSection>
|
||||
<StyledFormSection>
|
||||
<Section>
|
||||
<H2Title
|
||||
title={t`Danger zone`}
|
||||
description={t`Deactivate object`}
|
||||
/>
|
||||
<Button
|
||||
Icon={IconArchive}
|
||||
title={t`Deactivate`}
|
||||
size="small"
|
||||
onClick={handleDisable}
|
||||
/>
|
||||
</Section>
|
||||
</StyledFormSection>
|
||||
</StyledContentContainer>
|
||||
</RecordFieldValueSelectorContextProvider>
|
||||
</Section>
|
||||
</StyledFormSection>
|
||||
<StyledFormSection>
|
||||
<Section>
|
||||
<H2Title title={t`Danger zone`} description={t`Deactivate object`} />
|
||||
<Button
|
||||
Icon={IconArchive}
|
||||
title={t`Deactivate`}
|
||||
size="small"
|
||||
onClick={handleDisable}
|
||||
/>
|
||||
</Section>
|
||||
</StyledFormSection>
|
||||
</StyledContentContainer>
|
||||
);
|
||||
};
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
import { RecordFieldValueSelectorContextProvider } from '@/object-record/record-store/contexts/RecordFieldValueSelectorContext';
|
||||
import { SignInBackgroundMockContainer } from '@/sign-in-background-mock/components/SignInBackgroundMockContainer';
|
||||
import { PageBody } from '@/ui/layout/page/components/PageBody';
|
||||
import { PageContainer } from '@/ui/layout/page/components/PageContainer';
|
||||
@ -18,11 +17,9 @@ export const SignInBackgroundMockPage = () => {
|
||||
<PageContainer>
|
||||
<PageHeader title="Companies" Icon={IconBuildingSkyscraper} />
|
||||
<PageBody>
|
||||
<RecordFieldValueSelectorContextProvider>
|
||||
<StyledTableContainer>
|
||||
<SignInBackgroundMockContainer />
|
||||
</StyledTableContainer>
|
||||
</RecordFieldValueSelectorContextProvider>
|
||||
<StyledTableContainer>
|
||||
<SignInBackgroundMockContainer />
|
||||
</StyledTableContainer>
|
||||
</PageBody>
|
||||
</PageContainer>
|
||||
);
|
||||
|
||||
@ -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>
|
||||
);
|
||||
};
|
||||
|
||||
@ -10,7 +10,6 @@ import { RecordFiltersComponentInstanceContext } from '@/object-record/record-fi
|
||||
import { RecordIndexContextProvider } from '@/object-record/record-index/contexts/RecordIndexContext';
|
||||
import { useLoadRecordIndexStates } from '@/object-record/record-index/hooks/useLoadRecordIndexStates';
|
||||
import { RecordSortsComponentInstanceContext } from '@/object-record/record-sort/states/context/RecordSortsComponentInstanceContext';
|
||||
import { RecordFieldValueSelectorContextProvider } from '@/object-record/record-store/contexts/RecordFieldValueSelectorContext';
|
||||
import { RecordTableBodyContextProvider } from '@/object-record/record-table/contexts/RecordTableBodyContext';
|
||||
import { RecordTableContextProvider } from '@/object-record/record-table/contexts/RecordTableContext';
|
||||
import { useRecordTable } from '@/object-record/record-table/hooks/useRecordTable';
|
||||
@ -126,41 +125,39 @@ export const RecordTableDecorator: Decorator = (Story, context) => {
|
||||
);
|
||||
|
||||
return (
|
||||
<RecordFieldValueSelectorContextProvider>
|
||||
<RecordTableComponentInstanceContext.Provider
|
||||
value={{ instanceId: recordIndexId, onColumnsChange: () => {} }}
|
||||
<RecordTableComponentInstanceContext.Provider
|
||||
value={{ instanceId: recordIndexId, onColumnsChange: () => {} }}
|
||||
>
|
||||
<ViewComponentInstanceContext.Provider
|
||||
value={{ instanceId: recordIndexId }}
|
||||
>
|
||||
<ViewComponentInstanceContext.Provider
|
||||
<RecordFilterGroupsComponentInstanceContext.Provider
|
||||
value={{ instanceId: recordIndexId }}
|
||||
>
|
||||
<RecordFilterGroupsComponentInstanceContext.Provider
|
||||
<RecordFiltersComponentInstanceContext.Provider
|
||||
value={{ instanceId: recordIndexId }}
|
||||
>
|
||||
<RecordFiltersComponentInstanceContext.Provider
|
||||
<RecordSortsComponentInstanceContext.Provider
|
||||
value={{ instanceId: recordIndexId }}
|
||||
>
|
||||
<RecordSortsComponentInstanceContext.Provider
|
||||
value={{ instanceId: recordIndexId }}
|
||||
<ActionMenuComponentInstanceContext.Provider
|
||||
value={{
|
||||
instanceId: getActionMenuIdFromRecordIndexId(recordIndexId),
|
||||
}}
|
||||
>
|
||||
<ActionMenuComponentInstanceContext.Provider
|
||||
value={{
|
||||
instanceId: getActionMenuIdFromRecordIndexId(recordIndexId),
|
||||
}}
|
||||
<InternalTableStateLoaderEffect
|
||||
objectMetadataItem={objectMetadataItem}
|
||||
/>
|
||||
<InternalTableContextProviders
|
||||
objectMetadataItem={objectMetadataItem}
|
||||
>
|
||||
<InternalTableStateLoaderEffect
|
||||
objectMetadataItem={objectMetadataItem}
|
||||
/>
|
||||
<InternalTableContextProviders
|
||||
objectMetadataItem={objectMetadataItem}
|
||||
>
|
||||
<Story />
|
||||
</InternalTableContextProviders>
|
||||
</ActionMenuComponentInstanceContext.Provider>
|
||||
</RecordSortsComponentInstanceContext.Provider>
|
||||
</RecordFiltersComponentInstanceContext.Provider>
|
||||
</RecordFilterGroupsComponentInstanceContext.Provider>
|
||||
</ViewComponentInstanceContext.Provider>
|
||||
</RecordTableComponentInstanceContext.Provider>
|
||||
</RecordFieldValueSelectorContextProvider>
|
||||
<Story />
|
||||
</InternalTableContextProviders>
|
||||
</ActionMenuComponentInstanceContext.Provider>
|
||||
</RecordSortsComponentInstanceContext.Provider>
|
||||
</RecordFiltersComponentInstanceContext.Provider>
|
||||
</RecordFilterGroupsComponentInstanceContext.Provider>
|
||||
</ViewComponentInstanceContext.Provider>
|
||||
</RecordTableComponentInstanceContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
@ -6,10 +6,6 @@ import { formatFieldMetadataItemAsColumnDefinition } from '@/object-metadata/uti
|
||||
import { isLabelIdentifierField } from '@/object-metadata/utils/isLabelIdentifierField';
|
||||
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
|
||||
import { RecordFieldComponentInstanceContext } from '@/object-record/record-field/states/contexts/RecordFieldComponentInstanceContext';
|
||||
import {
|
||||
RecordFieldValueSelectorContextProvider,
|
||||
useSetRecordValue,
|
||||
} from '@/object-record/record-store/contexts/RecordFieldValueSelectorContext';
|
||||
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
|
||||
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
@ -27,15 +23,12 @@ const RecordMockSetterEffect = ({
|
||||
people: ObjectRecord[];
|
||||
tasks: ObjectRecord[];
|
||||
}) => {
|
||||
const setRecordValue = useSetRecordValue();
|
||||
|
||||
const setRecordInStores = useRecoilCallback(
|
||||
({ set }) =>
|
||||
(record: ObjectRecord) => {
|
||||
set(recordStoreFamilyState(record.id), record);
|
||||
setRecordValue(record.id, record);
|
||||
},
|
||||
[setRecordValue],
|
||||
[],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
@ -130,27 +123,25 @@ export const getFieldDecorator =
|
||||
instanceId: 'record-field-component-instance-id',
|
||||
}}
|
||||
>
|
||||
<RecordFieldValueSelectorContextProvider>
|
||||
<FieldContext.Provider
|
||||
value={{
|
||||
recordId: record.id,
|
||||
isLabelIdentifier,
|
||||
fieldDefinition: formatFieldMetadataItemAsColumnDefinition({
|
||||
field: fieldMetadataItem,
|
||||
position: 0,
|
||||
objectMetadataItem,
|
||||
}),
|
||||
isReadOnly: false,
|
||||
}}
|
||||
>
|
||||
<RecordMockSetterEffect
|
||||
companies={companies}
|
||||
people={people}
|
||||
tasks={tasks}
|
||||
/>
|
||||
<Story />
|
||||
</FieldContext.Provider>
|
||||
</RecordFieldValueSelectorContextProvider>
|
||||
<FieldContext.Provider
|
||||
value={{
|
||||
recordId: record.id,
|
||||
isLabelIdentifier,
|
||||
fieldDefinition: formatFieldMetadataItemAsColumnDefinition({
|
||||
field: fieldMetadataItem,
|
||||
position: 0,
|
||||
objectMetadataItem,
|
||||
}),
|
||||
isReadOnly: false,
|
||||
}}
|
||||
>
|
||||
<RecordMockSetterEffect
|
||||
companies={companies}
|
||||
people={people}
|
||||
tasks={tasks}
|
||||
/>
|
||||
<Story />
|
||||
</FieldContext.Provider>
|
||||
</RecordFieldComponentInstanceContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
11
yarn.lock
11
yarn.lock
@ -55579,7 +55579,6 @@ __metadata:
|
||||
tsx: "npm:^4.17.0"
|
||||
type-fest: "npm:4.10.1"
|
||||
typescript: "npm:5.3.3"
|
||||
use-context-selector: "npm:^2.0.0"
|
||||
use-debounce: "npm:^10.0.0"
|
||||
uuid: "npm:^9.0.0"
|
||||
vite: "npm:^5.4.0"
|
||||
@ -56763,16 +56762,6 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"use-context-selector@npm:^2.0.0":
|
||||
version: 2.0.0
|
||||
resolution: "use-context-selector@npm:2.0.0"
|
||||
peerDependencies:
|
||||
react: ">=18.0.0"
|
||||
scheduler: ">=0.19.0"
|
||||
checksum: 10c0/4eb6054ab8996ae8b3f87f9d102e576066e5a8b9db5db2c891128ae920bd64bcdcb4e93a13bc99658ef16280929a8331fc8ac45177f4acd716c425b1bc31135a
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"use-debounce@npm:^10.0.0":
|
||||
version: 10.0.2
|
||||
resolution: "use-debounce@npm:10.0.2"
|
||||
|
||||
Reference in New Issue
Block a user