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",
|
"tsup": "^8.2.4",
|
||||||
"type-fest": "4.10.1",
|
"type-fest": "4.10.1",
|
||||||
"typescript": "5.3.3",
|
"typescript": "5.3.3",
|
||||||
"use-context-selector": "^2.0.0",
|
|
||||||
"use-debounce": "^10.0.0",
|
"use-debounce": "^10.0.0",
|
||||||
"uuid": "^9.0.0",
|
"uuid": "^9.0.0",
|
||||||
"vite-tsconfig-paths": "^4.2.1",
|
"vite-tsconfig-paths": "^4.2.1",
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
import { CalendarEvent } from '@/activities/calendar/types/CalendarEvent';
|
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 { useUpsertRecordsInStore } from '@/object-record/record-store/hooks/useUpsertRecordsInStore';
|
||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
|
|
||||||
@ -11,7 +10,6 @@ export const CalendarEventDetailsEffect = ({
|
|||||||
record,
|
record,
|
||||||
}: CalendarEventDetailsEffectProps) => {
|
}: CalendarEventDetailsEffectProps) => {
|
||||||
const { upsertRecords } = useUpsertRecordsInStore();
|
const { upsertRecords } = useUpsertRecordsInStore();
|
||||||
const setRecordValueInContextSelector = useSetRecordValue();
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!record) {
|
if (!record) {
|
||||||
@ -19,8 +17,7 @@ export const CalendarEventDetailsEffect = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
upsertRecords([record]);
|
upsertRecords([record]);
|
||||||
setRecordValueInContextSelector(record.id, record);
|
}, [record, upsertRecords]);
|
||||||
}, [record, upsertRecords, setRecordValueInContextSelector]);
|
|
||||||
|
|
||||||
return <></>;
|
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 { EventFieldDiffValueEffect } from '@/activities/timeline-activities/rows/main-object/components/EventFieldDiffValueEffect';
|
||||||
import { FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
|
import { FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
|
||||||
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||||
import { RecordFieldValueSelectorContextProvider } from '@/object-record/record-store/contexts/RecordFieldValueSelectorContext';
|
|
||||||
import { Trans } from '@lingui/react/macro';
|
import { Trans } from '@lingui/react/macro';
|
||||||
|
|
||||||
type EventFieldDiffProps = {
|
type EventFieldDiffProps = {
|
||||||
@ -54,29 +53,27 @@ export const EventFieldDiff = ({
|
|||||||
isObjectEmpty(diffRecord));
|
isObjectEmpty(diffRecord));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<RecordFieldValueSelectorContextProvider>
|
<StyledEventFieldDiffContainer>
|
||||||
<StyledEventFieldDiffContainer>
|
<EventFieldDiffLabel fieldMetadataItem={fieldMetadataItem} />→
|
||||||
<EventFieldDiffLabel fieldMetadataItem={fieldMetadataItem} />→
|
{isUpdatedToEmpty ? (
|
||||||
{isUpdatedToEmpty ? (
|
<StyledEmptyValue>
|
||||||
<StyledEmptyValue>
|
<Trans>Empty</Trans>
|
||||||
<Trans>Empty</Trans>
|
</StyledEmptyValue>
|
||||||
</StyledEmptyValue>
|
) : (
|
||||||
) : (
|
<>
|
||||||
<>
|
<EventFieldDiffValueEffect
|
||||||
<EventFieldDiffValueEffect
|
diffArtificialRecordStoreId={diffArtificialRecordStoreId}
|
||||||
diffArtificialRecordStoreId={diffArtificialRecordStoreId}
|
mainObjectMetadataItem={mainObjectMetadataItem}
|
||||||
mainObjectMetadataItem={mainObjectMetadataItem}
|
fieldMetadataItem={fieldMetadataItem}
|
||||||
fieldMetadataItem={fieldMetadataItem}
|
diffRecord={diffRecord}
|
||||||
diffRecord={diffRecord}
|
/>
|
||||||
/>
|
<EventFieldDiffValue
|
||||||
<EventFieldDiffValue
|
diffArtificialRecordStoreId={diffArtificialRecordStoreId}
|
||||||
diffArtificialRecordStoreId={diffArtificialRecordStoreId}
|
mainObjectMetadataItem={mainObjectMetadataItem}
|
||||||
mainObjectMetadataItem={mainObjectMetadataItem}
|
fieldMetadataItem={fieldMetadataItem}
|
||||||
fieldMetadataItem={fieldMetadataItem}
|
/>
|
||||||
/>
|
</>
|
||||||
</>
|
)}
|
||||||
)}
|
</StyledEventFieldDiffContainer>
|
||||||
</StyledEventFieldDiffContainer>
|
|
||||||
</RecordFieldValueSelectorContextProvider>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -3,7 +3,6 @@ import { useSetRecoilState } from 'recoil';
|
|||||||
|
|
||||||
import { FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
|
import { FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
|
||||||
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
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 { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
|
||||||
import { isDefined } from 'twenty-shared/utils';
|
import { isDefined } from 'twenty-shared/utils';
|
||||||
|
|
||||||
@ -21,7 +20,6 @@ export const EventFieldDiffValueEffect = ({
|
|||||||
const setEntity = useSetRecoilState(
|
const setEntity = useSetRecoilState(
|
||||||
recordStoreFamilyState(diffArtificialRecordStoreId),
|
recordStoreFamilyState(diffArtificialRecordStoreId),
|
||||||
);
|
);
|
||||||
const setRecordValue = useSetRecordValue();
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!isDefined(diffRecord)) return;
|
if (!isDefined(diffRecord)) return;
|
||||||
@ -33,14 +31,12 @@ export const EventFieldDiffValueEffect = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
setEntity(forgedObjectRecord);
|
setEntity(forgedObjectRecord);
|
||||||
setRecordValue(forgedObjectRecord.id, forgedObjectRecord);
|
|
||||||
}, [
|
}, [
|
||||||
diffRecord,
|
diffRecord,
|
||||||
diffArtificialRecordStoreId,
|
diffArtificialRecordStoreId,
|
||||||
fieldMetadataItem.name,
|
fieldMetadataItem.name,
|
||||||
mainObjectMetadataItem.nameSingular,
|
mainObjectMetadataItem.nameSingular,
|
||||||
setEntity,
|
setEntity,
|
||||||
setRecordValue,
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return <></>;
|
return <></>;
|
||||||
|
|||||||
@ -4,10 +4,6 @@ import { FIND_ONE_CALENDAR_EVENT_OPERATION_SIGNATURE } from '@/activities/calend
|
|||||||
import { CalendarEvent } from '@/activities/calendar/types/CalendarEvent';
|
import { CalendarEvent } from '@/activities/calendar/types/CalendarEvent';
|
||||||
import { viewableRecordIdComponentState } from '@/command-menu/pages/record-page/states/viewableRecordIdComponentState';
|
import { viewableRecordIdComponentState } from '@/command-menu/pages/record-page/states/viewableRecordIdComponentState';
|
||||||
import { useFindOneRecord } from '@/object-record/hooks/useFindOneRecord';
|
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 { useUpsertRecordsInStore } from '@/object-record/record-store/hooks/useUpsertRecordsInStore';
|
||||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||||
|
|
||||||
@ -16,7 +12,6 @@ export const CommandMenuCalendarEventPage = () => {
|
|||||||
const viewableRecordId = useRecoilComponentValueV2(
|
const viewableRecordId = useRecoilComponentValueV2(
|
||||||
viewableRecordIdComponentState,
|
viewableRecordIdComponentState,
|
||||||
);
|
);
|
||||||
const setRecordValueInContextSelector = useSetRecordValue();
|
|
||||||
|
|
||||||
const { record: calendarEvent } = useFindOneRecord<CalendarEvent>({
|
const { record: calendarEvent } = useFindOneRecord<CalendarEvent>({
|
||||||
objectNameSingular:
|
objectNameSingular:
|
||||||
@ -26,7 +21,6 @@ export const CommandMenuCalendarEventPage = () => {
|
|||||||
// TODO: this is not executed on sub-sequent runs, make sure that it is intended
|
// TODO: this is not executed on sub-sequent runs, make sure that it is intended
|
||||||
onCompleted: (record) => {
|
onCompleted: (record) => {
|
||||||
upsertRecords([record]);
|
upsertRecords([record]);
|
||||||
setRecordValueInContextSelector(record.id, record);
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -35,9 +29,9 @@ export const CommandMenuCalendarEventPage = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<RecordFieldValueSelectorContextProvider>
|
<>
|
||||||
<CalendarEventDetailsEffect record={calendarEvent} />
|
<CalendarEventDetailsEffect record={calendarEvent} />
|
||||||
<CalendarEventDetails calendarEvent={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 { RecordShowEffect } from '@/object-record/record-show/components/RecordShowEffect';
|
||||||
import { useRecordShowPage } from '@/object-record/record-show/hooks/useRecordShowPage';
|
import { useRecordShowPage } from '@/object-record/record-show/hooks/useRecordShowPage';
|
||||||
import { RecordSortsComponentInstanceContext } from '@/object-record/record-sort/states/context/RecordSortsComponentInstanceContext';
|
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 { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';
|
||||||
import { useComponentInstanceStateContext } from '@/ui/utilities/state/component-state/hooks/useComponentInstanceStateContext';
|
import { useComponentInstanceStateContext } from '@/ui/utilities/state/component-state/hooks/useComponentInstanceStateContext';
|
||||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||||
@ -72,24 +71,22 @@ export const CommandMenuRecordPage = () => {
|
|||||||
value={{ instanceId: commandMenuPageInstanceId }}
|
value={{ instanceId: commandMenuPageInstanceId }}
|
||||||
>
|
>
|
||||||
<StyledRightDrawerRecord isMobile={isMobile}>
|
<StyledRightDrawerRecord isMobile={isMobile}>
|
||||||
<RecordFieldValueSelectorContextProvider>
|
<TimelineActivityContext.Provider
|
||||||
<TimelineActivityContext.Provider
|
value={{
|
||||||
value={{
|
recordId: objectRecordId,
|
||||||
recordId: objectRecordId,
|
}}
|
||||||
}}
|
>
|
||||||
>
|
<RecordShowEffect
|
||||||
<RecordShowEffect
|
objectNameSingular={objectNameSingular}
|
||||||
objectNameSingular={objectNameSingular}
|
recordId={objectRecordId}
|
||||||
recordId={objectRecordId}
|
/>
|
||||||
/>
|
<RecordShowContainer
|
||||||
<RecordShowContainer
|
objectNameSingular={objectNameSingular}
|
||||||
objectNameSingular={objectNameSingular}
|
objectRecordId={objectRecordId}
|
||||||
objectRecordId={objectRecordId}
|
loading={false}
|
||||||
loading={false}
|
isInRightDrawer={true}
|
||||||
isInRightDrawer={true}
|
/>
|
||||||
/>
|
</TimelineActivityContext.Provider>
|
||||||
</TimelineActivityContext.Provider>
|
|
||||||
</RecordFieldValueSelectorContextProvider>
|
|
||||||
</StyledRightDrawerRecord>
|
</StyledRightDrawerRecord>
|
||||||
</ActionMenuComponentInstanceContext.Provider>
|
</ActionMenuComponentInstanceContext.Provider>
|
||||||
</ContextStoreComponentInstanceContext.Provider>
|
</ContextStoreComponentInstanceContext.Provider>
|
||||||
|
|||||||
@ -2,7 +2,6 @@ import { useContext } from 'react';
|
|||||||
import { useRecoilCallback } from 'recoil';
|
import { useRecoilCallback } from 'recoil';
|
||||||
|
|
||||||
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
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 { recordStoreFamilySelector } from '@/object-record/record-store/states/selectors/recordStoreFamilySelector';
|
||||||
import { generateEmptyFieldValue } from '@/object-record/utils/generateEmptyFieldValue';
|
import { generateEmptyFieldValue } from '@/object-record/utils/generateEmptyFieldValue';
|
||||||
|
|
||||||
@ -17,8 +16,6 @@ export const useClearField = () => {
|
|||||||
|
|
||||||
const [updateRecord] = useUpdateRecord();
|
const [updateRecord] = useUpdateRecord();
|
||||||
|
|
||||||
const setRecordFieldValue = useSetRecordFieldValue();
|
|
||||||
|
|
||||||
const clearField = useRecoilCallback(
|
const clearField = useRecoilCallback(
|
||||||
({ snapshot, set }) =>
|
({ snapshot, set }) =>
|
||||||
() => {
|
() => {
|
||||||
@ -51,8 +48,6 @@ export const useClearField = () => {
|
|||||||
emptyFieldValue,
|
emptyFieldValue,
|
||||||
);
|
);
|
||||||
|
|
||||||
setRecordFieldValue(recordId, fieldName, emptyFieldValue);
|
|
||||||
|
|
||||||
updateRecord?.({
|
updateRecord?.({
|
||||||
variables: {
|
variables: {
|
||||||
where: { id: recordId },
|
where: { id: recordId },
|
||||||
@ -62,7 +57,7 @@ export const useClearField = () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
[recordId, fieldDefinition, updateRecord, setRecordFieldValue],
|
[recordId, fieldDefinition, updateRecord],
|
||||||
);
|
);
|
||||||
|
|
||||||
return clearField;
|
return clearField;
|
||||||
|
|||||||
@ -1,10 +1,10 @@
|
|||||||
import { useContext } from 'react';
|
import { useContext } from 'react';
|
||||||
|
|
||||||
import { isFieldValueEmpty } from '@/object-record/record-field/utils/isFieldValueEmpty';
|
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 { isDefined } from 'twenty-shared/utils';
|
||||||
|
import { FieldContext } from '../contexts/FieldContext';
|
||||||
|
|
||||||
export const useIsFieldEmpty = () => {
|
export const useIsFieldEmpty = () => {
|
||||||
const { recordId, fieldDefinition, overridenIsFieldEmpty } =
|
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 { PreComputedChipGeneratorsContext } from '@/object-metadata/contexts/PreComputedChipGeneratorsContext';
|
||||||
import { isFieldFullName } from '@/object-record/record-field/types/guards/isFieldFullName';
|
import { isFieldFullName } from '@/object-record/record-field/types/guards/isFieldFullName';
|
||||||
import { isFieldNumber } from '@/object-record/record-field/types/guards/isFieldNumber';
|
import { isFieldNumber } from '@/object-record/record-field/types/guards/isFieldNumber';
|
||||||
import { isFieldText } from '@/object-record/record-field/types/guards/isFieldText';
|
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 { 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 { isDefined } from 'twenty-shared/utils';
|
||||||
import { FieldContext } from '../../contexts/FieldContext';
|
import { FieldContext } from '../../contexts/FieldContext';
|
||||||
|
|
||||||
@ -38,7 +38,7 @@ export const useChipFieldDisplay = () => {
|
|||||||
? fieldDefinition.metadata.objectMetadataNameSingular
|
? fieldDefinition.metadata.objectMetadataNameSingular
|
||||||
: undefined;
|
: undefined;
|
||||||
|
|
||||||
const recordValue = useRecordValue(recordId);
|
const recordValue = useRecoilValue(recordStoreFamilyState(recordId));
|
||||||
|
|
||||||
if (!isNonEmptyString(objectNameSingular)) {
|
if (!isNonEmptyString(objectNameSingular)) {
|
||||||
throw new Error('Object metadata name singular is not a non-empty string');
|
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 { InformationBannerWrapper } from '@/information-banner/components/InformationBannerWrapper';
|
||||||
import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext';
|
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 { SpreadsheetImportProvider } from '@/spreadsheet-import/provider/components/SpreadsheetImportProvider';
|
||||||
|
|
||||||
import { RecordIndexFiltersToContextStoreEffect } from '@/object-record/record-index/components/RecordIndexFiltersToContextStoreEffect';
|
import { RecordIndexFiltersToContextStoreEffect } from '@/object-record/record-index/components/RecordIndexFiltersToContextStoreEffect';
|
||||||
@ -48,48 +47,46 @@ export const RecordIndexContainer = () => {
|
|||||||
<>
|
<>
|
||||||
<StyledContainer>
|
<StyledContainer>
|
||||||
<InformationBannerWrapper />
|
<InformationBannerWrapper />
|
||||||
<RecordFieldValueSelectorContextProvider>
|
<SpreadsheetImportProvider>
|
||||||
<SpreadsheetImportProvider>
|
<ViewBar
|
||||||
<ViewBar
|
viewBarId={recordIndexId}
|
||||||
viewBarId={recordIndexId}
|
optionsDropdownButton={
|
||||||
optionsDropdownButton={
|
<ObjectOptionsDropdown
|
||||||
<ObjectOptionsDropdown
|
recordIndexId={recordIndexId}
|
||||||
recordIndexId={recordIndexId}
|
objectMetadataItem={objectMetadataItem}
|
||||||
objectMetadataItem={objectMetadataItem}
|
viewType={recordIndexViewType ?? ViewType.Table}
|
||||||
viewType={recordIndexViewType ?? ViewType.Table}
|
/>
|
||||||
/>
|
}
|
||||||
}
|
/>
|
||||||
/>
|
<RecordIndexViewBarEffect
|
||||||
<RecordIndexViewBarEffect
|
objectNamePlural={objectNamePlural}
|
||||||
objectNamePlural={objectNamePlural}
|
viewBarId={recordIndexId}
|
||||||
|
/>
|
||||||
|
</SpreadsheetImportProvider>
|
||||||
|
<RecordIndexFiltersToContextStoreEffect />
|
||||||
|
{recordIndexViewType === ViewType.Table && (
|
||||||
|
<>
|
||||||
|
<RecordIndexTableContainer
|
||||||
|
recordTableId={recordIndexId}
|
||||||
viewBarId={recordIndexId}
|
viewBarId={recordIndexId}
|
||||||
/>
|
/>
|
||||||
</SpreadsheetImportProvider>
|
<RecordIndexTableContainerEffect />
|
||||||
<RecordIndexFiltersToContextStoreEffect />
|
</>
|
||||||
{recordIndexViewType === ViewType.Table && (
|
)}
|
||||||
<>
|
{recordIndexViewType === ViewType.Kanban && (
|
||||||
<RecordIndexTableContainer
|
<StyledContainerWithPadding>
|
||||||
recordTableId={recordIndexId}
|
<RecordIndexBoardContainer
|
||||||
viewBarId={recordIndexId}
|
recordBoardId={recordIndexId}
|
||||||
/>
|
viewBarId={recordIndexId}
|
||||||
<RecordIndexTableContainerEffect />
|
objectNameSingular={objectNameSingular}
|
||||||
</>
|
/>
|
||||||
)}
|
<RecordIndexBoardDataLoader
|
||||||
{recordIndexViewType === ViewType.Kanban && (
|
objectNameSingular={objectNameSingular}
|
||||||
<StyledContainerWithPadding>
|
recordBoardId={recordIndexId}
|
||||||
<RecordIndexBoardContainer
|
/>
|
||||||
recordBoardId={recordIndexId}
|
<RecordIndexBoardDataLoaderEffect recordBoardId={recordIndexId} />
|
||||||
viewBarId={recordIndexId}
|
</StyledContainerWithPadding>
|
||||||
objectNameSingular={objectNameSingular}
|
)}
|
||||||
/>
|
|
||||||
<RecordIndexBoardDataLoader
|
|
||||||
objectNameSingular={objectNameSingular}
|
|
||||||
recordBoardId={recordIndexId}
|
|
||||||
/>
|
|
||||||
<RecordIndexBoardDataLoaderEffect recordBoardId={recordIndexId} />
|
|
||||||
</StyledContainerWithPadding>
|
|
||||||
)}
|
|
||||||
</RecordFieldValueSelectorContextProvider>
|
|
||||||
</StyledContainer>
|
</StyledContainer>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -14,7 +14,7 @@ import { useRecordBoardRecordGqlFields } from '@/object-record/record-index/hook
|
|||||||
|
|
||||||
import { FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
|
import { FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
|
||||||
import { currentRecordSortsComponentState } from '@/object-record/record-sort/states/currentRecordSortsComponentState';
|
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 { useUpsertRecordsInStore } from '@/object-record/record-store/hooks/useUpsertRecordsInStore';
|
||||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||||
import { isDefined } from 'twenty-shared/utils';
|
import { isDefined } from 'twenty-shared/utils';
|
||||||
@ -32,7 +32,6 @@ export const useLoadRecordIndexBoardColumn = ({
|
|||||||
recordBoardId,
|
recordBoardId,
|
||||||
columnId,
|
columnId,
|
||||||
}: UseLoadRecordIndexBoardProps) => {
|
}: UseLoadRecordIndexBoardProps) => {
|
||||||
const setRecordValueInContextSelector = useSetRecordValue();
|
|
||||||
const { objectMetadataItem } = useObjectMetadataItem({
|
const { objectMetadataItem } = useObjectMetadataItem({
|
||||||
objectNameSingular,
|
objectNameSingular,
|
||||||
});
|
});
|
||||||
@ -102,10 +101,7 @@ export const useLoadRecordIndexBoardColumn = ({
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
upsertRecordsInStore(records);
|
upsertRecordsInStore(records);
|
||||||
for (const record of records) {
|
}, [records, upsertRecordsInStore]);
|
||||||
setRecordValueInContextSelector(record.id, record);
|
|
||||||
}
|
|
||||||
}, [records, upsertRecordsInStore, setRecordValueInContextSelector]);
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
records,
|
records,
|
||||||
|
|||||||
@ -2,7 +2,6 @@ import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadata
|
|||||||
import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems';
|
import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems';
|
||||||
import { useFindOneRecord } from '@/object-record/hooks/useFindOneRecord';
|
import { useFindOneRecord } from '@/object-record/hooks/useFindOneRecord';
|
||||||
import { buildFindOneRecordForShowPageOperationSignature } from '@/object-record/record-show/graphql/operations/factories/findOneRecordForShowPageOperationSignatureFactory';
|
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 { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
|
||||||
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
|
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
|
||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
@ -19,7 +18,6 @@ export const RecordShowEffect = ({
|
|||||||
}: RecordShowEffectProps) => {
|
}: RecordShowEffectProps) => {
|
||||||
const { objectMetadataItem } = useObjectMetadataItem({ objectNameSingular });
|
const { objectMetadataItem } = useObjectMetadataItem({ objectNameSingular });
|
||||||
const { objectMetadataItems } = useObjectMetadataItems();
|
const { objectMetadataItems } = useObjectMetadataItems();
|
||||||
const setRecordValueInContextSelector = useSetRecordValue();
|
|
||||||
|
|
||||||
const FIND_ONE_RECORD_FOR_SHOW_PAGE_OPERATION_SIGNATURE =
|
const FIND_ONE_RECORD_FOR_SHOW_PAGE_OPERATION_SIGNATURE =
|
||||||
buildFindOneRecordForShowPageOperationSignature({
|
buildFindOneRecordForShowPageOperationSignature({
|
||||||
@ -44,10 +42,8 @@ export const RecordShowEffect = ({
|
|||||||
if (JSON.stringify(previousRecordValue) !== JSON.stringify(newRecord)) {
|
if (JSON.stringify(previousRecordValue) !== JSON.stringify(newRecord)) {
|
||||||
set(recordStoreFamilyState(recordId), newRecord);
|
set(recordStoreFamilyState(recordId), newRecord);
|
||||||
}
|
}
|
||||||
|
|
||||||
setRecordValueInContextSelector(recordId, newRecord);
|
|
||||||
},
|
},
|
||||||
[recordId, setRecordValueInContextSelector],
|
[recordId],
|
||||||
);
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|||||||
@ -3,7 +3,7 @@ import { useContext, useEffect } from 'react';
|
|||||||
import { useFindOneRecord } from '@/object-record/hooks/useFindOneRecord';
|
import { useFindOneRecord } from '@/object-record/hooks/useFindOneRecord';
|
||||||
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
|
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
|
||||||
import { FieldRelationMetadata } from '@/object-record/record-field/types/FieldMetadata';
|
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 { useUpsertRecordsInStore } from '@/object-record/record-store/hooks/useUpsertRecordsInStore';
|
||||||
import { isDefined } from 'twenty-shared/utils';
|
import { isDefined } from 'twenty-shared/utils';
|
||||||
|
|
||||||
@ -14,8 +14,6 @@ type RecordDetailRelationRecordsListItemEffectProps = {
|
|||||||
export const RecordDetailRelationRecordsListItemEffect = ({
|
export const RecordDetailRelationRecordsListItemEffect = ({
|
||||||
relationRecordId,
|
relationRecordId,
|
||||||
}: RecordDetailRelationRecordsListItemEffectProps) => {
|
}: RecordDetailRelationRecordsListItemEffectProps) => {
|
||||||
const setRecordValueInContextSelector = useSetRecordValue();
|
|
||||||
|
|
||||||
const { fieldDefinition } = useContext(FieldContext);
|
const { fieldDefinition } = useContext(FieldContext);
|
||||||
|
|
||||||
const { relationObjectMetadataNameSingular } =
|
const { relationObjectMetadataNameSingular } =
|
||||||
@ -31,9 +29,8 @@ export const RecordDetailRelationRecordsListItemEffect = ({
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isDefined(record)) {
|
if (isDefined(record)) {
|
||||||
upsertRecords([record]);
|
upsertRecords([record]);
|
||||||
setRecordValueInContextSelector(record.id, record);
|
|
||||||
}
|
}
|
||||||
}, [record, upsertRecords, setRecordValueInContextSelector]);
|
}, [record, upsertRecords]);
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,78 +1,16 @@
|
|||||||
import { Dispatch, SetStateAction, useState } from 'react';
|
import { recordStoreFamilySelector } from '@/object-record/record-store/states/selectors/recordStoreFamilySelector';
|
||||||
import { createContext, useContextSelector } from 'use-context-selector';
|
import { useRecoilValue } from 'recoil';
|
||||||
|
|
||||||
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;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const useRecordFieldValue = <T,>(
|
export const useRecordFieldValue = <T,>(
|
||||||
recordId: string,
|
recordId: string,
|
||||||
fieldName: string,
|
fieldName: string,
|
||||||
) => {
|
) => {
|
||||||
const recordFieldValue = useContextSelector(
|
const recordFieldValue = useRecoilValue(
|
||||||
RecordFieldValueSelectorContext,
|
recordStoreFamilySelector({
|
||||||
(value) => value[0]?.[recordId]?.[fieldName],
|
recordId,
|
||||||
|
fieldName,
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
return recordFieldValue as T | undefined;
|
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 { getBasePathToShowPage } from '@/object-metadata/utils/getBasePathToShowPage';
|
||||||
|
|
||||||
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
|
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 { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
|
||||||
import { RecordTableComponentInstance } from '@/object-record/record-table/components/RecordTableComponentInstance';
|
import { RecordTableComponentInstance } from '@/object-record/record-table/components/RecordTableComponentInstance';
|
||||||
import { RecordTableCellContext } from '@/object-record/record-table/contexts/RecordTableCellContext';
|
import { RecordTableCellContext } from '@/object-record/record-table/contexts/RecordTableCellContext';
|
||||||
@ -36,22 +32,14 @@ const RelationFieldValueSetterEffect = () => {
|
|||||||
recordStoreFamilyState(mockPerformance.relationRecordId),
|
recordStoreFamilyState(mockPerformance.relationRecordId),
|
||||||
);
|
);
|
||||||
|
|
||||||
const setRecordValue = useSetRecordValue();
|
|
||||||
|
|
||||||
const [, setObjectMetadataItems] = useRecoilState(objectMetadataItemsState);
|
const [, setObjectMetadataItems] = useRecoilState(objectMetadataItemsState);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setEntity(mockPerformance.entityValue);
|
setEntity(mockPerformance.entityValue);
|
||||||
setRelationEntity(mockPerformance.relationFieldValue);
|
setRelationEntity(mockPerformance.relationFieldValue);
|
||||||
|
|
||||||
setRecordValue(mockPerformance.entityValue.id, mockPerformance.entityValue);
|
|
||||||
setRecordValue(
|
|
||||||
mockPerformance.relationFieldValue.id,
|
|
||||||
mockPerformance.relationFieldValue,
|
|
||||||
);
|
|
||||||
|
|
||||||
setObjectMetadataItems(generatedMockObjectMetadataItems);
|
setObjectMetadataItems(generatedMockObjectMetadataItems);
|
||||||
}, [setEntity, setRelationEntity, setRecordValue, setObjectMetadataItems]);
|
}, [setEntity, setRelationEntity, setObjectMetadataItems]);
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
@ -63,95 +51,93 @@ const meta: Meta = {
|
|||||||
ChipGeneratorsDecorator,
|
ChipGeneratorsDecorator,
|
||||||
(Story) => {
|
(Story) => {
|
||||||
return (
|
return (
|
||||||
<RecordFieldValueSelectorContextProvider>
|
<RecordIndexContextProvider
|
||||||
<RecordIndexContextProvider
|
value={{
|
||||||
|
indexIdentifierUrl: (_recordId: string) => '',
|
||||||
|
onIndexRecordsLoaded: () => {},
|
||||||
|
objectNamePlural: 'companies',
|
||||||
|
objectNameSingular: 'company',
|
||||||
|
objectMetadataItem: mockPerformance.objectMetadataItem as any,
|
||||||
|
recordIndexId: 'recordIndexId',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<RecordTableContextProvider
|
||||||
value={{
|
value={{
|
||||||
indexIdentifierUrl: (_recordId: string) => '',
|
recordTableId: 'recordTableId',
|
||||||
onIndexRecordsLoaded: () => {},
|
viewBarId: mockPerformance.recordId,
|
||||||
objectNamePlural: 'companies',
|
|
||||||
objectNameSingular: 'company',
|
|
||||||
objectMetadataItem: mockPerformance.objectMetadataItem as any,
|
objectMetadataItem: mockPerformance.objectMetadataItem as any,
|
||||||
recordIndexId: 'recordIndexId',
|
visibleTableColumns: mockPerformance.visibleTableColumns as any,
|
||||||
|
objectNameSingular:
|
||||||
|
mockPerformance.objectMetadataItem.nameSingular,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<RecordTableContextProvider
|
<RecordTableComponentInstance
|
||||||
value={{
|
recordTableId="asd"
|
||||||
recordTableId: 'recordTableId',
|
onColumnsChange={() => {}}
|
||||||
viewBarId: mockPerformance.recordId,
|
|
||||||
objectMetadataItem: mockPerformance.objectMetadataItem as any,
|
|
||||||
visibleTableColumns: mockPerformance.visibleTableColumns as any,
|
|
||||||
objectNameSingular:
|
|
||||||
mockPerformance.objectMetadataItem.nameSingular,
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<RecordTableComponentInstance
|
<RecordTableBodyContextProvider
|
||||||
recordTableId="asd"
|
value={{
|
||||||
onColumnsChange={() => {}}
|
onOpenTableCell: () => {},
|
||||||
|
onMoveFocus: () => {},
|
||||||
|
onCloseTableCell: () => {},
|
||||||
|
onMoveHoverToCurrentCell: () => {},
|
||||||
|
onActionMenuDropdownOpened: () => {},
|
||||||
|
onCellMouseEnter: () => {},
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<RecordTableBodyContextProvider
|
<RecordTableRowContextProvider
|
||||||
value={{
|
value={{
|
||||||
onOpenTableCell: () => {},
|
objectNameSingular:
|
||||||
onMoveFocus: () => {},
|
mockPerformance.entityValue.__typename.toLocaleLowerCase(),
|
||||||
onCloseTableCell: () => {},
|
recordId: mockPerformance.recordId,
|
||||||
onMoveHoverToCurrentCell: () => {},
|
rowIndex: 0,
|
||||||
onActionMenuDropdownOpened: () => {},
|
pathToShowPage:
|
||||||
onCellMouseEnter: () => {},
|
getBasePathToShowPage({
|
||||||
|
objectNameSingular:
|
||||||
|
mockPerformance.entityValue.__typename.toLocaleLowerCase(),
|
||||||
|
}) + mockPerformance.recordId,
|
||||||
|
isSelected: false,
|
||||||
|
inView: true,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<RecordTableRowContextProvider
|
<RecordTableRowDraggableContextProvider
|
||||||
value={{
|
value={{
|
||||||
objectNameSingular:
|
isDragging: false,
|
||||||
mockPerformance.entityValue.__typename.toLocaleLowerCase(),
|
dragHandleProps: null,
|
||||||
recordId: mockPerformance.recordId,
|
|
||||||
rowIndex: 0,
|
|
||||||
pathToShowPage:
|
|
||||||
getBasePathToShowPage({
|
|
||||||
objectNameSingular:
|
|
||||||
mockPerformance.entityValue.__typename.toLocaleLowerCase(),
|
|
||||||
}) + mockPerformance.recordId,
|
|
||||||
isSelected: false,
|
|
||||||
inView: true,
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<RecordTableRowDraggableContextProvider
|
<RecordTableCellContext.Provider
|
||||||
value={{
|
value={{
|
||||||
isDragging: false,
|
columnDefinition: mockPerformance.fieldDefinition,
|
||||||
dragHandleProps: null,
|
cellPosition: { row: 0, column: 0 },
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<RecordTableCellContext.Provider
|
<FieldContext.Provider
|
||||||
value={{
|
value={{
|
||||||
columnDefinition: mockPerformance.fieldDefinition,
|
recordId: mockPerformance.recordId,
|
||||||
cellPosition: { row: 0, column: 0 },
|
isLabelIdentifier: false,
|
||||||
|
fieldDefinition: {
|
||||||
|
...mockPerformance.fieldDefinition,
|
||||||
|
},
|
||||||
|
isReadOnly: false,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<FieldContext.Provider
|
<RelationFieldValueSetterEffect />
|
||||||
value={{
|
<table>
|
||||||
recordId: mockPerformance.recordId,
|
<tbody>
|
||||||
isLabelIdentifier: false,
|
<tr>
|
||||||
fieldDefinition: {
|
<Story />
|
||||||
...mockPerformance.fieldDefinition,
|
</tr>
|
||||||
},
|
</tbody>
|
||||||
isReadOnly: false,
|
</table>
|
||||||
}}
|
</FieldContext.Provider>
|
||||||
>
|
</RecordTableCellContext.Provider>
|
||||||
<RelationFieldValueSetterEffect />
|
</RecordTableRowDraggableContextProvider>
|
||||||
<table>
|
</RecordTableRowContextProvider>
|
||||||
<tbody>
|
</RecordTableBodyContextProvider>
|
||||||
<tr>
|
</RecordTableComponentInstance>
|
||||||
<Story />
|
</RecordTableContextProvider>
|
||||||
</tr>
|
</RecordIndexContextProvider>
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</FieldContext.Provider>
|
|
||||||
</RecordTableCellContext.Provider>
|
|
||||||
</RecordTableRowDraggableContextProvider>
|
|
||||||
</RecordTableRowContextProvider>
|
|
||||||
</RecordTableBodyContextProvider>
|
|
||||||
</RecordTableComponentInstance>
|
|
||||||
</RecordTableContextProvider>
|
|
||||||
</RecordIndexContextProvider>
|
|
||||||
</RecordFieldValueSelectorContextProvider>
|
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
ComponentDecorator,
|
ComponentDecorator,
|
||||||
|
|||||||
@ -2,7 +2,7 @@ import { useRecoilCallback } from 'recoil';
|
|||||||
|
|
||||||
import { recordIndexRecordIdsByGroupComponentFamilyState } from '@/object-record/record-index/states/recordIndexRecordIdsByGroupComponentFamilyState';
|
import { recordIndexRecordIdsByGroupComponentFamilyState } from '@/object-record/record-index/states/recordIndexRecordIdsByGroupComponentFamilyState';
|
||||||
import { recordIndexAllRecordIdsComponentSelector } from '@/object-record/record-index/states/selectors/recordIndexAllRecordIdsComponentSelector';
|
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 { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
|
||||||
import { useSetIsRecordTableFocusActive } from '@/object-record/record-table/record-table-cell/hooks/useSetIsRecordTableFocusActive';
|
import { useSetIsRecordTableFocusActive } from '@/object-record/record-table/record-table-cell/hooks/useSetIsRecordTableFocusActive';
|
||||||
import { hasUserSelectedAllRowsComponentState } from '@/object-record/record-table/record-table-row/states/hasUserSelectedAllRowsFamilyState';
|
import { hasUserSelectedAllRowsComponentState } from '@/object-record/record-table/record-table-row/states/hasUserSelectedAllRowsFamilyState';
|
||||||
@ -27,8 +27,6 @@ export const useSetRecordTableData = ({
|
|||||||
recordTableId,
|
recordTableId,
|
||||||
onEntityCountChange,
|
onEntityCountChange,
|
||||||
}: useSetRecordTableDataProps) => {
|
}: useSetRecordTableDataProps) => {
|
||||||
const setRecordValueInContextSelector = useSetRecordValue();
|
|
||||||
|
|
||||||
const recordIndexRecordIdsByGroupFamilyState =
|
const recordIndexRecordIdsByGroupFamilyState =
|
||||||
useRecoilComponentCallbackStateV2(
|
useRecoilComponentCallbackStateV2(
|
||||||
recordIndexRecordIdsByGroupComponentFamilyState,
|
recordIndexRecordIdsByGroupComponentFamilyState,
|
||||||
@ -82,7 +80,6 @@ export const useSetRecordTableData = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
set(recordStoreFamilyState(record.id), newRecord);
|
set(recordStoreFamilyState(record.id), newRecord);
|
||||||
setRecordValueInContextSelector(record.id, newRecord);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -130,7 +127,6 @@ export const useSetRecordTableData = ({
|
|||||||
setRecordTableHoverPosition,
|
setRecordTableHoverPosition,
|
||||||
onEntityCountChange,
|
onEntityCountChange,
|
||||||
isRowSelectedFamilyState,
|
isRowSelectedFamilyState,
|
||||||
setRecordValueInContextSelector,
|
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,12 +1,13 @@
|
|||||||
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
|
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 { 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 { 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 { TitleInputHotkeyScope } from '@/ui/input/types/TitleInputHotkeyScope';
|
||||||
import { usePreviousHotkeyScope } from '@/ui/utilities/hotkey/hooks/usePreviousHotkeyScope';
|
import { usePreviousHotkeyScope } from '@/ui/utilities/hotkey/hooks/usePreviousHotkeyScope';
|
||||||
import { Theme, withTheme } from '@emotion/react';
|
import { Theme, withTheme } from '@emotion/react';
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
import { useContext } from 'react';
|
import { useContext } from 'react';
|
||||||
|
import { useRecoilValue } from 'recoil';
|
||||||
import { OverflowingTextWithTooltip } from 'twenty-ui/display';
|
import { OverflowingTextWithTooltip } from 'twenty-ui/display';
|
||||||
|
|
||||||
const StyledDiv = styled.div`
|
const StyledDiv = styled.div`
|
||||||
@ -33,7 +34,9 @@ const StyledEmptyText = withTheme(styled.div<{ theme: Theme }>`
|
|||||||
|
|
||||||
export const RecordTitleCellSingleTextDisplayMode = () => {
|
export const RecordTitleCellSingleTextDisplayMode = () => {
|
||||||
const { recordId, fieldDefinition } = useContext(FieldContext);
|
const { recordId, fieldDefinition } = useContext(FieldContext);
|
||||||
const recordValue = useRecordValue(recordId);
|
|
||||||
|
const recordValue = useRecoilValue(recordStoreFamilyState(recordId));
|
||||||
|
|
||||||
const isEmpty =
|
const isEmpty =
|
||||||
recordValue?.[fieldDefinition.metadata.fieldName]?.trim() === '';
|
recordValue?.[fieldDefinition.metadata.fieldName]?.trim() === '';
|
||||||
|
|
||||||
|
|||||||
@ -112,10 +112,7 @@ export const SettingsDataModelFieldPreview = ({
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{isDefined(previewRecord) ? (
|
{isDefined(previewRecord) ? (
|
||||||
<SettingsDataModelSetPreviewRecordEffect
|
<SettingsDataModelSetPreviewRecordEffect record={previewRecord} />
|
||||||
fieldName={fieldName}
|
|
||||||
record={previewRecord}
|
|
||||||
/>
|
|
||||||
) : (
|
) : (
|
||||||
<SettingsDataModelSetFieldValueEffect
|
<SettingsDataModelSetFieldValueEffect
|
||||||
recordId={recordId}
|
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 { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
|
||||||
import { recordStoreFamilySelector } from '@/object-record/record-store/states/selectors/recordStoreFamilySelector';
|
import { recordStoreFamilySelector } from '@/object-record/record-store/states/selectors/recordStoreFamilySelector';
|
||||||
import { settingsPreviewRecordIdState } from '@/settings/data-model/fields/preview/states/settingsPreviewRecordIdState';
|
import { settingsPreviewRecordIdState } from '@/settings/data-model/fields/preview/states/settingsPreviewRecordIdState';
|
||||||
@ -29,7 +28,6 @@ export const SettingsDataModelSetFieldValueEffect = ({
|
|||||||
fieldName,
|
fieldName,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
const setRecordFieldValue = useSetRecordFieldValue();
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (
|
if (
|
||||||
@ -37,23 +35,10 @@ export const SettingsDataModelSetFieldValueEffect = ({
|
|||||||
!!upsertedPreviewRecord[fieldName]
|
!!upsertedPreviewRecord[fieldName]
|
||||||
) {
|
) {
|
||||||
setFieldValue(upsertedPreviewRecord[fieldName]);
|
setFieldValue(upsertedPreviewRecord[fieldName]);
|
||||||
setRecordFieldValue(
|
|
||||||
recordId,
|
|
||||||
fieldName,
|
|
||||||
upsertedPreviewRecord[fieldName],
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
setFieldValue(value);
|
setFieldValue(value);
|
||||||
setRecordFieldValue(recordId, fieldName, value);
|
|
||||||
}
|
}
|
||||||
}, [
|
}, [value, setFieldValue, recordId, fieldName, upsertedPreviewRecord]);
|
||||||
value,
|
|
||||||
setFieldValue,
|
|
||||||
setRecordFieldValue,
|
|
||||||
recordId,
|
|
||||||
fieldName,
|
|
||||||
upsertedPreviewRecord,
|
|
||||||
]);
|
|
||||||
|
|
||||||
return null;
|
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 { useUpsertRecordsInStore } from '@/object-record/record-store/hooks/useUpsertRecordsInStore';
|
||||||
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
|
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
|
||||||
import { settingsPreviewRecordIdState } from '@/settings/data-model/fields/preview/states/settingsPreviewRecordIdState';
|
import { settingsPreviewRecordIdState } from '@/settings/data-model/fields/preview/states/settingsPreviewRecordIdState';
|
||||||
@ -7,15 +6,12 @@ import { useSetRecoilState } from 'recoil';
|
|||||||
|
|
||||||
type SettingsDataModelSetPreviewRecordEffectProps = {
|
type SettingsDataModelSetPreviewRecordEffectProps = {
|
||||||
record: ObjectRecord;
|
record: ObjectRecord;
|
||||||
fieldName: string;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const SettingsDataModelSetPreviewRecordEffect = ({
|
export const SettingsDataModelSetPreviewRecordEffect = ({
|
||||||
record,
|
record,
|
||||||
fieldName,
|
|
||||||
}: SettingsDataModelSetPreviewRecordEffectProps) => {
|
}: SettingsDataModelSetPreviewRecordEffectProps) => {
|
||||||
const { upsertRecords: upsertRecordsInStore } = useUpsertRecordsInStore();
|
const { upsertRecords: upsertRecordsInStore } = useUpsertRecordsInStore();
|
||||||
const setRecordFieldValue = useSetRecordFieldValue();
|
|
||||||
|
|
||||||
const setSettingsPreviewRecordId = useSetRecoilState(
|
const setSettingsPreviewRecordId = useSetRecoilState(
|
||||||
settingsPreviewRecordIdState,
|
settingsPreviewRecordIdState,
|
||||||
@ -23,15 +19,8 @@ export const SettingsDataModelSetPreviewRecordEffect = ({
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
upsertRecordsInStore([record]);
|
upsertRecordsInStore([record]);
|
||||||
setRecordFieldValue(record.id, fieldName, record[fieldName]);
|
|
||||||
setSettingsPreviewRecordId(record.id);
|
setSettingsPreviewRecordId(record.id);
|
||||||
}, [
|
}, [record, upsertRecordsInStore, setSettingsPreviewRecordId]);
|
||||||
record,
|
|
||||||
upsertRecordsInStore,
|
|
||||||
setRecordFieldValue,
|
|
||||||
fieldName,
|
|
||||||
setSettingsPreviewRecordId,
|
|
||||||
]);
|
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,16 +1,15 @@
|
|||||||
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||||
|
|
||||||
import { useUpdateOneObjectMetadataItem } from '@/object-metadata/hooks/useUpdateOneObjectMetadataItem';
|
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 { SettingsUpdateDataModelObjectAboutForm } from '@/settings/data-model/object-details/components/SettingsUpdateDataModelObjectAboutForm';
|
||||||
import { SettingsDataModelObjectSettingsFormCard } from '@/settings/data-model/objects/forms/components/SettingsDataModelObjectSettingsFormCard';
|
import { SettingsDataModelObjectSettingsFormCard } from '@/settings/data-model/objects/forms/components/SettingsDataModelObjectSettingsFormCard';
|
||||||
import { SettingsPath } from '@/types/SettingsPath';
|
import { SettingsPath } from '@/types/SettingsPath';
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
import { useLingui } from '@lingui/react/macro';
|
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 { H2Title, IconArchive } from 'twenty-ui/display';
|
||||||
|
import { Button } from 'twenty-ui/input';
|
||||||
import { Section } from 'twenty-ui/layout';
|
import { Section } from 'twenty-ui/layout';
|
||||||
|
import { useNavigateSettings } from '~/hooks/useNavigateSettings';
|
||||||
|
|
||||||
type ObjectSettingsProps = {
|
type ObjectSettingsProps = {
|
||||||
objectMetadataItem: ObjectMetadataItem;
|
objectMetadataItem: ObjectMetadataItem;
|
||||||
@ -39,43 +38,38 @@ export const ObjectSettings = ({ objectMetadataItem }: ObjectSettingsProps) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<RecordFieldValueSelectorContextProvider>
|
<StyledContentContainer>
|
||||||
<StyledContentContainer>
|
<StyledFormSection>
|
||||||
<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
|
<H2Title
|
||||||
title={t`About`}
|
title={t`Options`}
|
||||||
description={t`Name in both singular (e.g., 'Invoice') and plural (e.g., 'Invoices') forms.`}
|
description={t`Choose the fields that will identify your records`}
|
||||||
/>
|
/>
|
||||||
<SettingsUpdateDataModelObjectAboutForm
|
<SettingsDataModelObjectSettingsFormCard
|
||||||
objectMetadataItem={objectMetadataItem}
|
objectMetadataItem={objectMetadataItem}
|
||||||
/>
|
/>
|
||||||
</StyledFormSection>
|
</Section>
|
||||||
<StyledFormSection>
|
</StyledFormSection>
|
||||||
<Section>
|
<StyledFormSection>
|
||||||
<H2Title
|
<Section>
|
||||||
title={t`Options`}
|
<H2Title title={t`Danger zone`} description={t`Deactivate object`} />
|
||||||
description={t`Choose the fields that will identify your records`}
|
<Button
|
||||||
/>
|
Icon={IconArchive}
|
||||||
<SettingsDataModelObjectSettingsFormCard
|
title={t`Deactivate`}
|
||||||
objectMetadataItem={objectMetadataItem}
|
size="small"
|
||||||
/>
|
onClick={handleDisable}
|
||||||
</Section>
|
/>
|
||||||
</StyledFormSection>
|
</Section>
|
||||||
<StyledFormSection>
|
</StyledFormSection>
|
||||||
<Section>
|
</StyledContentContainer>
|
||||||
<H2Title
|
|
||||||
title={t`Danger zone`}
|
|
||||||
description={t`Deactivate object`}
|
|
||||||
/>
|
|
||||||
<Button
|
|
||||||
Icon={IconArchive}
|
|
||||||
title={t`Deactivate`}
|
|
||||||
size="small"
|
|
||||||
onClick={handleDisable}
|
|
||||||
/>
|
|
||||||
</Section>
|
|
||||||
</StyledFormSection>
|
|
||||||
</StyledContentContainer>
|
|
||||||
</RecordFieldValueSelectorContextProvider>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
|
|
||||||
import { RecordFieldValueSelectorContextProvider } from '@/object-record/record-store/contexts/RecordFieldValueSelectorContext';
|
|
||||||
import { SignInBackgroundMockContainer } from '@/sign-in-background-mock/components/SignInBackgroundMockContainer';
|
import { SignInBackgroundMockContainer } from '@/sign-in-background-mock/components/SignInBackgroundMockContainer';
|
||||||
import { PageBody } from '@/ui/layout/page/components/PageBody';
|
import { PageBody } from '@/ui/layout/page/components/PageBody';
|
||||||
import { PageContainer } from '@/ui/layout/page/components/PageContainer';
|
import { PageContainer } from '@/ui/layout/page/components/PageContainer';
|
||||||
@ -18,11 +17,9 @@ export const SignInBackgroundMockPage = () => {
|
|||||||
<PageContainer>
|
<PageContainer>
|
||||||
<PageHeader title="Companies" Icon={IconBuildingSkyscraper} />
|
<PageHeader title="Companies" Icon={IconBuildingSkyscraper} />
|
||||||
<PageBody>
|
<PageBody>
|
||||||
<RecordFieldValueSelectorContextProvider>
|
<StyledTableContainer>
|
||||||
<StyledTableContainer>
|
<SignInBackgroundMockContainer />
|
||||||
<SignInBackgroundMockContainer />
|
</StyledTableContainer>
|
||||||
</StyledTableContainer>
|
|
||||||
</RecordFieldValueSelectorContextProvider>
|
|
||||||
</PageBody>
|
</PageBody>
|
||||||
</PageContainer>
|
</PageContainer>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -11,7 +11,6 @@ import { RecordShowContainer } from '@/object-record/record-show/components/Reco
|
|||||||
import { RecordShowEffect } from '@/object-record/record-show/components/RecordShowEffect';
|
import { RecordShowEffect } from '@/object-record/record-show/components/RecordShowEffect';
|
||||||
import { useRecordShowPage } from '@/object-record/record-show/hooks/useRecordShowPage';
|
import { useRecordShowPage } from '@/object-record/record-show/hooks/useRecordShowPage';
|
||||||
import { RecordSortsComponentInstanceContext } from '@/object-record/record-sort/states/context/RecordSortsComponentInstanceContext';
|
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 { PageHeaderToggleCommandMenuButton } from '@/ui/layout/page-header/components/PageHeaderToggleCommandMenuButton';
|
||||||
import { PageBody } from '@/ui/layout/page/components/PageBody';
|
import { PageBody } from '@/ui/layout/page/components/PageBody';
|
||||||
import { PageContainer } from '@/ui/layout/page/components/PageContainer';
|
import { PageContainer } from '@/ui/layout/page/components/PageContainer';
|
||||||
@ -30,57 +29,55 @@ export const RecordShowPage = () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<RecordFieldValueSelectorContextProvider>
|
<RecordFilterGroupsComponentInstanceContext.Provider
|
||||||
<RecordFilterGroupsComponentInstanceContext.Provider
|
value={{ instanceId: `record-show-${objectRecordId}` }}
|
||||||
|
>
|
||||||
|
<RecordFiltersComponentInstanceContext.Provider
|
||||||
value={{ instanceId: `record-show-${objectRecordId}` }}
|
value={{ instanceId: `record-show-${objectRecordId}` }}
|
||||||
>
|
>
|
||||||
<RecordFiltersComponentInstanceContext.Provider
|
<RecordSortsComponentInstanceContext.Provider
|
||||||
value={{ instanceId: `record-show-${objectRecordId}` }}
|
value={{ instanceId: `record-show-${objectRecordId}` }}
|
||||||
>
|
>
|
||||||
<RecordSortsComponentInstanceContext.Provider
|
<ContextStoreComponentInstanceContext.Provider
|
||||||
value={{ instanceId: `record-show-${objectRecordId}` }}
|
value={{ instanceId: MAIN_CONTEXT_STORE_INSTANCE_ID }}
|
||||||
>
|
>
|
||||||
<ContextStoreComponentInstanceContext.Provider
|
<ActionMenuComponentInstanceContext.Provider
|
||||||
value={{ instanceId: MAIN_CONTEXT_STORE_INSTANCE_ID }}
|
value={{ instanceId: `record-show-${objectRecordId}` }}
|
||||||
>
|
>
|
||||||
<ActionMenuComponentInstanceContext.Provider
|
<PageContainer>
|
||||||
value={{ instanceId: `record-show-${objectRecordId}` }}
|
<RecordShowPageTitle
|
||||||
>
|
objectNameSingular={objectNameSingular}
|
||||||
<PageContainer>
|
objectRecordId={objectRecordId}
|
||||||
<RecordShowPageTitle
|
/>
|
||||||
objectNameSingular={objectNameSingular}
|
<RecordShowPageHeader
|
||||||
objectRecordId={objectRecordId}
|
objectNameSingular={objectNameSingular}
|
||||||
/>
|
objectRecordId={objectRecordId}
|
||||||
<RecordShowPageHeader
|
>
|
||||||
objectNameSingular={objectNameSingular}
|
<RecordShowActionMenu />
|
||||||
objectRecordId={objectRecordId}
|
<PageHeaderToggleCommandMenuButton />
|
||||||
|
</RecordShowPageHeader>
|
||||||
|
<PageBody>
|
||||||
|
<TimelineActivityContext.Provider
|
||||||
|
value={{
|
||||||
|
recordId: objectRecordId,
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<RecordShowActionMenu />
|
<RecordShowEffect
|
||||||
<PageHeaderToggleCommandMenuButton />
|
objectNameSingular={objectNameSingular}
|
||||||
</RecordShowPageHeader>
|
recordId={objectRecordId}
|
||||||
<PageBody>
|
/>
|
||||||
<TimelineActivityContext.Provider
|
<RecordShowContainer
|
||||||
value={{
|
objectNameSingular={objectNameSingular}
|
||||||
recordId: objectRecordId,
|
objectRecordId={objectRecordId}
|
||||||
}}
|
loading={false}
|
||||||
>
|
/>
|
||||||
<RecordShowEffect
|
</TimelineActivityContext.Provider>
|
||||||
objectNameSingular={objectNameSingular}
|
</PageBody>
|
||||||
recordId={objectRecordId}
|
</PageContainer>
|
||||||
/>
|
</ActionMenuComponentInstanceContext.Provider>
|
||||||
<RecordShowContainer
|
</ContextStoreComponentInstanceContext.Provider>
|
||||||
objectNameSingular={objectNameSingular}
|
</RecordSortsComponentInstanceContext.Provider>
|
||||||
objectRecordId={objectRecordId}
|
</RecordFiltersComponentInstanceContext.Provider>
|
||||||
loading={false}
|
</RecordFilterGroupsComponentInstanceContext.Provider>
|
||||||
/>
|
|
||||||
</TimelineActivityContext.Provider>
|
|
||||||
</PageBody>
|
|
||||||
</PageContainer>
|
|
||||||
</ActionMenuComponentInstanceContext.Provider>
|
|
||||||
</ContextStoreComponentInstanceContext.Provider>
|
|
||||||
</RecordSortsComponentInstanceContext.Provider>
|
|
||||||
</RecordFiltersComponentInstanceContext.Provider>
|
|
||||||
</RecordFilterGroupsComponentInstanceContext.Provider>
|
|
||||||
</RecordFieldValueSelectorContextProvider>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -12,7 +12,6 @@ import { useGetRelationMetadata } from '@/object-metadata/hooks/useGetRelationMe
|
|||||||
import { useUpdateOneFieldMetadataItem } from '@/object-metadata/hooks/useUpdateOneFieldMetadataItem';
|
import { useUpdateOneFieldMetadataItem } from '@/object-metadata/hooks/useUpdateOneFieldMetadataItem';
|
||||||
import { formatFieldMetadataItemInput } from '@/object-metadata/utils/formatFieldMetadataItemInput';
|
import { formatFieldMetadataItemInput } from '@/object-metadata/utils/formatFieldMetadataItemInput';
|
||||||
import { isLabelIdentifierField } from '@/object-metadata/utils/isLabelIdentifierField';
|
import { isLabelIdentifierField } from '@/object-metadata/utils/isLabelIdentifierField';
|
||||||
import { RecordFieldValueSelectorContextProvider } from '@/object-record/record-store/contexts/RecordFieldValueSelectorContext';
|
|
||||||
import { SaveAndCancelButtons } from '@/settings/components/SaveAndCancelButtons/SaveAndCancelButtons';
|
import { SaveAndCancelButtons } from '@/settings/components/SaveAndCancelButtons/SaveAndCancelButtons';
|
||||||
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
|
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
|
||||||
import { FIELD_NAME_MAXIMUM_LENGTH } from '@/settings/data-model/constants/FieldNameMaximumLength';
|
import { FIELD_NAME_MAXIMUM_LENGTH } from '@/settings/data-model/constants/FieldNameMaximumLength';
|
||||||
@ -161,7 +160,7 @@ export const SettingsObjectFieldEdit = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<RecordFieldValueSelectorContextProvider>
|
<>
|
||||||
{/* eslint-disable-next-line react/jsx-props-no-spreading */}
|
{/* eslint-disable-next-line react/jsx-props-no-spreading */}
|
||||||
<FormProvider {...formConfig}>
|
<FormProvider {...formConfig}>
|
||||||
<SubMenuTopBarContainer
|
<SubMenuTopBarContainer
|
||||||
@ -265,6 +264,6 @@ export const SettingsObjectFieldEdit = () => {
|
|||||||
</SettingsPageContainer>
|
</SettingsPageContainer>
|
||||||
</SubMenuTopBarContainer>
|
</SubMenuTopBarContainer>
|
||||||
</FormProvider>
|
</FormProvider>
|
||||||
</RecordFieldValueSelectorContextProvider>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -3,7 +3,6 @@ import { useFieldMetadataItem } from '@/object-metadata/hooks/useFieldMetadataIt
|
|||||||
import { useFilteredObjectMetadataItems } from '@/object-metadata/hooks/useFilteredObjectMetadataItems';
|
import { useFilteredObjectMetadataItems } from '@/object-metadata/hooks/useFilteredObjectMetadataItems';
|
||||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||||
import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords';
|
import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords';
|
||||||
import { RecordFieldValueSelectorContextProvider } from '@/object-record/record-store/contexts/RecordFieldValueSelectorContext';
|
|
||||||
import { SaveAndCancelButtons } from '@/settings/components/SaveAndCancelButtons/SaveAndCancelButtons';
|
import { SaveAndCancelButtons } from '@/settings/components/SaveAndCancelButtons/SaveAndCancelButtons';
|
||||||
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
|
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
|
||||||
import { SettingsDataModelNewFieldBreadcrumbDropDown } from '@/settings/data-model/components/SettingsDataModelNewFieldBreadcrumbDropDown';
|
import { SettingsDataModelNewFieldBreadcrumbDropDown } from '@/settings/data-model/components/SettingsDataModelNewFieldBreadcrumbDropDown';
|
||||||
@ -27,6 +26,8 @@ import pick from 'lodash.pick';
|
|||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { FormProvider, useForm } from 'react-hook-form';
|
import { FormProvider, useForm } from 'react-hook-form';
|
||||||
import { useParams, useSearchParams } from 'react-router-dom';
|
import { useParams, useSearchParams } from 'react-router-dom';
|
||||||
|
import { H2Title } from 'twenty-ui/display';
|
||||||
|
import { Section } from 'twenty-ui/layout';
|
||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
import { FieldMetadataType } from '~/generated-metadata/graphql';
|
import { FieldMetadataType } from '~/generated-metadata/graphql';
|
||||||
import { useNavigateApp } from '~/hooks/useNavigateApp';
|
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 { computeMetadataNameFromLabel } from '~/pages/settings/data-model/utils/compute-metadata-name-from-label.utils';
|
||||||
import { isUndefinedOrNull } from '~/utils/isUndefinedOrNull';
|
import { isUndefinedOrNull } from '~/utils/isUndefinedOrNull';
|
||||||
import { getSettingsPath } from '~/utils/navigation/getSettingsPath';
|
import { getSettingsPath } from '~/utils/navigation/getSettingsPath';
|
||||||
import { H2Title } from 'twenty-ui/display';
|
|
||||||
import { Section } from 'twenty-ui/layout';
|
|
||||||
|
|
||||||
type SettingsDataModelNewFieldFormValues = z.infer<
|
type SettingsDataModelNewFieldFormValues = z.infer<
|
||||||
ReturnType<typeof settingsFieldFormSchema>
|
ReturnType<typeof settingsFieldFormSchema>
|
||||||
@ -200,87 +199,85 @@ export const SettingsObjectNewFieldConfigure = () => {
|
|||||||
if (!activeObjectMetadataItem) return null;
|
if (!activeObjectMetadataItem) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<RecordFieldValueSelectorContextProvider>
|
<FormProvider // eslint-disable-next-line react/jsx-props-no-spreading
|
||||||
<FormProvider // eslint-disable-next-line react/jsx-props-no-spreading
|
{...formConfig}
|
||||||
{...formConfig}
|
>
|
||||||
>
|
<SubMenuTopBarContainer
|
||||||
<SubMenuTopBarContainer
|
title={t`2. Configure field`}
|
||||||
title={t`2. Configure field`}
|
links={[
|
||||||
links={[
|
{
|
||||||
{
|
children: t`Workspace`,
|
||||||
children: t`Workspace`,
|
href: getSettingsPath(SettingsPath.Workspace),
|
||||||
href: getSettingsPath(SettingsPath.Workspace),
|
},
|
||||||
},
|
{
|
||||||
{
|
children: t`Objects`,
|
||||||
children: t`Objects`,
|
href: getSettingsPath(SettingsPath.Objects),
|
||||||
href: getSettingsPath(SettingsPath.Objects),
|
},
|
||||||
},
|
{
|
||||||
{
|
children: activeObjectMetadataItem.labelPlural,
|
||||||
children: activeObjectMetadataItem.labelPlural,
|
href: getSettingsPath(SettingsPath.ObjectDetail, {
|
||||||
href: getSettingsPath(SettingsPath.ObjectDetail, {
|
objectNamePlural,
|
||||||
objectNamePlural,
|
}),
|
||||||
}),
|
},
|
||||||
},
|
|
||||||
|
|
||||||
{ children: <SettingsDataModelNewFieldBreadcrumbDropDown /> },
|
{ children: <SettingsDataModelNewFieldBreadcrumbDropDown /> },
|
||||||
]}
|
]}
|
||||||
actionButton={
|
actionButton={
|
||||||
<SaveAndCancelButtons
|
<SaveAndCancelButtons
|
||||||
isSaveDisabled={!canSave}
|
isSaveDisabled={!canSave}
|
||||||
isCancelDisabled={isSubmitting}
|
isCancelDisabled={isSubmitting}
|
||||||
onCancel={() =>
|
onCancel={() =>
|
||||||
navigate(
|
navigate(
|
||||||
SettingsPath.ObjectNewFieldSelect,
|
SettingsPath.ObjectNewFieldSelect,
|
||||||
{
|
{
|
||||||
objectNamePlural,
|
objectNamePlural,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
fieldType,
|
fieldType,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
onSave={formConfig.handleSubmit(handleSave)}
|
onSave={formConfig.handleSubmit(handleSave)}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<SettingsPageContainer>
|
||||||
|
<Section>
|
||||||
|
<H2Title
|
||||||
|
title={t`Icon and Name`}
|
||||||
|
description={t`The name and icon of this field`}
|
||||||
/>
|
/>
|
||||||
}
|
<SettingsDataModelFieldIconLabelForm
|
||||||
>
|
maxLength={FIELD_NAME_MAXIMUM_LENGTH}
|
||||||
<SettingsPageContainer>
|
canToggleSyncLabelWithName={
|
||||||
<Section>
|
fieldType !== FieldMetadataType.RELATION
|
||||||
<H2Title
|
}
|
||||||
title={t`Icon and Name`}
|
/>
|
||||||
description={t`The name and icon of this field`}
|
</Section>
|
||||||
/>
|
<Section>
|
||||||
<SettingsDataModelFieldIconLabelForm
|
<H2Title
|
||||||
maxLength={FIELD_NAME_MAXIMUM_LENGTH}
|
title={t`Values`}
|
||||||
canToggleSyncLabelWithName={
|
description={t`The values of this field`}
|
||||||
fieldType !== FieldMetadataType.RELATION
|
/>
|
||||||
}
|
<SettingsDataModelFieldSettingsFormCard
|
||||||
/>
|
fieldMetadataItem={{
|
||||||
</Section>
|
icon: formConfig.watch('icon'),
|
||||||
<Section>
|
label: formConfig.watch('label') || 'New Field',
|
||||||
<H2Title
|
settings: formConfig.watch('settings') || null,
|
||||||
title={t`Values`}
|
type: fieldType as FieldMetadataType,
|
||||||
description={t`The values of this field`}
|
}}
|
||||||
/>
|
objectMetadataItem={activeObjectMetadataItem}
|
||||||
<SettingsDataModelFieldSettingsFormCard
|
/>
|
||||||
fieldMetadataItem={{
|
</Section>
|
||||||
icon: formConfig.watch('icon'),
|
<Section>
|
||||||
label: formConfig.watch('label') || 'New Field',
|
<H2Title
|
||||||
settings: formConfig.watch('settings') || null,
|
title={t`Description`}
|
||||||
type: fieldType as FieldMetadataType,
|
description={t`The description of this field`}
|
||||||
}}
|
/>
|
||||||
objectMetadataItem={activeObjectMetadataItem}
|
<SettingsDataModelFieldDescriptionForm />
|
||||||
/>
|
</Section>
|
||||||
</Section>
|
</SettingsPageContainer>
|
||||||
<Section>
|
</SubMenuTopBarContainer>
|
||||||
<H2Title
|
</FormProvider>
|
||||||
title={t`Description`}
|
|
||||||
description={t`The description of this field`}
|
|
||||||
/>
|
|
||||||
<SettingsDataModelFieldDescriptionForm />
|
|
||||||
</Section>
|
|
||||||
</SettingsPageContainer>
|
|
||||||
</SubMenuTopBarContainer>
|
|
||||||
</FormProvider>
|
|
||||||
</RecordFieldValueSelectorContextProvider>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
import { useFilteredObjectMetadataItems } from '@/object-metadata/hooks/useFilteredObjectMetadataItems';
|
import { useFilteredObjectMetadataItems } from '@/object-metadata/hooks/useFilteredObjectMetadataItems';
|
||||||
import { RecordFieldValueSelectorContextProvider } from '@/object-record/record-store/contexts/RecordFieldValueSelectorContext';
|
|
||||||
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
|
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
|
||||||
import { SettingsDataModelNewFieldBreadcrumbDropDown } from '@/settings/data-model/components/SettingsDataModelNewFieldBreadcrumbDropDown';
|
import { SettingsDataModelNewFieldBreadcrumbDropDown } from '@/settings/data-model/components/SettingsDataModelNewFieldBreadcrumbDropDown';
|
||||||
import { SETTINGS_FIELD_TYPE_CONFIGS } from '@/settings/data-model/constants/SettingsFieldTypeConfigs';
|
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 { SettingsPath } from '@/types/SettingsPath';
|
||||||
import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer';
|
import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer';
|
||||||
import { zodResolver } from '@hookform/resolvers/zod';
|
import { zodResolver } from '@hookform/resolvers/zod';
|
||||||
|
import { t } from '@lingui/core/macro';
|
||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
import { FormProvider, useForm } from 'react-hook-form';
|
import { FormProvider, useForm } from 'react-hook-form';
|
||||||
import { useParams } from 'react-router-dom';
|
import { useParams } from 'react-router-dom';
|
||||||
|
import { isDefined } from 'twenty-shared/utils';
|
||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
import { FieldMetadataType } from '~/generated-metadata/graphql';
|
import { FieldMetadataType } from '~/generated-metadata/graphql';
|
||||||
import { useNavigateApp } from '~/hooks/useNavigateApp';
|
import { useNavigateApp } from '~/hooks/useNavigateApp';
|
||||||
import { getSettingsPath } from '~/utils/navigation/getSettingsPath';
|
import { getSettingsPath } from '~/utils/navigation/getSettingsPath';
|
||||||
import { t } from '@lingui/core/macro';
|
|
||||||
import { isDefined } from 'twenty-shared/utils';
|
|
||||||
|
|
||||||
export const settingsDataModelFieldTypeFormSchema = z.object({
|
export const settingsDataModelFieldTypeFormSchema = z.object({
|
||||||
type: z.enum(
|
type: z.enum(
|
||||||
@ -64,32 +63,30 @@ export const SettingsObjectNewFieldSelect = () => {
|
|||||||
if (!activeObjectMetadataItem) return null;
|
if (!activeObjectMetadataItem) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<RecordFieldValueSelectorContextProvider>
|
<FormProvider // eslint-disable-next-line react/jsx-props-no-spreading
|
||||||
<FormProvider // eslint-disable-next-line react/jsx-props-no-spreading
|
{...formMethods}
|
||||||
{...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
|
<SettingsPageContainer>
|
||||||
title={t`1. Select a field type`}
|
<SettingsObjectNewFieldSelector
|
||||||
links={[
|
objectNamePlural={objectNamePlural}
|
||||||
{ children: t`Workspace`, href: '/settings/workspace' },
|
excludedFieldTypes={excludedFieldTypes}
|
||||||
{ children: t`Objects`, href: '/settings/objects' },
|
/>
|
||||||
{
|
</SettingsPageContainer>
|
||||||
children: activeObjectMetadataItem.labelPlural,
|
</SubMenuTopBarContainer>
|
||||||
href: getSettingsPath(SettingsPath.ObjectDetail, {
|
</FormProvider>
|
||||||
objectNamePlural,
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
{ children: <SettingsDataModelNewFieldBreadcrumbDropDown /> },
|
|
||||||
]}
|
|
||||||
>
|
|
||||||
<SettingsPageContainer>
|
|
||||||
<SettingsObjectNewFieldSelector
|
|
||||||
objectNamePlural={objectNamePlural}
|
|
||||||
excludedFieldTypes={excludedFieldTypes}
|
|
||||||
/>
|
|
||||||
</SettingsPageContainer>
|
|
||||||
</SubMenuTopBarContainer>
|
|
||||||
</FormProvider>
|
|
||||||
</RecordFieldValueSelectorContextProvider>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -10,7 +10,6 @@ import { RecordFiltersComponentInstanceContext } from '@/object-record/record-fi
|
|||||||
import { RecordIndexContextProvider } from '@/object-record/record-index/contexts/RecordIndexContext';
|
import { RecordIndexContextProvider } from '@/object-record/record-index/contexts/RecordIndexContext';
|
||||||
import { useLoadRecordIndexStates } from '@/object-record/record-index/hooks/useLoadRecordIndexStates';
|
import { useLoadRecordIndexStates } from '@/object-record/record-index/hooks/useLoadRecordIndexStates';
|
||||||
import { RecordSortsComponentInstanceContext } from '@/object-record/record-sort/states/context/RecordSortsComponentInstanceContext';
|
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 { RecordTableBodyContextProvider } from '@/object-record/record-table/contexts/RecordTableBodyContext';
|
||||||
import { RecordTableContextProvider } from '@/object-record/record-table/contexts/RecordTableContext';
|
import { RecordTableContextProvider } from '@/object-record/record-table/contexts/RecordTableContext';
|
||||||
import { useRecordTable } from '@/object-record/record-table/hooks/useRecordTable';
|
import { useRecordTable } from '@/object-record/record-table/hooks/useRecordTable';
|
||||||
@ -126,41 +125,39 @@ export const RecordTableDecorator: Decorator = (Story, context) => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<RecordFieldValueSelectorContextProvider>
|
<RecordTableComponentInstanceContext.Provider
|
||||||
<RecordTableComponentInstanceContext.Provider
|
value={{ instanceId: recordIndexId, onColumnsChange: () => {} }}
|
||||||
value={{ instanceId: recordIndexId, onColumnsChange: () => {} }}
|
>
|
||||||
|
<ViewComponentInstanceContext.Provider
|
||||||
|
value={{ instanceId: recordIndexId }}
|
||||||
>
|
>
|
||||||
<ViewComponentInstanceContext.Provider
|
<RecordFilterGroupsComponentInstanceContext.Provider
|
||||||
value={{ instanceId: recordIndexId }}
|
value={{ instanceId: recordIndexId }}
|
||||||
>
|
>
|
||||||
<RecordFilterGroupsComponentInstanceContext.Provider
|
<RecordFiltersComponentInstanceContext.Provider
|
||||||
value={{ instanceId: recordIndexId }}
|
value={{ instanceId: recordIndexId }}
|
||||||
>
|
>
|
||||||
<RecordFiltersComponentInstanceContext.Provider
|
<RecordSortsComponentInstanceContext.Provider
|
||||||
value={{ instanceId: recordIndexId }}
|
value={{ instanceId: recordIndexId }}
|
||||||
>
|
>
|
||||||
<RecordSortsComponentInstanceContext.Provider
|
<ActionMenuComponentInstanceContext.Provider
|
||||||
value={{ instanceId: recordIndexId }}
|
value={{
|
||||||
|
instanceId: getActionMenuIdFromRecordIndexId(recordIndexId),
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<ActionMenuComponentInstanceContext.Provider
|
<InternalTableStateLoaderEffect
|
||||||
value={{
|
objectMetadataItem={objectMetadataItem}
|
||||||
instanceId: getActionMenuIdFromRecordIndexId(recordIndexId),
|
/>
|
||||||
}}
|
<InternalTableContextProviders
|
||||||
|
objectMetadataItem={objectMetadataItem}
|
||||||
>
|
>
|
||||||
<InternalTableStateLoaderEffect
|
<Story />
|
||||||
objectMetadataItem={objectMetadataItem}
|
</InternalTableContextProviders>
|
||||||
/>
|
</ActionMenuComponentInstanceContext.Provider>
|
||||||
<InternalTableContextProviders
|
</RecordSortsComponentInstanceContext.Provider>
|
||||||
objectMetadataItem={objectMetadataItem}
|
</RecordFiltersComponentInstanceContext.Provider>
|
||||||
>
|
</RecordFilterGroupsComponentInstanceContext.Provider>
|
||||||
<Story />
|
</ViewComponentInstanceContext.Provider>
|
||||||
</InternalTableContextProviders>
|
</RecordTableComponentInstanceContext.Provider>
|
||||||
</ActionMenuComponentInstanceContext.Provider>
|
|
||||||
</RecordSortsComponentInstanceContext.Provider>
|
|
||||||
</RecordFiltersComponentInstanceContext.Provider>
|
|
||||||
</RecordFilterGroupsComponentInstanceContext.Provider>
|
|
||||||
</ViewComponentInstanceContext.Provider>
|
|
||||||
</RecordTableComponentInstanceContext.Provider>
|
|
||||||
</RecordFieldValueSelectorContextProvider>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -6,10 +6,6 @@ import { formatFieldMetadataItemAsColumnDefinition } from '@/object-metadata/uti
|
|||||||
import { isLabelIdentifierField } from '@/object-metadata/utils/isLabelIdentifierField';
|
import { isLabelIdentifierField } from '@/object-metadata/utils/isLabelIdentifierField';
|
||||||
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
|
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
|
||||||
import { RecordFieldComponentInstanceContext } from '@/object-record/record-field/states/contexts/RecordFieldComponentInstanceContext';
|
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 { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
|
||||||
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
|
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
|
||||||
import { isDefined } from 'twenty-shared/utils';
|
import { isDefined } from 'twenty-shared/utils';
|
||||||
@ -27,15 +23,12 @@ const RecordMockSetterEffect = ({
|
|||||||
people: ObjectRecord[];
|
people: ObjectRecord[];
|
||||||
tasks: ObjectRecord[];
|
tasks: ObjectRecord[];
|
||||||
}) => {
|
}) => {
|
||||||
const setRecordValue = useSetRecordValue();
|
|
||||||
|
|
||||||
const setRecordInStores = useRecoilCallback(
|
const setRecordInStores = useRecoilCallback(
|
||||||
({ set }) =>
|
({ set }) =>
|
||||||
(record: ObjectRecord) => {
|
(record: ObjectRecord) => {
|
||||||
set(recordStoreFamilyState(record.id), record);
|
set(recordStoreFamilyState(record.id), record);
|
||||||
setRecordValue(record.id, record);
|
|
||||||
},
|
},
|
||||||
[setRecordValue],
|
[],
|
||||||
);
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -130,27 +123,25 @@ export const getFieldDecorator =
|
|||||||
instanceId: 'record-field-component-instance-id',
|
instanceId: 'record-field-component-instance-id',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<RecordFieldValueSelectorContextProvider>
|
<FieldContext.Provider
|
||||||
<FieldContext.Provider
|
value={{
|
||||||
value={{
|
recordId: record.id,
|
||||||
recordId: record.id,
|
isLabelIdentifier,
|
||||||
isLabelIdentifier,
|
fieldDefinition: formatFieldMetadataItemAsColumnDefinition({
|
||||||
fieldDefinition: formatFieldMetadataItemAsColumnDefinition({
|
field: fieldMetadataItem,
|
||||||
field: fieldMetadataItem,
|
position: 0,
|
||||||
position: 0,
|
objectMetadataItem,
|
||||||
objectMetadataItem,
|
}),
|
||||||
}),
|
isReadOnly: false,
|
||||||
isReadOnly: false,
|
}}
|
||||||
}}
|
>
|
||||||
>
|
<RecordMockSetterEffect
|
||||||
<RecordMockSetterEffect
|
companies={companies}
|
||||||
companies={companies}
|
people={people}
|
||||||
people={people}
|
tasks={tasks}
|
||||||
tasks={tasks}
|
/>
|
||||||
/>
|
<Story />
|
||||||
<Story />
|
</FieldContext.Provider>
|
||||||
</FieldContext.Provider>
|
|
||||||
</RecordFieldValueSelectorContextProvider>
|
|
||||||
</RecordFieldComponentInstanceContext.Provider>
|
</RecordFieldComponentInstanceContext.Provider>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
11
yarn.lock
11
yarn.lock
@ -55579,7 +55579,6 @@ __metadata:
|
|||||||
tsx: "npm:^4.17.0"
|
tsx: "npm:^4.17.0"
|
||||||
type-fest: "npm:4.10.1"
|
type-fest: "npm:4.10.1"
|
||||||
typescript: "npm:5.3.3"
|
typescript: "npm:5.3.3"
|
||||||
use-context-selector: "npm:^2.0.0"
|
|
||||||
use-debounce: "npm:^10.0.0"
|
use-debounce: "npm:^10.0.0"
|
||||||
uuid: "npm:^9.0.0"
|
uuid: "npm:^9.0.0"
|
||||||
vite: "npm:^5.4.0"
|
vite: "npm:^5.4.0"
|
||||||
@ -56763,16 +56762,6 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
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":
|
"use-debounce@npm:^10.0.0":
|
||||||
version: 10.0.2
|
version: 10.0.2
|
||||||
resolution: "use-debounce@npm:10.0.2"
|
resolution: "use-debounce@npm:10.0.2"
|
||||||
|
|||||||
Reference in New Issue
Block a user