diff --git a/packages/twenty-front/src/modules/activities/inline-cell/components/ActivityTargetInlineCellEditMode.tsx b/packages/twenty-front/src/modules/activities/inline-cell/components/ActivityTargetInlineCellEditMode.tsx
index 5b9d62b6cd7a..7719f4576bed 100644
--- a/packages/twenty-front/src/modules/activities/inline-cell/components/ActivityTargetInlineCellEditMode.tsx
+++ b/packages/twenty-front/src/modules/activities/inline-cell/components/ActivityTargetInlineCellEditMode.tsx
@@ -27,6 +27,7 @@ import {
import { useInlineCell } from '@/object-record/record-inline-cell/hooks/useInlineCell';
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
import { ActivityTargetInlineCellEditModeMultiRecordsEffect } from '@/object-record/relation-picker/components/ActivityTargetInlineCellEditModeMultiRecordsEffect';
+import { ActivityTargetInlineCellEditModeMultiRecordsSearchFilterEffect } from '@/object-record/relation-picker/components/ActivityTargetInlineCellEditModeMultiRecordsSearchFilterEffect';
import { MultiRecordSelect } from '@/object-record/relation-picker/components/MultiRecordSelect';
import { RelationPickerScope } from '@/object-record/relation-picker/scopes/RelationPickerScope';
import { prefillRecord } from '@/object-record/utils/prefillRecord';
@@ -287,6 +288,7 @@ export const ActivityTargetInlineCellEditMode = ({
+
diff --git a/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/RelationFromManyFieldInputMultiRecordsEffect.tsx b/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/RelationFromManyFieldInputMultiRecordsEffect.tsx
index 6f42a7fbad2e..866edfdada99 100644
--- a/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/RelationFromManyFieldInputMultiRecordsEffect.tsx
+++ b/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/RelationFromManyFieldInputMultiRecordsEffect.tsx
@@ -5,10 +5,10 @@ import { useObjectRecordMultiSelectScopedStates } from '@/activities/hooks/useOb
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
import { useRelationField } from '@/object-record/record-field/meta-types/hooks/useRelationField';
import { objectRecordMultiSelectComponentFamilyState } from '@/object-record/record-field/states/objectRecordMultiSelectComponentFamilyState';
-import { ObjectRecordForSelect } from '@/object-record/relation-picker/hooks/useMultiObjectSearch';
import { useRelationPickerEntitiesOptions } from '@/object-record/relation-picker/hooks/useRelationPickerEntitiesOptions';
import { RelationPickerScopeInternalContext } from '@/object-record/relation-picker/scopes/scope-internal-context/RelationPickerScopeInternalContext';
import { EntityForSelect } from '@/object-record/relation-picker/types/EntityForSelect';
+import { ObjectRecordForSelect } from '@/object-record/types/ObjectRecordForSelect';
import { useAvailableScopeIdOrThrow } from '@/ui/utilities/recoil-scope/scopes-internal/hooks/useAvailableScopeId';
import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
diff --git a/packages/twenty-front/src/modules/object-record/record-field/states/objectRecordMultiSelectComponentFamilyState.ts b/packages/twenty-front/src/modules/object-record/record-field/states/objectRecordMultiSelectComponentFamilyState.ts
index 0e15c962e11b..e4150ae029c6 100644
--- a/packages/twenty-front/src/modules/object-record/record-field/states/objectRecordMultiSelectComponentFamilyState.ts
+++ b/packages/twenty-front/src/modules/object-record/record-field/states/objectRecordMultiSelectComponentFamilyState.ts
@@ -1,4 +1,4 @@
-import { ObjectRecordForSelect } from '@/object-record/relation-picker/hooks/useMultiObjectSearch';
+import { ObjectRecordForSelect } from '@/object-record/types/ObjectRecordForSelect';
import { createComponentFamilyState } from '@/ui/utilities/state/component-state/utils/createComponentFamilyState';
export type ObjectRecordAndSelected = ObjectRecordForSelect & {
diff --git a/packages/twenty-front/src/modules/object-record/record-field/states/objectRecordMultiSelectMatchesFilterRecordsIdsComponentState.ts b/packages/twenty-front/src/modules/object-record/record-field/states/objectRecordMultiSelectMatchesFilterRecordsIdsComponentState.ts
new file mode 100644
index 000000000000..bfaebeaa86fa
--- /dev/null
+++ b/packages/twenty-front/src/modules/object-record/record-field/states/objectRecordMultiSelectMatchesFilterRecordsIdsComponentState.ts
@@ -0,0 +1,8 @@
+import { ObjectRecordForSelect } from '@/object-record/types/ObjectRecordForSelect';
+import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState';
+
+export const objectRecordMultiSelectMatchesFilterRecordsIdsComponentState =
+ createComponentState({
+ key: 'objectRecordMultiSelectMatchesFilterRecordsIdsComponentState',
+ defaultValue: [],
+ });
diff --git a/packages/twenty-front/src/modules/object-record/relation-picker/components/ActivityTargetInlineCellEditModeMultiRecordsEffect.tsx b/packages/twenty-front/src/modules/object-record/relation-picker/components/ActivityTargetInlineCellEditModeMultiRecordsEffect.tsx
index 425877c20e15..26981f3c0396 100644
--- a/packages/twenty-front/src/modules/object-record/relation-picker/components/ActivityTargetInlineCellEditModeMultiRecordsEffect.tsx
+++ b/packages/twenty-front/src/modules/object-record/relation-picker/components/ActivityTargetInlineCellEditModeMultiRecordsEffect.tsx
@@ -7,15 +7,11 @@ import {
} from 'recoil';
import { useObjectRecordMultiSelectScopedStates } from '@/activities/hooks/useObjectRecordMultiSelectScopedStates';
-import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
import { objectRecordMultiSelectComponentFamilyState } from '@/object-record/record-field/states/objectRecordMultiSelectComponentFamilyState';
-import { useRelationPickerScopedStates } from '@/object-record/relation-picker/hooks/internal/useRelationPickerScopedStates';
-import {
- ObjectRecordForSelect,
- SelectedObjectRecordId,
- useMultiObjectSearch,
-} from '@/object-record/relation-picker/hooks/useMultiObjectSearch';
+import { objectRecordMultiSelectMatchesFilterRecordsIdsComponentState } from '@/object-record/record-field/states/objectRecordMultiSelectMatchesFilterRecordsIdsComponentState';
import { RelationPickerScopeInternalContext } from '@/object-record/relation-picker/scopes/scope-internal-context/RelationPickerScopeInternalContext';
+import { ObjectRecordForSelect } from '@/object-record/types/ObjectRecordForSelect';
+import { SelectedObjectRecordId } from '@/object-record/types/SelectedObjectRecordId';
import { useAvailableScopeIdOrThrow } from '@/ui/utilities/recoil-scope/scopes-internal/hooks/useAvailableScopeId';
import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
@@ -30,43 +26,14 @@ export const ActivityTargetInlineCellEditModeMultiRecordsEffect = ({
const {
objectRecordsIdsMultiSelectState,
objectRecordMultiSelectCheckedRecordsIdsState,
- recordMultiSelectIsLoadingState,
} = useObjectRecordMultiSelectScopedStates(scopeId);
const [objectRecordsIdsMultiSelect, setObjectRecordsIdsMultiSelect] =
useRecoilState(objectRecordsIdsMultiSelectState);
- const setRecordMultiSelectIsLoading = useSetRecoilState(
- recordMultiSelectIsLoadingState,
- );
-
- const relationPickerScopedId = useAvailableScopeIdOrThrow(
- RelationPickerScopeInternalContext,
- );
-
- const { relationPickerSearchFilterState } = useRelationPickerScopedStates({
- relationPickerScopedId,
- });
- const relationPickerSearchFilter = useRecoilValue(
- relationPickerSearchFilterState,
+ const setObjectRecordMultiSelectCheckedRecordsIds = useSetRecoilState(
+ objectRecordMultiSelectCheckedRecordsIdsState,
);
- const { filteredSelectedObjectRecords, loading, objectRecordsToSelect } =
- useMultiObjectSearch({
- searchFilterValue: relationPickerSearchFilter,
- excludedObjects: [
- CoreObjectNameSingular.Task,
- CoreObjectNameSingular.Note,
- ],
- selectedObjectRecordIds,
- excludedObjectRecordIds: [],
- limit: 10,
- });
-
- const [
- objectRecordMultiSelectCheckedRecordsIds,
- setObjectRecordMultiSelectCheckedRecordsIds,
- ] = useRecoilState(objectRecordMultiSelectCheckedRecordsIdsState);
-
const updateRecords = useRecoilCallback(
({ snapshot, set }) =>
(newRecords: ObjectRecordForSelect[]) => {
@@ -80,6 +47,10 @@ export const ActivityTargetInlineCellEditModeMultiRecordsEffect = ({
)
.getValue();
+ const objectRecordMultiSelectCheckedRecordsIds = snapshot
+ .getLoadable(objectRecordMultiSelectCheckedRecordsIdsState)
+ .getValue();
+
const newRecordWithSelected = {
...newRecord,
selected: objectRecordMultiSelectCheckedRecordsIds.some(
@@ -103,23 +74,25 @@ export const ActivityTargetInlineCellEditModeMultiRecordsEffect = ({
}
}
},
- [objectRecordMultiSelectCheckedRecordsIds, scopeId],
+ [objectRecordMultiSelectCheckedRecordsIdsState, scopeId],
+ );
+
+ const matchesSearchFilterObjectRecords = useRecoilValue(
+ objectRecordMultiSelectMatchesFilterRecordsIdsComponentState({
+ scopeId,
+ }),
);
useEffect(() => {
- const allRecords = [
- ...(filteredSelectedObjectRecords ?? []),
- ...(objectRecordsToSelect ?? []),
- ];
+ const allRecords = matchesSearchFilterObjectRecords ?? [];
updateRecords(allRecords);
const allRecordsIds = allRecords.map((record) => record.record.id);
if (!isDeeplyEqual(allRecordsIds, objectRecordsIdsMultiSelect)) {
setObjectRecordsIdsMultiSelect(allRecordsIds);
}
}, [
- filteredSelectedObjectRecords,
+ matchesSearchFilterObjectRecords,
objectRecordsIdsMultiSelect,
- objectRecordsToSelect,
setObjectRecordsIdsMultiSelect,
updateRecords,
]);
@@ -130,9 +103,5 @@ export const ActivityTargetInlineCellEditModeMultiRecordsEffect = ({
);
}, [selectedObjectRecordIds, setObjectRecordMultiSelectCheckedRecordsIds]);
- useEffect(() => {
- setRecordMultiSelectIsLoading(loading);
- }, [loading, setRecordMultiSelectIsLoading]);
-
return <>>;
};
diff --git a/packages/twenty-front/src/modules/object-record/relation-picker/components/ActivityTargetInlineCellEditModeMultiRecordsSearchFilterEffect.tsx b/packages/twenty-front/src/modules/object-record/relation-picker/components/ActivityTargetInlineCellEditModeMultiRecordsSearchFilterEffect.tsx
new file mode 100644
index 000000000000..c216122c148c
--- /dev/null
+++ b/packages/twenty-front/src/modules/object-record/relation-picker/components/ActivityTargetInlineCellEditModeMultiRecordsSearchFilterEffect.tsx
@@ -0,0 +1,54 @@
+import { useEffect } from 'react';
+import { useRecoilValue, useSetRecoilState } from 'recoil';
+
+import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
+import { objectRecordMultiSelectMatchesFilterRecordsIdsComponentState } from '@/object-record/record-field/states/objectRecordMultiSelectMatchesFilterRecordsIdsComponentState';
+import { useRelationPickerScopedStates } from '@/object-record/relation-picker/hooks/internal/useRelationPickerScopedStates';
+import { useMultiObjectSearchMatchesSearchFilterQuery } from '@/object-record/relation-picker/hooks/useMultiObjectSearchMatchesSearchFilterQuery';
+import { RelationPickerScopeInternalContext } from '@/object-record/relation-picker/scopes/scope-internal-context/RelationPickerScopeInternalContext';
+import { useAvailableScopeIdOrThrow } from '@/ui/utilities/recoil-scope/scopes-internal/hooks/useAvailableScopeId';
+
+export const ActivityTargetInlineCellEditModeMultiRecordsSearchFilterEffect =
+ () => {
+ const scopeId = useAvailableScopeIdOrThrow(
+ RelationPickerScopeInternalContext,
+ );
+
+ const setRecordMultiSelectMatchesFilterRecords = useSetRecoilState(
+ objectRecordMultiSelectMatchesFilterRecordsIdsComponentState({
+ scopeId,
+ }),
+ );
+
+ const relationPickerScopedId = useAvailableScopeIdOrThrow(
+ RelationPickerScopeInternalContext,
+ );
+
+ const { relationPickerSearchFilterState } = useRelationPickerScopedStates({
+ relationPickerScopedId,
+ });
+ const relationPickerSearchFilter = useRecoilValue(
+ relationPickerSearchFilterState,
+ );
+
+ const { matchesSearchFilterObjectRecords } =
+ useMultiObjectSearchMatchesSearchFilterQuery({
+ excludedObjects: [
+ CoreObjectNameSingular.Task,
+ CoreObjectNameSingular.Note,
+ ],
+ searchFilterValue: relationPickerSearchFilter,
+ limit: 10,
+ });
+
+ useEffect(() => {
+ setRecordMultiSelectMatchesFilterRecords(
+ matchesSearchFilterObjectRecords,
+ );
+ }, [
+ setRecordMultiSelectMatchesFilterRecords,
+ matchesSearchFilterObjectRecords,
+ ]);
+
+ return <>>;
+ };
diff --git a/packages/twenty-front/src/modules/object-record/relation-picker/hooks/__tests__/useMultiObjectSearch.test.tsx b/packages/twenty-front/src/modules/object-record/relation-picker/hooks/__tests__/useMultiObjectSearch.test.tsx
deleted file mode 100644
index 0f27bd796e54..000000000000
--- a/packages/twenty-front/src/modules/object-record/relation-picker/hooks/__tests__/useMultiObjectSearch.test.tsx
+++ /dev/null
@@ -1,141 +0,0 @@
-import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
-import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
-import {
- MultiObjectSearch,
- ObjectRecordForSelect,
- SelectedObjectRecordId,
- useMultiObjectSearch,
-} from '@/object-record/relation-picker/hooks/useMultiObjectSearch';
-import { useMultiObjectSearchMatchesSearchFilterAndSelectedItemsQuery } from '@/object-record/relation-picker/hooks/useMultiObjectSearchMatchesSearchFilterAndSelectedItemsQuery';
-import { useMultiObjectSearchMatchesSearchFilterAndToSelectQuery } from '@/object-record/relation-picker/hooks/useMultiObjectSearchMatchesSearchFilterAndToSelectQuery';
-import { useMultiObjectSearchSelectedItemsQuery } from '@/object-record/relation-picker/hooks/useMultiObjectSearchSelectedItemsQuery';
-import { renderHook } from '@testing-library/react';
-import { FieldMetadataType } from '~/generated/graphql';
-
-jest.mock(
- '@/object-record/relation-picker/hooks/useMultiObjectSearchSelectedItemsQuery',
-);
-jest.mock(
- '@/object-record/relation-picker/hooks/useMultiObjectSearchMatchesSearchFilterAndSelectedItemsQuery',
-);
-jest.mock(
- '@/object-record/relation-picker/hooks/useMultiObjectSearchMatchesSearchFilterAndToSelectQuery',
-);
-
-const objectData: ObjectMetadataItem[] = [
- {
- createdAt: 'createdAt',
- id: 'id',
- isActive: true,
- isCustom: true,
- isSystem: false,
- isRemote: false,
- labelPlural: 'labelPlural',
- labelSingular: 'labelSingular',
- namePlural: 'namePlural',
- nameSingular: 'nameSingular',
- isLabelSyncedWithName: false,
- updatedAt: 'updatedAt',
- fields: [
- {
- id: 'f6a0a73a-5ee6-442e-b764-39b682471240',
- name: 'id',
- label: 'id',
- type: FieldMetadataType.Uuid,
- createdAt: '2024-01-01T00:00:00.000Z',
- updatedAt: '2024-01-01T00:00:00.000Z',
- isActive: true,
- },
- ],
- indexMetadatas: [],
- },
-];
-
-describe('useMultiObjectSearch', () => {
- const selectedObjectRecordIds: SelectedObjectRecordId[] = [
- { objectNameSingular: 'object1', id: '1' },
- { objectNameSingular: 'object2', id: '2' },
- ];
- const searchFilterValue = 'searchValue';
- const limit = 5;
- const excludedObjectRecordIds: SelectedObjectRecordId[] = [
- { objectNameSingular: 'object3', id: '3' },
- { objectNameSingular: 'object4', id: '4' },
- ];
- const excludedObjects: CoreObjectNameSingular[] = [];
-
- const selectedObjectRecords: ObjectRecordForSelect[] = [
- {
- objectMetadataItem: objectData[0],
- record: {
- __typename: 'ObjectRecord',
- id: '1',
- createdAt: 'createdAt',
- updatedAt: 'updatedAt',
- },
- recordIdentifier: {
- id: '1',
- name: 'name',
- },
- },
- ];
- const selectedObjectRecordsLoading = false;
-
- const selectedAndMatchesSearchFilterObjectRecords: ObjectRecordForSelect[] =
- [];
- const selectedAndMatchesSearchFilterObjectRecordsLoading = false;
-
- const toSelectAndMatchesSearchFilterObjectRecords: ObjectRecordForSelect[] =
- [];
- const toSelectAndMatchesSearchFilterObjectRecordsLoading = false;
-
- beforeEach(() => {
- (useMultiObjectSearchSelectedItemsQuery as jest.Mock).mockReturnValue({
- selectedObjectRecords,
- selectedObjectRecordsLoading,
- });
-
- (
- useMultiObjectSearchMatchesSearchFilterAndSelectedItemsQuery as jest.Mock
- ).mockReturnValue({
- selectedAndMatchesSearchFilterObjectRecords,
- selectedAndMatchesSearchFilterObjectRecordsLoading,
- });
-
- (
- useMultiObjectSearchMatchesSearchFilterAndToSelectQuery as jest.Mock
- ).mockReturnValue({
- toSelectAndMatchesSearchFilterObjectRecords,
- toSelectAndMatchesSearchFilterObjectRecordsLoading,
- });
- });
-
- afterEach(() => {
- jest.resetAllMocks();
- });
-
- it('should return the correct object records and loading state', () => {
- const { result } = renderHook(() =>
- useMultiObjectSearch({
- searchFilterValue,
- selectedObjectRecordIds,
- limit,
- excludedObjectRecordIds,
- excludedObjects,
- }),
- );
-
- const expected: MultiObjectSearch = {
- selectedObjectRecords,
- filteredSelectedObjectRecords:
- selectedAndMatchesSearchFilterObjectRecords,
- objectRecordsToSelect: toSelectAndMatchesSearchFilterObjectRecords,
- loading:
- selectedAndMatchesSearchFilterObjectRecordsLoading ||
- toSelectAndMatchesSearchFilterObjectRecordsLoading ||
- selectedObjectRecordsLoading,
- };
-
- expect(result.current).toEqual(expected);
- });
-});
diff --git a/packages/twenty-front/src/modules/object-record/relation-picker/hooks/useMultiObjectRecordsQueryResultFormattedAsObjectRecordForSelectArray.ts b/packages/twenty-front/src/modules/object-record/relation-picker/hooks/useMultiObjectRecordsQueryResultFormattedAsObjectRecordForSelectArray.ts
index a1047478a7ba..ebac778c44f9 100644
--- a/packages/twenty-front/src/modules/object-record/relation-picker/hooks/useMultiObjectRecordsQueryResultFormattedAsObjectRecordForSelectArray.ts
+++ b/packages/twenty-front/src/modules/object-record/relation-picker/hooks/useMultiObjectRecordsQueryResultFormattedAsObjectRecordForSelectArray.ts
@@ -4,7 +4,8 @@ import { useRecoilValue } from 'recoil';
import { objectMetadataItemsByNamePluralMapSelector } from '@/object-metadata/states/objectMetadataItemsByNamePluralMapSelector';
import { getObjectRecordIdentifier } from '@/object-metadata/utils/getObjectRecordIdentifier';
import { RecordGqlConnection } from '@/object-record/graphql/types/RecordGqlConnection';
-import { ObjectRecordForSelect } from '@/object-record/relation-picker/hooks/useMultiObjectSearch';
+import { formatMultiObjectRecordSearchResults } from '@/object-record/relation-picker/utils/formatMultiObjectRecordSearchResults';
+import { ObjectRecordForSelect } from '@/object-record/types/ObjectRecordForSelect';
import { isDefined } from '~/utils/isDefined';
export type MultiObjectRecordQueryResult = {
@@ -24,25 +25,34 @@ export const useMultiObjectRecordsQueryResultFormattedAsObjectRecordForSelectArr
objectMetadataItemsByNamePluralMapSelector,
);
+ const formattedMultiObjectRecordsQueryResult = useMemo(() => {
+ return formatMultiObjectRecordSearchResults(
+ multiObjectRecordsQueryResult,
+ );
+ }, [multiObjectRecordsQueryResult]);
+
const objectRecordForSelectArray = useMemo(() => {
- return Object.entries(multiObjectRecordsQueryResult ?? {}).flatMap(
- ([namePlural, objectRecordConnection]) => {
- const objectMetadataItem =
- objectMetadataItemsByNamePluralMap.get(namePlural);
+ return Object.entries(
+ formattedMultiObjectRecordsQueryResult ?? {},
+ ).flatMap(([namePlural, objectRecordConnection]) => {
+ const objectMetadataItem =
+ objectMetadataItemsByNamePluralMap.get(namePlural);
- if (!isDefined(objectMetadataItem)) return [];
+ if (!isDefined(objectMetadataItem)) return [];
- return objectRecordConnection.edges.map(({ node }) => ({
+ return objectRecordConnection.edges.map(({ node }) => ({
+ objectMetadataItem,
+ record: node,
+ recordIdentifier: getObjectRecordIdentifier({
objectMetadataItem,
record: node,
- recordIdentifier: getObjectRecordIdentifier({
- objectMetadataItem,
- record: node,
- }),
- })) as ObjectRecordForSelect[];
- },
- );
- }, [multiObjectRecordsQueryResult, objectMetadataItemsByNamePluralMap]);
+ }),
+ })) as ObjectRecordForSelect[];
+ });
+ }, [
+ formattedMultiObjectRecordsQueryResult,
+ objectMetadataItemsByNamePluralMap,
+ ]);
return {
objectRecordForSelectArray,
diff --git a/packages/twenty-front/src/modules/object-record/relation-picker/hooks/useMultiObjectSearch.ts b/packages/twenty-front/src/modules/object-record/relation-picker/hooks/useMultiObjectSearch.ts
deleted file mode 100644
index 8651e7f428f8..000000000000
--- a/packages/twenty-front/src/modules/object-record/relation-picker/hooks/useMultiObjectSearch.ts
+++ /dev/null
@@ -1,76 +0,0 @@
-import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
-import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
-import { useMultiObjectSearchMatchesSearchFilterAndSelectedItemsQuery } from '@/object-record/relation-picker/hooks/useMultiObjectSearchMatchesSearchFilterAndSelectedItemsQuery';
-import { useMultiObjectSearchMatchesSearchFilterAndToSelectQuery } from '@/object-record/relation-picker/hooks/useMultiObjectSearchMatchesSearchFilterAndToSelectQuery';
-import { useMultiObjectSearchSelectedItemsQuery } from '@/object-record/relation-picker/hooks/useMultiObjectSearchSelectedItemsQuery';
-import { ObjectRecord } from '@/object-record/types/ObjectRecord';
-import { ObjectRecordIdentifier } from '@/object-record/types/ObjectRecordIdentifier';
-
-export const MULTI_OBJECT_SEARCH_REQUEST_LIMIT = 5;
-
-export type ObjectRecordForSelect = {
- objectMetadataItem: ObjectMetadataItem;
- record: ObjectRecord;
- recordIdentifier: ObjectRecordIdentifier;
-};
-
-export type SelectedObjectRecordId = {
- objectNameSingular: string;
- id: string;
-};
-
-export type MultiObjectSearch = {
- selectedObjectRecords: ObjectRecordForSelect[];
- filteredSelectedObjectRecords: ObjectRecordForSelect[];
- objectRecordsToSelect: ObjectRecordForSelect[];
- loading: boolean;
-};
-
-export const useMultiObjectSearch = ({
- searchFilterValue,
- selectedObjectRecordIds,
- limit,
- excludedObjectRecordIds = [],
- excludedObjects,
-}: {
- searchFilterValue: string;
- selectedObjectRecordIds: SelectedObjectRecordId[];
- limit?: number;
- excludedObjectRecordIds?: SelectedObjectRecordId[];
- excludedObjects?: CoreObjectNameSingular[];
-}): MultiObjectSearch => {
- const { selectedObjectRecords, selectedObjectRecordsLoading } =
- useMultiObjectSearchSelectedItemsQuery({
- selectedObjectRecordIds,
- });
-
- const {
- selectedAndMatchesSearchFilterObjectRecords,
- selectedAndMatchesSearchFilterObjectRecordsLoading,
- } = useMultiObjectSearchMatchesSearchFilterAndSelectedItemsQuery({
- searchFilterValue,
- selectedObjectRecordIds,
- limit,
- });
-
- const {
- toSelectAndMatchesSearchFilterObjectRecords,
- toSelectAndMatchesSearchFilterObjectRecordsLoading,
- } = useMultiObjectSearchMatchesSearchFilterAndToSelectQuery({
- excludedObjects,
- excludedObjectRecordIds,
- searchFilterValue,
- selectedObjectRecordIds,
- limit,
- });
-
- return {
- selectedObjectRecords,
- filteredSelectedObjectRecords: selectedAndMatchesSearchFilterObjectRecords,
- objectRecordsToSelect: toSelectAndMatchesSearchFilterObjectRecords,
- loading:
- selectedAndMatchesSearchFilterObjectRecordsLoading ||
- toSelectAndMatchesSearchFilterObjectRecordsLoading ||
- selectedObjectRecordsLoading,
- };
-};
diff --git a/packages/twenty-front/src/modules/object-record/relation-picker/hooks/useMultiObjectSearchMatchesSearchFilterAndSelectedItemsQuery.ts b/packages/twenty-front/src/modules/object-record/relation-picker/hooks/useMultiObjectSearchMatchesSearchFilterAndSelectedItemsQuery.ts
deleted file mode 100644
index b69ef1f40c6d..000000000000
--- a/packages/twenty-front/src/modules/object-record/relation-picker/hooks/useMultiObjectSearchMatchesSearchFilterAndSelectedItemsQuery.ts
+++ /dev/null
@@ -1,120 +0,0 @@
-import { useQuery } from '@apollo/client';
-import { isNonEmptyArray } from '@sniptt/guards';
-import { useRecoilValue } from 'recoil';
-
-import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
-import { EMPTY_QUERY } from '@/object-record/constants/EmptyQuery';
-import { useGenerateCombinedSearchRecordsQuery } from '@/object-record/multiple-objects/hooks/useGenerateCombinedSearchRecordsQuery';
-import { useLimitPerMetadataItem } from '@/object-record/relation-picker/hooks/useLimitPerMetadataItem';
-import {
- MultiObjectRecordQueryResult,
- useMultiObjectRecordsQueryResultFormattedAsObjectRecordForSelectArray,
-} from '@/object-record/relation-picker/hooks/useMultiObjectRecordsQueryResultFormattedAsObjectRecordForSelectArray';
-import { SelectedObjectRecordId } from '@/object-record/relation-picker/hooks/useMultiObjectSearch';
-import { useMemo } from 'react';
-import { isDefined } from '~/utils/isDefined';
-import { capitalize } from '~/utils/string/capitalize';
-
-export const formatSearchResults = (
- searchResults: MultiObjectRecordQueryResult | undefined,
-): MultiObjectRecordQueryResult => {
- if (!searchResults) {
- return {};
- }
-
- return Object.entries(searchResults).reduce((acc, [key, value]) => {
- let newKey = key.replace(/^search/, '');
- newKey = newKey.charAt(0).toLowerCase() + newKey.slice(1);
- acc[newKey] = value;
- return acc;
- }, {} as MultiObjectRecordQueryResult);
-};
-
-export const useMultiObjectSearchMatchesSearchFilterAndSelectedItemsQuery = ({
- selectedObjectRecordIds,
- searchFilterValue,
- limit,
-}: {
- selectedObjectRecordIds: SelectedObjectRecordId[];
- searchFilterValue: string;
- limit?: number;
-}) => {
- const objectMetadataItems = useRecoilValue(objectMetadataItemsState);
-
- const objectMetadataItemsUsedInSelectedIdsQuery = useMemo(
- () =>
- objectMetadataItems.filter(({ nameSingular }) => {
- return selectedObjectRecordIds.some(({ objectNameSingular }) => {
- return objectNameSingular === nameSingular;
- });
- }),
- [objectMetadataItems, selectedObjectRecordIds],
- );
-
- const selectedAndMatchesSearchFilterTextFilterPerMetadataItem =
- Object.fromEntries(
- objectMetadataItems
- .map(({ nameSingular }) => {
- const selectedIds = selectedObjectRecordIds
- .filter(
- ({ objectNameSingular }) => objectNameSingular === nameSingular,
- )
- .map(({ id }) => id);
-
- if (!isNonEmptyArray(selectedIds)) return null;
-
- return [
- `filter${capitalize(nameSingular)}`,
- {
- id: {
- in: selectedIds,
- },
- },
- ];
- })
- .filter(isDefined),
- );
-
- const { limitPerMetadataItem } = useLimitPerMetadataItem({
- objectMetadataItems: objectMetadataItemsUsedInSelectedIdsQuery,
- limit,
- });
-
- const multiSelectSearchQueryForSelectedIds =
- useGenerateCombinedSearchRecordsQuery({
- operationSignatures: objectMetadataItemsUsedInSelectedIdsQuery.map(
- (objectMetadataItem) => ({
- objectNameSingular: objectMetadataItem.nameSingular,
- variables: {},
- }),
- ),
- });
-
- const {
- loading: selectedAndMatchesSearchFilterObjectRecordsLoading,
- data: selectedAndMatchesSearchFilterObjectRecordsQueryResult,
- } = useQuery(
- multiSelectSearchQueryForSelectedIds ?? EMPTY_QUERY,
- {
- variables: {
- search: searchFilterValue,
- ...selectedAndMatchesSearchFilterTextFilterPerMetadataItem,
- ...limitPerMetadataItem,
- },
- skip: !isDefined(multiSelectSearchQueryForSelectedIds),
- },
- );
-
- const {
- objectRecordForSelectArray: selectedAndMatchesSearchFilterObjectRecords,
- } = useMultiObjectRecordsQueryResultFormattedAsObjectRecordForSelectArray({
- multiObjectRecordsQueryResult: formatSearchResults(
- selectedAndMatchesSearchFilterObjectRecordsQueryResult,
- ),
- });
-
- return {
- selectedAndMatchesSearchFilterObjectRecordsLoading,
- selectedAndMatchesSearchFilterObjectRecords,
- };
-};
diff --git a/packages/twenty-front/src/modules/object-record/relation-picker/hooks/useMultiObjectSearchMatchesSearchFilterAndToSelectQuery.ts b/packages/twenty-front/src/modules/object-record/relation-picker/hooks/useMultiObjectSearchMatchesSearchFilterAndToSelectQuery.ts
deleted file mode 100644
index c3150cd44ca8..000000000000
--- a/packages/twenty-front/src/modules/object-record/relation-picker/hooks/useMultiObjectSearchMatchesSearchFilterAndToSelectQuery.ts
+++ /dev/null
@@ -1,110 +0,0 @@
-import { useQuery } from '@apollo/client';
-import { useRecoilValue } from 'recoil';
-
-import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
-import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
-import { EMPTY_QUERY } from '@/object-record/constants/EmptyQuery';
-import { useGenerateCombinedSearchRecordsQuery } from '@/object-record/multiple-objects/hooks/useGenerateCombinedSearchRecordsQuery';
-import { useLimitPerMetadataItem } from '@/object-record/relation-picker/hooks/useLimitPerMetadataItem';
-import {
- MultiObjectRecordQueryResult,
- useMultiObjectRecordsQueryResultFormattedAsObjectRecordForSelectArray,
-} from '@/object-record/relation-picker/hooks/useMultiObjectRecordsQueryResultFormattedAsObjectRecordForSelectArray';
-import { SelectedObjectRecordId } from '@/object-record/relation-picker/hooks/useMultiObjectSearch';
-import { formatSearchResults } from '@/object-record/relation-picker/hooks/useMultiObjectSearchMatchesSearchFilterAndSelectedItemsQuery';
-import { isObjectMetadataItemSearchableInCombinedRequest } from '@/object-record/utils/isObjectMetadataItemSearchableInCombinedRequest';
-import { makeAndFilterVariables } from '@/object-record/utils/makeAndFilterVariables';
-import { isDefined } from '~/utils/isDefined';
-import { capitalize } from '~/utils/string/capitalize';
-
-export const useMultiObjectSearchMatchesSearchFilterAndToSelectQuery = ({
- selectedObjectRecordIds,
- excludedObjectRecordIds,
- searchFilterValue,
- limit,
- excludedObjects,
-}: {
- selectedObjectRecordIds: SelectedObjectRecordId[];
- excludedObjectRecordIds: SelectedObjectRecordId[];
- searchFilterValue: string;
- limit?: number;
- excludedObjects?: CoreObjectNameSingular[];
-}) => {
- const objectMetadataItems = useRecoilValue(objectMetadataItemsState);
-
- const selectableObjectMetadataItems = objectMetadataItems
- .filter(({ isSystem, isRemote }) => !isSystem && !isRemote)
- .filter(({ nameSingular }) => {
- return !excludedObjects?.includes(nameSingular as CoreObjectNameSingular);
- })
- .filter((object) =>
- isObjectMetadataItemSearchableInCombinedRequest(object),
- );
-
- const objectRecordsToSelectAndMatchesSearchFilterTextFilterPerMetadataItem =
- Object.fromEntries(
- selectableObjectMetadataItems
- .map(({ nameSingular }) => {
- const selectedIds = selectedObjectRecordIds
- .filter(
- ({ objectNameSingular }) => objectNameSingular === nameSingular,
- )
- .map(({ id }) => id);
-
- const excludedIds = excludedObjectRecordIds
- .filter(
- ({ objectNameSingular }) => objectNameSingular === nameSingular,
- )
- .map(({ id }) => id);
-
- const excludedIdsUnion = [...selectedIds, ...excludedIds];
- const excludedIdsFilter = excludedIdsUnion.length
- ? { not: { id: { in: excludedIdsUnion } } }
- : undefined;
-
- return [
- `filter${capitalize(nameSingular)}`,
- makeAndFilterVariables([excludedIdsFilter]),
- ];
- })
- .filter(isDefined),
- );
- const { limitPerMetadataItem } = useLimitPerMetadataItem({
- objectMetadataItems: selectableObjectMetadataItems,
- limit,
- });
-
- const multiSelectQuery = useGenerateCombinedSearchRecordsQuery({
- operationSignatures: selectableObjectMetadataItems.map(
- (objectMetadataItem) => ({
- objectNameSingular: objectMetadataItem.nameSingular,
- variables: {},
- }),
- ),
- });
-
- const {
- loading: toSelectAndMatchesSearchFilterObjectRecordsLoading,
- data: toSelectAndMatchesSearchFilterObjectRecordsQueryResult,
- } = useQuery(multiSelectQuery ?? EMPTY_QUERY, {
- variables: {
- search: searchFilterValue,
- ...objectRecordsToSelectAndMatchesSearchFilterTextFilterPerMetadataItem,
- ...limitPerMetadataItem,
- },
- skip: !isDefined(multiSelectQuery),
- });
-
- const {
- objectRecordForSelectArray: toSelectAndMatchesSearchFilterObjectRecords,
- } = useMultiObjectRecordsQueryResultFormattedAsObjectRecordForSelectArray({
- multiObjectRecordsQueryResult: formatSearchResults(
- toSelectAndMatchesSearchFilterObjectRecordsQueryResult,
- ),
- });
-
- return {
- toSelectAndMatchesSearchFilterObjectRecordsLoading,
- toSelectAndMatchesSearchFilterObjectRecords,
- };
-};
diff --git a/packages/twenty-front/src/modules/object-record/relation-picker/hooks/useMultiObjectSearchMatchesSearchFilterQuery.ts b/packages/twenty-front/src/modules/object-record/relation-picker/hooks/useMultiObjectSearchMatchesSearchFilterQuery.ts
new file mode 100644
index 000000000000..a8bdfec35419
--- /dev/null
+++ b/packages/twenty-front/src/modules/object-record/relation-picker/hooks/useMultiObjectSearchMatchesSearchFilterQuery.ts
@@ -0,0 +1,75 @@
+import { useQuery } from '@apollo/client';
+import { useRecoilValue } from 'recoil';
+
+import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
+import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
+import { EMPTY_QUERY } from '@/object-record/constants/EmptyQuery';
+import { useGenerateCombinedSearchRecordsQuery } from '@/object-record/multiple-objects/hooks/useGenerateCombinedSearchRecordsQuery';
+import { useLimitPerMetadataItem } from '@/object-record/relation-picker/hooks/useLimitPerMetadataItem';
+import {
+ MultiObjectRecordQueryResult,
+ useMultiObjectRecordsQueryResultFormattedAsObjectRecordForSelectArray,
+} from '@/object-record/relation-picker/hooks/useMultiObjectRecordsQueryResultFormattedAsObjectRecordForSelectArray';
+import { isObjectMetadataItemSearchableInCombinedRequest } from '@/object-record/utils/isObjectMetadataItemSearchableInCombinedRequest';
+import { isDefined } from '~/utils/isDefined';
+
+export const useMultiObjectSearchMatchesSearchFilterQuery = ({
+ searchFilterValue,
+ limit,
+ excludedObjects,
+}: {
+ searchFilterValue: string;
+ limit?: number;
+ excludedObjects?: CoreObjectNameSingular[];
+}) => {
+ const objectMetadataItems = useRecoilValue(objectMetadataItemsState);
+
+ const selectableObjectMetadataItems = objectMetadataItems
+ .filter(({ isSystem, isRemote }) => !isSystem && !isRemote)
+ .filter(({ nameSingular }) => {
+ return !excludedObjects?.includes(nameSingular as CoreObjectNameSingular);
+ })
+ .filter((objectMetadataItem) =>
+ isObjectMetadataItemSearchableInCombinedRequest(objectMetadataItem),
+ );
+
+ const { limitPerMetadataItem } = useLimitPerMetadataItem({
+ objectMetadataItems,
+ limit,
+ });
+
+ const multiSelectSearchQueryForSelectedIds =
+ useGenerateCombinedSearchRecordsQuery({
+ operationSignatures: selectableObjectMetadataItems.map(
+ (objectMetadataItem) => ({
+ objectNameSingular: objectMetadataItem.nameSingular,
+ variables: {},
+ }),
+ ),
+ });
+
+ const {
+ loading: matchesSearchFilterObjectRecordsLoading,
+ data: matchesSearchFilterObjectRecordsQueryResult,
+ } = useQuery(
+ multiSelectSearchQueryForSelectedIds ?? EMPTY_QUERY,
+ {
+ variables: {
+ search: searchFilterValue,
+ ...limitPerMetadataItem,
+ },
+ skip: !isDefined(multiSelectSearchQueryForSelectedIds),
+ },
+ );
+
+ const { objectRecordForSelectArray: matchesSearchFilterObjectRecords } =
+ useMultiObjectRecordsQueryResultFormattedAsObjectRecordForSelectArray({
+ multiObjectRecordsQueryResult:
+ matchesSearchFilterObjectRecordsQueryResult,
+ });
+
+ return {
+ matchesSearchFilterObjectRecordsLoading,
+ matchesSearchFilterObjectRecords,
+ };
+};
diff --git a/packages/twenty-front/src/modules/object-record/relation-picker/hooks/useMultiObjectSearchSelectedItemsQuery.ts b/packages/twenty-front/src/modules/object-record/relation-picker/hooks/useMultiObjectSearchSelectedItemsQuery.ts
index 5656cb77f5b9..a4fd29ddcbb5 100644
--- a/packages/twenty-front/src/modules/object-record/relation-picker/hooks/useMultiObjectSearchSelectedItemsQuery.ts
+++ b/packages/twenty-front/src/modules/object-record/relation-picker/hooks/useMultiObjectSearchSelectedItemsQuery.ts
@@ -9,8 +9,8 @@ import {
MultiObjectRecordQueryResult,
useMultiObjectRecordsQueryResultFormattedAsObjectRecordForSelectArray,
} from '@/object-record/relation-picker/hooks/useMultiObjectRecordsQueryResultFormattedAsObjectRecordForSelectArray';
-import { SelectedObjectRecordId } from '@/object-record/relation-picker/hooks/useMultiObjectSearch';
import { useOrderByFieldPerMetadataItem } from '@/object-record/relation-picker/hooks/useOrderByFieldPerMetadataItem';
+import { SelectedObjectRecordId } from '@/object-record/types/SelectedObjectRecordId';
import { isDefined } from '~/utils/isDefined';
import { capitalize } from '~/utils/string/capitalize';
diff --git a/packages/twenty-front/src/modules/object-record/relation-picker/utils/formatMultiObjectRecordSearchResults.ts b/packages/twenty-front/src/modules/object-record/relation-picker/utils/formatMultiObjectRecordSearchResults.ts
new file mode 100644
index 000000000000..318f12ab7548
--- /dev/null
+++ b/packages/twenty-front/src/modules/object-record/relation-picker/utils/formatMultiObjectRecordSearchResults.ts
@@ -0,0 +1,16 @@
+import { MultiObjectRecordQueryResult } from '@/object-record/relation-picker/hooks/useMultiObjectRecordsQueryResultFormattedAsObjectRecordForSelectArray';
+
+export const formatMultiObjectRecordSearchResults = (
+ searchResults: MultiObjectRecordQueryResult | undefined | null,
+): MultiObjectRecordQueryResult => {
+ if (!searchResults) {
+ return {};
+ }
+
+ return Object.entries(searchResults).reduce((acc, [key, value]) => {
+ let newKey = key.replace(/^search/, '');
+ newKey = newKey.charAt(0).toLowerCase() + newKey.slice(1);
+ acc[newKey] = value;
+ return acc;
+ }, {} as MultiObjectRecordQueryResult);
+};
diff --git a/packages/twenty-front/src/modules/object-record/types/ObjectRecordForSelect.ts b/packages/twenty-front/src/modules/object-record/types/ObjectRecordForSelect.ts
new file mode 100644
index 000000000000..a1266fb6f702
--- /dev/null
+++ b/packages/twenty-front/src/modules/object-record/types/ObjectRecordForSelect.ts
@@ -0,0 +1,9 @@
+import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
+import { ObjectRecord } from '@/object-record/types/ObjectRecord';
+import { ObjectRecordIdentifier } from '@/object-record/types/ObjectRecordIdentifier';
+
+export type ObjectRecordForSelect = {
+ objectMetadataItem: ObjectMetadataItem;
+ record: ObjectRecord;
+ recordIdentifier: ObjectRecordIdentifier;
+};
diff --git a/packages/twenty-front/src/modules/object-record/types/SelectedObjectRecordId.ts b/packages/twenty-front/src/modules/object-record/types/SelectedObjectRecordId.ts
new file mode 100644
index 000000000000..2c9bb2353892
--- /dev/null
+++ b/packages/twenty-front/src/modules/object-record/types/SelectedObjectRecordId.ts
@@ -0,0 +1,4 @@
+export type SelectedObjectRecordId = {
+ objectNameSingular: string;
+ id: string;
+};