Fixed record pickers create new (#12705)
This PR fixes many bugs related to creating a record from inside a relation picker, single or multiple. QA video : Part 1 : https://github.com/user-attachments/assets/35450b08-ff84-4698-8318-681d72437cd4 Part 2 : https://github.com/user-attachments/assets/807c3a7b-4116-41ff-b9a0-23767452b631 Also : - Refactored `RecordDetailRelationSectionDropdown` to split it into two components to avoid too many ternaries inside functions. Fixes https://github.com/twentyhq/twenty/issues/12668 Fixes https://github.com/twentyhq/twenty/issues/12669 Fixes https://github.com/twentyhq/twenty/issues/12670 Fixes https://github.com/twentyhq/twenty/issues/12671
This commit is contained in:
@ -16,7 +16,12 @@ import { FieldDefinition } from '@/object-record/record-field/types/FieldDefinit
|
|||||||
import { FieldInputEvent } from '@/object-record/record-field/types/FieldInputEvent';
|
import { FieldInputEvent } from '@/object-record/record-field/types/FieldInputEvent';
|
||||||
import { FieldRelationMetadata } from '@/object-record/record-field/types/FieldMetadata';
|
import { FieldRelationMetadata } from '@/object-record/record-field/types/FieldMetadata';
|
||||||
import { MultipleRecordPicker } from '@/object-record/record-picker/multiple-record-picker/components/MultipleRecordPicker';
|
import { MultipleRecordPicker } from '@/object-record/record-picker/multiple-record-picker/components/MultipleRecordPicker';
|
||||||
|
import { useMultipleRecordPickerPerformSearch } from '@/object-record/record-picker/multiple-record-picker/hooks/useMultipleRecordPickerPerformSearch';
|
||||||
|
import { multipleRecordPickerPickableMorphItemsComponentState } from '@/object-record/record-picker/multiple-record-picker/states/multipleRecordPickerPickableMorphItemsComponentState';
|
||||||
|
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
|
||||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||||
|
import { useRecoilCallback } from 'recoil';
|
||||||
|
import { isDefined } from 'twenty-shared/utils';
|
||||||
|
|
||||||
type RelationFromManyFieldInputProps = {
|
type RelationFromManyFieldInputProps = {
|
||||||
onSubmit?: FieldInputEvent;
|
onSubmit?: FieldInputEvent;
|
||||||
@ -86,6 +91,55 @@ export const RelationFromManyFieldInput = ({
|
|||||||
recordFieldInputLayoutDirectionComponentState,
|
recordFieldInputLayoutDirectionComponentState,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const multipleRecordPickerPickableMorphItemsCallbackState =
|
||||||
|
useRecoilComponentCallbackStateV2(
|
||||||
|
multipleRecordPickerPickableMorphItemsComponentState,
|
||||||
|
recordPickerInstanceId,
|
||||||
|
);
|
||||||
|
const { performSearch: multipleRecordPickerPerformSearch } =
|
||||||
|
useMultipleRecordPickerPerformSearch();
|
||||||
|
|
||||||
|
const handleCreateNew = useRecoilCallback(
|
||||||
|
({ snapshot, set }) =>
|
||||||
|
async (searchInput?: string) => {
|
||||||
|
const newRecordId =
|
||||||
|
await createNewRecordAndOpenRightDrawer?.(searchInput);
|
||||||
|
|
||||||
|
if (!isDefined(newRecordId)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const multipleRecordPickerPickableMorphItems = snapshot
|
||||||
|
.getLoadable(multipleRecordPickerPickableMorphItemsCallbackState)
|
||||||
|
.getValue();
|
||||||
|
|
||||||
|
const newMorphItems = multipleRecordPickerPickableMorphItems.concat({
|
||||||
|
recordId: newRecordId,
|
||||||
|
objectMetadataId: relationObjectMetadataItem.id,
|
||||||
|
isSelected: true,
|
||||||
|
isMatchingSearchFilter: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
set(multipleRecordPickerPickableMorphItemsCallbackState, newMorphItems);
|
||||||
|
|
||||||
|
multipleRecordPickerPerformSearch({
|
||||||
|
multipleRecordPickerInstanceId: recordPickerInstanceId,
|
||||||
|
forceSearchFilter: searchInput,
|
||||||
|
forceSearchableObjectMetadataItems: [relationObjectMetadataItem],
|
||||||
|
forcePickableMorphItems: newMorphItems,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
[
|
||||||
|
createNewRecordAndOpenRightDrawer,
|
||||||
|
relationObjectMetadataItem,
|
||||||
|
recordPickerInstanceId,
|
||||||
|
multipleRecordPickerPickableMorphItemsCallbackState,
|
||||||
|
multipleRecordPickerPerformSearch,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
const canCreateNew = !isRelationFromActivityTargets;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MultipleRecordPicker
|
<MultipleRecordPicker
|
||||||
focusId={recordPickerInstanceId}
|
focusId={recordPickerInstanceId}
|
||||||
@ -102,11 +156,7 @@ export const RelationFromManyFieldInput = ({
|
|||||||
updateRelation(morphItem);
|
updateRelation(morphItem);
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
onCreate={
|
onCreate={canCreateNew ? handleCreateNew : undefined}
|
||||||
!isRelationFromActivityTargets
|
|
||||||
? createNewRecordAndOpenRightDrawer
|
|
||||||
: undefined
|
|
||||||
}
|
|
||||||
onClickOutside={handleSubmit}
|
onClickOutside={handleSubmit}
|
||||||
layoutDirection={
|
layoutDirection={
|
||||||
layoutDirection === 'downward'
|
layoutDirection === 'downward'
|
||||||
|
|||||||
@ -8,9 +8,12 @@ import { recordFieldInputLayoutDirectionComponentState } from '@/object-record/r
|
|||||||
import { recordFieldInputLayoutDirectionLoadingComponentState } from '@/object-record/record-field/states/recordFieldInputLayoutDirectionLoadingComponentState';
|
import { recordFieldInputLayoutDirectionLoadingComponentState } from '@/object-record/record-field/states/recordFieldInputLayoutDirectionLoadingComponentState';
|
||||||
import { FieldInputEvent } from '@/object-record/record-field/types/FieldInputEvent';
|
import { FieldInputEvent } from '@/object-record/record-field/types/FieldInputEvent';
|
||||||
import { SingleRecordPicker } from '@/object-record/record-picker/single-record-picker/components/SingleRecordPicker';
|
import { SingleRecordPicker } from '@/object-record/record-picker/single-record-picker/components/SingleRecordPicker';
|
||||||
|
import { singleRecordPickerSelectedIdComponentState } from '@/object-record/record-picker/single-record-picker/states/singleRecordPickerSelectedIdComponentState';
|
||||||
import { SingleRecordPickerRecord } from '@/object-record/record-picker/single-record-picker/types/SingleRecordPickerRecord';
|
import { SingleRecordPickerRecord } from '@/object-record/record-picker/single-record-picker/types/SingleRecordPickerRecord';
|
||||||
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
|
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
|
||||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||||
|
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
||||||
|
import { isDefined } from 'twenty-shared/utils';
|
||||||
import { IconForbid } from 'twenty-ui/display';
|
import { IconForbid } from 'twenty-ui/display';
|
||||||
|
|
||||||
export type RelationToOneFieldInputProps = {
|
export type RelationToOneFieldInputProps = {
|
||||||
@ -62,6 +65,19 @@ export const RelationToOneFieldInput = ({
|
|||||||
recordFieldInputLayoutDirectionLoadingComponentState,
|
recordFieldInputLayoutDirectionLoadingComponentState,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const setSingleRecordPickerSelectedId = useSetRecoilComponentStateV2(
|
||||||
|
singleRecordPickerSelectedIdComponentState,
|
||||||
|
recordPickerInstanceId,
|
||||||
|
);
|
||||||
|
|
||||||
|
const handleCreateNew = async (searchInput?: string) => {
|
||||||
|
const newRecordId = await createNewRecordAndOpenRightDrawer?.(searchInput);
|
||||||
|
|
||||||
|
if (isDefined(newRecordId)) {
|
||||||
|
setSingleRecordPickerSelectedId(newRecordId);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
if (isLoading) {
|
if (isLoading) {
|
||||||
return <></>;
|
return <></>;
|
||||||
}
|
}
|
||||||
@ -73,7 +89,7 @@ export const RelationToOneFieldInput = ({
|
|||||||
EmptyIcon={IconForbid}
|
EmptyIcon={IconForbid}
|
||||||
emptyLabel={'No ' + fieldDefinition.label}
|
emptyLabel={'No ' + fieldDefinition.label}
|
||||||
onCancel={onCancel}
|
onCancel={onCancel}
|
||||||
onCreate={createNewRecordAndOpenRightDrawer}
|
onCreate={handleCreateNew}
|
||||||
onRecordSelected={handleRecordSelected}
|
onRecordSelected={handleRecordSelected}
|
||||||
objectNameSingular={
|
objectNameSingular={
|
||||||
fieldDefinition.metadata.relationObjectMetadataNameSingular
|
fieldDefinition.metadata.relationObjectMetadataNameSingular
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import { useSetRecoilState } from 'recoil';
|
import { useSetRecoilState } from 'recoil';
|
||||||
import { v4 } from 'uuid';
|
import { v4 } from 'uuid';
|
||||||
|
|
||||||
|
import { SEARCH_QUERY } from '@/command-menu/graphql/queries/search';
|
||||||
import { useOpenRecordInCommandMenu } from '@/command-menu/hooks/useOpenRecordInCommandMenu';
|
import { useOpenRecordInCommandMenu } from '@/command-menu/hooks/useOpenRecordInCommandMenu';
|
||||||
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';
|
||||||
@ -9,6 +10,8 @@ import { useCreateOneRecord } from '@/object-record/hooks/useCreateOneRecord';
|
|||||||
import { useUpdateOneRecord } from '@/object-record/hooks/useUpdateOneRecord';
|
import { useUpdateOneRecord } from '@/object-record/hooks/useUpdateOneRecord';
|
||||||
import { viewableRecordIdState } from '@/object-record/record-right-drawer/states/viewableRecordIdState';
|
import { viewableRecordIdState } from '@/object-record/record-right-drawer/states/viewableRecordIdState';
|
||||||
import { viewableRecordNameSingularState } from '@/object-record/record-right-drawer/states/viewableRecordNameSingularState';
|
import { viewableRecordNameSingularState } from '@/object-record/record-right-drawer/states/viewableRecordNameSingularState';
|
||||||
|
import { useApolloClient } from '@apollo/client';
|
||||||
|
import { getOperationName } from '@apollo/client/utilities';
|
||||||
import { isDefined } from 'twenty-shared/utils';
|
import { isDefined } from 'twenty-shared/utils';
|
||||||
import { FieldMetadataType, RelationType } from '~/generated-metadata/graphql';
|
import { FieldMetadataType, RelationType } from '~/generated-metadata/graphql';
|
||||||
|
|
||||||
@ -18,6 +21,7 @@ type RecordDetailRelationSectionProps = {
|
|||||||
relationFieldMetadataItem?: FieldMetadataItem;
|
relationFieldMetadataItem?: FieldMetadataItem;
|
||||||
recordId: string;
|
recordId: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useAddNewRecordAndOpenRightDrawer = ({
|
export const useAddNewRecordAndOpenRightDrawer = ({
|
||||||
relationObjectMetadataNameSingular,
|
relationObjectMetadataNameSingular,
|
||||||
relationObjectMetadataItem,
|
relationObjectMetadataItem,
|
||||||
@ -41,6 +45,8 @@ export const useAddNewRecordAndOpenRightDrawer = ({
|
|||||||
|
|
||||||
const { openRecordInCommandMenu } = useOpenRecordInCommandMenu();
|
const { openRecordInCommandMenu } = useOpenRecordInCommandMenu();
|
||||||
|
|
||||||
|
const apolloClient = useApolloClient();
|
||||||
|
|
||||||
if (
|
if (
|
||||||
relationObjectMetadataNameSingular === 'workspaceMember' ||
|
relationObjectMetadataNameSingular === 'workspaceMember' ||
|
||||||
!isDefined(
|
!isDefined(
|
||||||
@ -103,10 +109,16 @@ export const useAddNewRecordAndOpenRightDrawer = ({
|
|||||||
setViewableRecordId(newRecordId);
|
setViewableRecordId(newRecordId);
|
||||||
setViewableRecordNameSingular(relationObjectMetadataNameSingular);
|
setViewableRecordNameSingular(relationObjectMetadataNameSingular);
|
||||||
|
|
||||||
|
apolloClient.refetchQueries({
|
||||||
|
include: [getOperationName(SEARCH_QUERY) ?? ''],
|
||||||
|
});
|
||||||
|
|
||||||
openRecordInCommandMenu({
|
openRecordInCommandMenu({
|
||||||
recordId: newRecordId,
|
recordId: newRecordId,
|
||||||
objectNameSingular: relationObjectMetadataNameSingular,
|
objectNameSingular: relationObjectMetadataNameSingular,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
return newRecordId;
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import {
|
|||||||
} from '@/object-record/record-picker/single-record-picker/components/SingleRecordPickerMenuItemsWithSearch';
|
} from '@/object-record/record-picker/single-record-picker/components/SingleRecordPickerMenuItemsWithSearch';
|
||||||
import { SingleRecordPickerComponentInstanceContext } from '@/object-record/record-picker/single-record-picker/states/contexts/SingleRecordPickerComponentInstanceContext';
|
import { SingleRecordPickerComponentInstanceContext } from '@/object-record/record-picker/single-record-picker/states/contexts/SingleRecordPickerComponentInstanceContext';
|
||||||
import { singleRecordPickerSearchFilterComponentState } from '@/object-record/record-picker/single-record-picker/states/singleRecordPickerSearchFilterComponentState';
|
import { singleRecordPickerSearchFilterComponentState } from '@/object-record/record-picker/single-record-picker/states/singleRecordPickerSearchFilterComponentState';
|
||||||
|
import { SingleRecordPickerRecord } from '@/object-record/record-picker/single-record-picker/types/SingleRecordPickerRecord';
|
||||||
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||||
import { useListenClickOutside } from '@/ui/utilities/pointer-event/hooks/useListenClickOutside';
|
import { useListenClickOutside } from '@/ui/utilities/pointer-event/hooks/useListenClickOutside';
|
||||||
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
||||||
@ -43,10 +44,12 @@ export const SingleRecordPicker = ({
|
|||||||
onCancel?.();
|
onCancel?.();
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleCreateNew = (searchInput?: string | undefined) => {
|
const handleRecordSelected = (
|
||||||
onCreate?.(searchInput);
|
selectedRecord?: SingleRecordPickerRecord | undefined,
|
||||||
|
) => {
|
||||||
setRecordPickerSearchFilter('');
|
setRecordPickerSearchFilter('');
|
||||||
|
|
||||||
|
onRecordSelected?.(selectedRecord);
|
||||||
};
|
};
|
||||||
|
|
||||||
useListenClickOutside({
|
useListenClickOutside({
|
||||||
@ -78,8 +81,8 @@ export const SingleRecordPicker = ({
|
|||||||
emptyLabel,
|
emptyLabel,
|
||||||
excludedRecordIds,
|
excludedRecordIds,
|
||||||
onCancel: handleCancel,
|
onCancel: handleCancel,
|
||||||
onCreate: handleCreateNew,
|
onCreate,
|
||||||
onRecordSelected,
|
onRecordSelected: handleRecordSelected,
|
||||||
objectNameSingular,
|
objectNameSingular,
|
||||||
layoutDirection,
|
layoutDirection,
|
||||||
}}
|
}}
|
||||||
|
|||||||
@ -76,6 +76,7 @@ export const SingleRecordPickerMenuItemsWithSearch = ({
|
|||||||
const searchHasNoResults =
|
const searchHasNoResults =
|
||||||
isNonEmptyString(recordPickerSearchFilter) &&
|
isNonEmptyString(recordPickerSearchFilter) &&
|
||||||
records.recordsToSelect.length === 0 &&
|
records.recordsToSelect.length === 0 &&
|
||||||
|
records.filteredSelectedRecords.length === 0 &&
|
||||||
!records.loading;
|
!records.loading;
|
||||||
|
|
||||||
const handleCreateNew = () => {
|
const handleCreateNew = () => {
|
||||||
|
|||||||
@ -40,7 +40,6 @@ export const useSingleRecordPickerSearch = (
|
|||||||
event: React.ChangeEvent<HTMLInputElement>,
|
event: React.ChangeEvent<HTMLInputElement>,
|
||||||
) => {
|
) => {
|
||||||
debouncedSetSearchFilter(event.currentTarget.value);
|
debouncedSetSearchFilter(event.currentTarget.value);
|
||||||
setRecordPickerSelectedId(undefined);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@ -1,34 +1,12 @@
|
|||||||
import { useCallback, useContext } from 'react';
|
import { useContext } from 'react';
|
||||||
import { useRecoilValue } from 'recoil';
|
|
||||||
|
|
||||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||||
import { useUpdateOneRecord } from '@/object-record/hooks/useUpdateOneRecord';
|
|
||||||
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
|
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
|
||||||
import { useIsFieldValueReadOnly } from '@/object-record/record-field/hooks/useIsFieldValueReadOnly';
|
import { useIsFieldValueReadOnly } from '@/object-record/record-field/hooks/useIsFieldValueReadOnly';
|
||||||
import { useIsRecordReadOnly } from '@/object-record/record-field/hooks/useIsRecordReadOnly';
|
import { useIsRecordReadOnly } from '@/object-record/record-field/hooks/useIsRecordReadOnly';
|
||||||
import { usePersistField } from '@/object-record/record-field/hooks/usePersistField';
|
|
||||||
import { useAddNewRecordAndOpenRightDrawer } from '@/object-record/record-field/meta-types/input/hooks/useAddNewRecordAndOpenRightDrawer';
|
|
||||||
import { useUpdateRelationFromManyFieldInput } from '@/object-record/record-field/meta-types/input/hooks/useUpdateRelationFromManyFieldInput';
|
|
||||||
import { FieldRelationMetadata } from '@/object-record/record-field/types/FieldMetadata';
|
import { FieldRelationMetadata } from '@/object-record/record-field/types/FieldMetadata';
|
||||||
import { MultipleRecordPicker } from '@/object-record/record-picker/multiple-record-picker/components/MultipleRecordPicker';
|
import { RecordDetailRelationSectionDropdownToMany } from '@/object-record/record-show/record-detail-section/components/RecordDetailRelationSectionDropdownToMany';
|
||||||
import { useMultipleRecordPickerPerformSearch } from '@/object-record/record-picker/multiple-record-picker/hooks/useMultipleRecordPickerPerformSearch';
|
import { RecordDetailRelationSectionDropdownToOne } from '@/object-record/record-show/record-detail-section/components/RecordDetailRelationSectionDropdownToOne';
|
||||||
import { multipleRecordPickerPickableMorphItemsComponentState } from '@/object-record/record-picker/multiple-record-picker/states/multipleRecordPickerPickableMorphItemsComponentState';
|
|
||||||
import { multipleRecordPickerSearchFilterComponentState } from '@/object-record/record-picker/multiple-record-picker/states/multipleRecordPickerSearchFilterComponentState';
|
|
||||||
import { multipleRecordPickerSearchableObjectMetadataItemsComponentState } from '@/object-record/record-picker/multiple-record-picker/states/multipleRecordPickerSearchableObjectMetadataItemsComponentState';
|
|
||||||
import { SingleRecordPicker } from '@/object-record/record-picker/single-record-picker/components/SingleRecordPicker';
|
|
||||||
import { singleRecordPickerSearchFilterComponentState } from '@/object-record/record-picker/single-record-picker/states/singleRecordPickerSearchFilterComponentState';
|
|
||||||
import { singleRecordPickerSelectedIdComponentState } from '@/object-record/record-picker/single-record-picker/states/singleRecordPickerSelectedIdComponentState';
|
|
||||||
import { SingleRecordPickerRecord } from '@/object-record/record-picker/single-record-picker/types/SingleRecordPickerRecord';
|
|
||||||
import { getRecordFieldCardRelationPickerDropdownId } from '@/object-record/record-show/utils/getRecordFieldCardRelationPickerDropdownId';
|
|
||||||
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
|
|
||||||
import { recordStoreFamilySelector } from '@/object-record/record-store/states/selectors/recordStoreFamilySelector';
|
|
||||||
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
|
|
||||||
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
|
||||||
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
|
||||||
import { DropdownScope } from '@/ui/layout/dropdown/scopes/DropdownScope';
|
|
||||||
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
|
||||||
import { IconForbid, IconPencil, IconPlus } from 'twenty-ui/display';
|
|
||||||
import { LightIconButton } from 'twenty-ui/input';
|
|
||||||
import { RelationType } from '~/generated-metadata/graphql';
|
import { RelationType } from '~/generated-metadata/graphql';
|
||||||
|
|
||||||
type RecordDetailRelationSectionDropdownProps = {
|
type RecordDetailRelationSectionDropdownProps = {
|
||||||
@ -38,17 +16,13 @@ type RecordDetailRelationSectionDropdownProps = {
|
|||||||
export const RecordDetailRelationSectionDropdown = ({
|
export const RecordDetailRelationSectionDropdown = ({
|
||||||
loading,
|
loading,
|
||||||
}: RecordDetailRelationSectionDropdownProps) => {
|
}: RecordDetailRelationSectionDropdownProps) => {
|
||||||
const { recordId, fieldDefinition } = useContext(FieldContext);
|
const { fieldDefinition, recordId } = useContext(FieldContext);
|
||||||
const {
|
const {
|
||||||
fieldName,
|
|
||||||
relationFieldMetadataId,
|
|
||||||
relationObjectMetadataNameSingular,
|
|
||||||
relationType,
|
relationType,
|
||||||
objectMetadataNameSingular,
|
objectMetadataNameSingular,
|
||||||
|
relationObjectMetadataNameSingular,
|
||||||
} = fieldDefinition.metadata as FieldRelationMetadata;
|
} = fieldDefinition.metadata as FieldRelationMetadata;
|
||||||
|
|
||||||
const record = useRecoilValue(recordStoreFamilyState(recordId));
|
|
||||||
|
|
||||||
const { objectMetadataItem: recordObjectMetadataItem } =
|
const { objectMetadataItem: recordObjectMetadataItem } =
|
||||||
useObjectMetadataItem({
|
useObjectMetadataItem({
|
||||||
objectNameSingular: objectMetadataNameSingular ?? '',
|
objectNameSingular: objectMetadataNameSingular ?? '',
|
||||||
@ -59,99 +33,10 @@ export const RecordDetailRelationSectionDropdown = ({
|
|||||||
objectNameSingular: relationObjectMetadataNameSingular,
|
objectNameSingular: relationObjectMetadataNameSingular,
|
||||||
});
|
});
|
||||||
|
|
||||||
const relationFieldMetadataItem = relationObjectMetadataItem.fields.find(
|
|
||||||
({ id }) => id === relationFieldMetadataId,
|
|
||||||
);
|
|
||||||
|
|
||||||
const fieldValue = useRecoilValue<
|
|
||||||
({ id: string } & Record<string, any>) | ObjectRecord[] | null
|
|
||||||
>(recordStoreFamilySelector({ recordId, fieldName }));
|
|
||||||
|
|
||||||
// TODO: use new relation type
|
// TODO: use new relation type
|
||||||
const isToOneObject = relationType === RelationType.MANY_TO_ONE;
|
const isToOneObject = relationType === RelationType.MANY_TO_ONE;
|
||||||
const isToManyObjects = relationType === RelationType.ONE_TO_MANY;
|
const isToManyObjects = relationType === RelationType.ONE_TO_MANY;
|
||||||
|
|
||||||
const relationRecords: ObjectRecord[] =
|
|
||||||
fieldValue && isToOneObject
|
|
||||||
? [fieldValue as ObjectRecord]
|
|
||||||
: ((fieldValue as ObjectRecord[]) ?? []);
|
|
||||||
|
|
||||||
const dropdownId = getRecordFieldCardRelationPickerDropdownId({
|
|
||||||
fieldDefinition,
|
|
||||||
recordId,
|
|
||||||
});
|
|
||||||
|
|
||||||
const { closeDropdown, dropdownPlacement } = useDropdown(dropdownId);
|
|
||||||
|
|
||||||
const setMultipleRecordPickerSearchFilter = useSetRecoilComponentStateV2(
|
|
||||||
multipleRecordPickerSearchFilterComponentState,
|
|
||||||
dropdownId,
|
|
||||||
);
|
|
||||||
|
|
||||||
const setMultipleRecordPickerPickableMorphItems =
|
|
||||||
useSetRecoilComponentStateV2(
|
|
||||||
multipleRecordPickerPickableMorphItemsComponentState,
|
|
||||||
dropdownId,
|
|
||||||
);
|
|
||||||
|
|
||||||
const setMultipleRecordPickerSearchableObjectMetadataItems =
|
|
||||||
useSetRecoilComponentStateV2(
|
|
||||||
multipleRecordPickerSearchableObjectMetadataItemsComponentState,
|
|
||||||
dropdownId,
|
|
||||||
);
|
|
||||||
|
|
||||||
const { performSearch: multipleRecordPickerPerformSearch } =
|
|
||||||
useMultipleRecordPickerPerformSearch();
|
|
||||||
|
|
||||||
const setSingleRecordPickerSearchFilter = useSetRecoilComponentStateV2(
|
|
||||||
singleRecordPickerSearchFilterComponentState,
|
|
||||||
dropdownId,
|
|
||||||
);
|
|
||||||
|
|
||||||
const setSingleRecordPickerSelectedId = useSetRecoilComponentStateV2(
|
|
||||||
singleRecordPickerSelectedIdComponentState,
|
|
||||||
dropdownId,
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleCloseRelationPickerDropdown = useCallback(() => {
|
|
||||||
setMultipleRecordPickerSearchFilter('');
|
|
||||||
}, [setMultipleRecordPickerSearchFilter]);
|
|
||||||
|
|
||||||
const persistField = usePersistField();
|
|
||||||
const { updateOneRecord: updateOneRelationRecord } = useUpdateOneRecord({
|
|
||||||
objectNameSingular: relationObjectMetadataNameSingular,
|
|
||||||
});
|
|
||||||
|
|
||||||
const handleRelationPickerEntitySelected = (
|
|
||||||
selectedRelationEntity?: SingleRecordPickerRecord,
|
|
||||||
) => {
|
|
||||||
closeDropdown();
|
|
||||||
|
|
||||||
if (!selectedRelationEntity?.id || !relationFieldMetadataItem?.name) return;
|
|
||||||
|
|
||||||
if (isToOneObject) {
|
|
||||||
persistField(selectedRelationEntity.record);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
updateOneRelationRecord({
|
|
||||||
idToUpdate: selectedRelationEntity.id,
|
|
||||||
updateOneRecordInput: {
|
|
||||||
[relationFieldMetadataItem.name]: record,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const { updateRelation } = useUpdateRelationFromManyFieldInput();
|
|
||||||
|
|
||||||
const { createNewRecordAndOpenRightDrawer } =
|
|
||||||
useAddNewRecordAndOpenRightDrawer({
|
|
||||||
relationObjectMetadataNameSingular,
|
|
||||||
relationObjectMetadataItem,
|
|
||||||
relationFieldMetadataItem,
|
|
||||||
recordId,
|
|
||||||
});
|
|
||||||
|
|
||||||
const isRecordReadOnly = useIsRecordReadOnly({
|
const isRecordReadOnly = useIsRecordReadOnly({
|
||||||
recordId,
|
recordId,
|
||||||
objectMetadataId: isToOneObject
|
objectMetadataId: isToOneObject
|
||||||
@ -166,93 +51,11 @@ export const RecordDetailRelationSectionDropdown = ({
|
|||||||
|
|
||||||
if (loading || isFieldReadOnly) return null;
|
if (loading || isFieldReadOnly) return null;
|
||||||
|
|
||||||
const handleOpenRelationPickerDropdown = () => {
|
if (isToOneObject) {
|
||||||
if (isToOneObject) {
|
return <RecordDetailRelationSectionDropdownToOne />;
|
||||||
setSingleRecordPickerSearchFilter('');
|
} else if (isToManyObjects) {
|
||||||
if (relationRecords.length > 0) {
|
return <RecordDetailRelationSectionDropdownToMany />;
|
||||||
setSingleRecordPickerSelectedId(relationRecords[0].id);
|
} else {
|
||||||
}
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isToManyObjects) {
|
|
||||||
setMultipleRecordPickerSearchableObjectMetadataItems([
|
|
||||||
relationObjectMetadataItem,
|
|
||||||
]);
|
|
||||||
setMultipleRecordPickerSearchFilter('');
|
|
||||||
setMultipleRecordPickerPickableMorphItems(
|
|
||||||
relationRecords.map((record) => ({
|
|
||||||
recordId: record.id,
|
|
||||||
objectMetadataId: relationObjectMetadataItem.id,
|
|
||||||
isSelected: true,
|
|
||||||
isMatchingSearchFilter: true,
|
|
||||||
})),
|
|
||||||
);
|
|
||||||
|
|
||||||
multipleRecordPickerPerformSearch({
|
|
||||||
multipleRecordPickerInstanceId: dropdownId,
|
|
||||||
forceSearchFilter: '',
|
|
||||||
forceSearchableObjectMetadataItems: [relationObjectMetadataItem],
|
|
||||||
forcePickableMorphItems: relationRecords.map((record) => ({
|
|
||||||
recordId: record.id,
|
|
||||||
objectMetadataId: relationObjectMetadataItem.id,
|
|
||||||
isSelected: true,
|
|
||||||
isMatchingSearchFilter: true,
|
|
||||||
})),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<DropdownScope dropdownScopeId={dropdownId}>
|
|
||||||
<Dropdown
|
|
||||||
dropdownId={dropdownId}
|
|
||||||
dropdownPlacement="left-start"
|
|
||||||
onClose={handleCloseRelationPickerDropdown}
|
|
||||||
onOpen={handleOpenRelationPickerDropdown}
|
|
||||||
clickableComponent={
|
|
||||||
<LightIconButton
|
|
||||||
className="displayOnHover"
|
|
||||||
Icon={isToOneObject ? IconPencil : IconPlus}
|
|
||||||
accent="tertiary"
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
dropdownComponents={
|
|
||||||
isToOneObject ? (
|
|
||||||
<SingleRecordPicker
|
|
||||||
focusId={dropdownId}
|
|
||||||
componentInstanceId={dropdownId}
|
|
||||||
EmptyIcon={IconForbid}
|
|
||||||
onRecordSelected={handleRelationPickerEntitySelected}
|
|
||||||
objectNameSingular={relationObjectMetadataNameSingular}
|
|
||||||
recordPickerInstanceId={dropdownId}
|
|
||||||
onCreate={createNewRecordAndOpenRightDrawer}
|
|
||||||
onCancel={closeDropdown}
|
|
||||||
layoutDirection={
|
|
||||||
dropdownPlacement?.includes('end')
|
|
||||||
? 'search-bar-on-bottom'
|
|
||||||
: 'search-bar-on-top'
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
<MultipleRecordPicker
|
|
||||||
focusId={dropdownId}
|
|
||||||
componentInstanceId={dropdownId}
|
|
||||||
onCreate={() => {
|
|
||||||
closeDropdown();
|
|
||||||
createNewRecordAndOpenRightDrawer?.();
|
|
||||||
}}
|
|
||||||
onChange={updateRelation}
|
|
||||||
onSubmit={closeDropdown}
|
|
||||||
onClickOutside={closeDropdown}
|
|
||||||
layoutDirection={
|
|
||||||
dropdownPlacement?.includes('end')
|
|
||||||
? 'search-bar-on-bottom'
|
|
||||||
: 'search-bar-on-top'
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</DropdownScope>
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|||||||
@ -0,0 +1,153 @@
|
|||||||
|
import { useCallback, useContext } from 'react';
|
||||||
|
import { useRecoilValue } from 'recoil';
|
||||||
|
|
||||||
|
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||||
|
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
|
||||||
|
import { useAddNewRecordAndOpenRightDrawer } from '@/object-record/record-field/meta-types/input/hooks/useAddNewRecordAndOpenRightDrawer';
|
||||||
|
import { useUpdateRelationFromManyFieldInput } from '@/object-record/record-field/meta-types/input/hooks/useUpdateRelationFromManyFieldInput';
|
||||||
|
import { FieldRelationMetadata } from '@/object-record/record-field/types/FieldMetadata';
|
||||||
|
import { MultipleRecordPicker } from '@/object-record/record-picker/multiple-record-picker/components/MultipleRecordPicker';
|
||||||
|
import { useMultipleRecordPickerPerformSearch } from '@/object-record/record-picker/multiple-record-picker/hooks/useMultipleRecordPickerPerformSearch';
|
||||||
|
import { multipleRecordPickerPickableMorphItemsComponentState } from '@/object-record/record-picker/multiple-record-picker/states/multipleRecordPickerPickableMorphItemsComponentState';
|
||||||
|
import { multipleRecordPickerSearchFilterComponentState } from '@/object-record/record-picker/multiple-record-picker/states/multipleRecordPickerSearchFilterComponentState';
|
||||||
|
import { multipleRecordPickerSearchableObjectMetadataItemsComponentState } from '@/object-record/record-picker/multiple-record-picker/states/multipleRecordPickerSearchableObjectMetadataItemsComponentState';
|
||||||
|
import { getRecordFieldCardRelationPickerDropdownId } from '@/object-record/record-show/utils/getRecordFieldCardRelationPickerDropdownId';
|
||||||
|
import { recordStoreFamilySelector } from '@/object-record/record-store/states/selectors/recordStoreFamilySelector';
|
||||||
|
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
|
||||||
|
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
||||||
|
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
||||||
|
import { DropdownScope } from '@/ui/layout/dropdown/scopes/DropdownScope';
|
||||||
|
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
||||||
|
import { IconPlus } from 'twenty-ui/display';
|
||||||
|
import { LightIconButton } from 'twenty-ui/input';
|
||||||
|
|
||||||
|
export const RecordDetailRelationSectionDropdownToMany = () => {
|
||||||
|
const { recordId, fieldDefinition } = useContext(FieldContext);
|
||||||
|
const {
|
||||||
|
fieldName,
|
||||||
|
relationFieldMetadataId,
|
||||||
|
relationObjectMetadataNameSingular,
|
||||||
|
} = fieldDefinition.metadata as FieldRelationMetadata;
|
||||||
|
|
||||||
|
const { objectMetadataItem: relationObjectMetadataItem } =
|
||||||
|
useObjectMetadataItem({
|
||||||
|
objectNameSingular: relationObjectMetadataNameSingular,
|
||||||
|
});
|
||||||
|
|
||||||
|
const relationFieldMetadataItem = relationObjectMetadataItem.fields.find(
|
||||||
|
({ id }) => id === relationFieldMetadataId,
|
||||||
|
);
|
||||||
|
|
||||||
|
const fieldValue = useRecoilValue<
|
||||||
|
({ id: string } & Record<string, any>) | ObjectRecord[] | null
|
||||||
|
>(recordStoreFamilySelector({ recordId, fieldName }));
|
||||||
|
|
||||||
|
const relationRecords: ObjectRecord[] = (fieldValue as ObjectRecord[]) ?? [];
|
||||||
|
|
||||||
|
const dropdownId = getRecordFieldCardRelationPickerDropdownId({
|
||||||
|
fieldDefinition,
|
||||||
|
recordId,
|
||||||
|
});
|
||||||
|
|
||||||
|
const { closeDropdown, dropdownPlacement } = useDropdown(dropdownId);
|
||||||
|
|
||||||
|
const setMultipleRecordPickerSearchFilter = useSetRecoilComponentStateV2(
|
||||||
|
multipleRecordPickerSearchFilterComponentState,
|
||||||
|
dropdownId,
|
||||||
|
);
|
||||||
|
|
||||||
|
const setMultipleRecordPickerPickableMorphItems =
|
||||||
|
useSetRecoilComponentStateV2(
|
||||||
|
multipleRecordPickerPickableMorphItemsComponentState,
|
||||||
|
dropdownId,
|
||||||
|
);
|
||||||
|
|
||||||
|
const setMultipleRecordPickerSearchableObjectMetadataItems =
|
||||||
|
useSetRecoilComponentStateV2(
|
||||||
|
multipleRecordPickerSearchableObjectMetadataItemsComponentState,
|
||||||
|
dropdownId,
|
||||||
|
);
|
||||||
|
|
||||||
|
const { performSearch: multipleRecordPickerPerformSearch } =
|
||||||
|
useMultipleRecordPickerPerformSearch();
|
||||||
|
|
||||||
|
const handleCloseRelationPickerDropdown = useCallback(() => {
|
||||||
|
setMultipleRecordPickerSearchFilter('');
|
||||||
|
}, [setMultipleRecordPickerSearchFilter]);
|
||||||
|
|
||||||
|
const { updateRelation } = useUpdateRelationFromManyFieldInput();
|
||||||
|
|
||||||
|
const { createNewRecordAndOpenRightDrawer } =
|
||||||
|
useAddNewRecordAndOpenRightDrawer({
|
||||||
|
relationObjectMetadataNameSingular,
|
||||||
|
relationObjectMetadataItem,
|
||||||
|
relationFieldMetadataItem,
|
||||||
|
recordId,
|
||||||
|
});
|
||||||
|
|
||||||
|
const handleOpenRelationPickerDropdown = () => {
|
||||||
|
setMultipleRecordPickerSearchableObjectMetadataItems([
|
||||||
|
relationObjectMetadataItem,
|
||||||
|
]);
|
||||||
|
setMultipleRecordPickerSearchFilter('');
|
||||||
|
setMultipleRecordPickerPickableMorphItems(
|
||||||
|
relationRecords.map((record) => ({
|
||||||
|
recordId: record.id,
|
||||||
|
objectMetadataId: relationObjectMetadataItem.id,
|
||||||
|
isSelected: true,
|
||||||
|
isMatchingSearchFilter: true,
|
||||||
|
})),
|
||||||
|
);
|
||||||
|
|
||||||
|
multipleRecordPickerPerformSearch({
|
||||||
|
multipleRecordPickerInstanceId: dropdownId,
|
||||||
|
forceSearchFilter: '',
|
||||||
|
forceSearchableObjectMetadataItems: [relationObjectMetadataItem],
|
||||||
|
forcePickableMorphItems: relationRecords.map((record) => ({
|
||||||
|
recordId: record.id,
|
||||||
|
objectMetadataId: relationObjectMetadataItem.id,
|
||||||
|
isSelected: true,
|
||||||
|
isMatchingSearchFilter: true,
|
||||||
|
})),
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleCreateNew = (searchString?: string) => {
|
||||||
|
closeDropdown();
|
||||||
|
|
||||||
|
createNewRecordAndOpenRightDrawer?.(searchString);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<DropdownScope dropdownScopeId={dropdownId}>
|
||||||
|
<Dropdown
|
||||||
|
dropdownId={dropdownId}
|
||||||
|
dropdownPlacement="left-start"
|
||||||
|
onClose={handleCloseRelationPickerDropdown}
|
||||||
|
onOpen={handleOpenRelationPickerDropdown}
|
||||||
|
clickableComponent={
|
||||||
|
<LightIconButton
|
||||||
|
className="displayOnHover"
|
||||||
|
Icon={IconPlus}
|
||||||
|
accent="tertiary"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
dropdownComponents={
|
||||||
|
<MultipleRecordPicker
|
||||||
|
focusId={dropdownId}
|
||||||
|
componentInstanceId={dropdownId}
|
||||||
|
onCreate={handleCreateNew}
|
||||||
|
onChange={updateRelation}
|
||||||
|
onSubmit={closeDropdown}
|
||||||
|
onClickOutside={closeDropdown}
|
||||||
|
layoutDirection={
|
||||||
|
dropdownPlacement?.includes('end')
|
||||||
|
? 'search-bar-on-bottom'
|
||||||
|
: 'search-bar-on-top'
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</DropdownScope>
|
||||||
|
);
|
||||||
|
};
|
||||||
@ -0,0 +1,141 @@
|
|||||||
|
import { useCallback, useContext } from 'react';
|
||||||
|
import { useRecoilValue } from 'recoil';
|
||||||
|
|
||||||
|
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||||
|
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||||
|
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
|
||||||
|
import { usePersistField } from '@/object-record/record-field/hooks/usePersistField';
|
||||||
|
import { useAddNewRecordAndOpenRightDrawer } from '@/object-record/record-field/meta-types/input/hooks/useAddNewRecordAndOpenRightDrawer';
|
||||||
|
import { FieldRelationMetadata } from '@/object-record/record-field/types/FieldMetadata';
|
||||||
|
import { SingleRecordPicker } from '@/object-record/record-picker/single-record-picker/components/SingleRecordPicker';
|
||||||
|
import { singleRecordPickerSearchFilterComponentState } from '@/object-record/record-picker/single-record-picker/states/singleRecordPickerSearchFilterComponentState';
|
||||||
|
import { singleRecordPickerSelectedIdComponentState } from '@/object-record/record-picker/single-record-picker/states/singleRecordPickerSelectedIdComponentState';
|
||||||
|
import { SingleRecordPickerRecord } from '@/object-record/record-picker/single-record-picker/types/SingleRecordPickerRecord';
|
||||||
|
import { getRecordFieldCardRelationPickerDropdownId } from '@/object-record/record-show/utils/getRecordFieldCardRelationPickerDropdownId';
|
||||||
|
import { recordStoreFamilySelector } from '@/object-record/record-store/states/selectors/recordStoreFamilySelector';
|
||||||
|
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
|
||||||
|
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
||||||
|
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
||||||
|
import { DropdownScope } from '@/ui/layout/dropdown/scopes/DropdownScope';
|
||||||
|
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
||||||
|
import { IconForbid, IconPencil } from 'twenty-ui/display';
|
||||||
|
import { LightIconButton } from 'twenty-ui/input';
|
||||||
|
|
||||||
|
export const RecordDetailRelationSectionDropdownToOne = () => {
|
||||||
|
const { recordId, fieldDefinition } = useContext(FieldContext);
|
||||||
|
const {
|
||||||
|
fieldName,
|
||||||
|
relationFieldMetadataId,
|
||||||
|
relationObjectMetadataNameSingular,
|
||||||
|
} = fieldDefinition.metadata as FieldRelationMetadata;
|
||||||
|
|
||||||
|
const { objectMetadataItem: relationObjectMetadataItem } =
|
||||||
|
useObjectMetadataItem({
|
||||||
|
objectNameSingular: relationObjectMetadataNameSingular,
|
||||||
|
});
|
||||||
|
|
||||||
|
const relationFieldMetadataItem = relationObjectMetadataItem.fields.find(
|
||||||
|
({ id }) => id === relationFieldMetadataId,
|
||||||
|
);
|
||||||
|
|
||||||
|
const fieldValue = useRecoilValue<
|
||||||
|
({ id: string } & Record<string, any>) | ObjectRecord[] | null
|
||||||
|
>(recordStoreFamilySelector({ recordId, fieldName }));
|
||||||
|
|
||||||
|
const relationRecords: ObjectRecord[] = fieldValue
|
||||||
|
? [fieldValue as ObjectRecord]
|
||||||
|
: [];
|
||||||
|
|
||||||
|
const dropdownId = getRecordFieldCardRelationPickerDropdownId({
|
||||||
|
fieldDefinition,
|
||||||
|
recordId,
|
||||||
|
});
|
||||||
|
|
||||||
|
const { closeDropdown, dropdownPlacement } = useDropdown(dropdownId);
|
||||||
|
|
||||||
|
const setSingleRecordPickerSearchFilter = useSetRecoilComponentStateV2(
|
||||||
|
singleRecordPickerSearchFilterComponentState,
|
||||||
|
dropdownId,
|
||||||
|
);
|
||||||
|
|
||||||
|
const setSingleRecordPickerSelectedId = useSetRecoilComponentStateV2(
|
||||||
|
singleRecordPickerSelectedIdComponentState,
|
||||||
|
dropdownId,
|
||||||
|
);
|
||||||
|
|
||||||
|
const handleCloseRelationPickerDropdown = useCallback(() => {
|
||||||
|
setSingleRecordPickerSearchFilter('');
|
||||||
|
}, [setSingleRecordPickerSearchFilter]);
|
||||||
|
|
||||||
|
const persistField = usePersistField();
|
||||||
|
|
||||||
|
const handleRelationPickerEntitySelected = (
|
||||||
|
selectedRelationEntity?: SingleRecordPickerRecord,
|
||||||
|
) => {
|
||||||
|
closeDropdown();
|
||||||
|
|
||||||
|
if (!selectedRelationEntity?.id || !relationFieldMetadataItem?.name) return;
|
||||||
|
|
||||||
|
persistField(selectedRelationEntity.record);
|
||||||
|
};
|
||||||
|
|
||||||
|
const { createNewRecordAndOpenRightDrawer } =
|
||||||
|
useAddNewRecordAndOpenRightDrawer({
|
||||||
|
relationObjectMetadataNameSingular,
|
||||||
|
relationObjectMetadataItem,
|
||||||
|
relationFieldMetadataItem,
|
||||||
|
recordId,
|
||||||
|
});
|
||||||
|
|
||||||
|
const handleOpenRelationPickerDropdown = () => {
|
||||||
|
setSingleRecordPickerSearchFilter('');
|
||||||
|
if (relationRecords.length > 0) {
|
||||||
|
setSingleRecordPickerSelectedId(relationRecords[0]?.id);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleCreateNew = (searchString?: string) => {
|
||||||
|
closeDropdown();
|
||||||
|
|
||||||
|
createNewRecordAndOpenRightDrawer?.(searchString);
|
||||||
|
};
|
||||||
|
|
||||||
|
const shouldAllowCreateNew =
|
||||||
|
relationObjectMetadataNameSingular !==
|
||||||
|
CoreObjectNameSingular.WorkspaceMember;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<DropdownScope dropdownScopeId={dropdownId}>
|
||||||
|
<Dropdown
|
||||||
|
dropdownId={dropdownId}
|
||||||
|
dropdownPlacement="left-start"
|
||||||
|
onClose={handleCloseRelationPickerDropdown}
|
||||||
|
onOpen={handleOpenRelationPickerDropdown}
|
||||||
|
clickableComponent={
|
||||||
|
<LightIconButton
|
||||||
|
className="displayOnHover"
|
||||||
|
Icon={IconPencil}
|
||||||
|
accent="tertiary"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
dropdownComponents={
|
||||||
|
<SingleRecordPicker
|
||||||
|
focusId={dropdownId}
|
||||||
|
componentInstanceId={dropdownId}
|
||||||
|
EmptyIcon={IconForbid}
|
||||||
|
onRecordSelected={handleRelationPickerEntitySelected}
|
||||||
|
objectNameSingular={relationObjectMetadataNameSingular}
|
||||||
|
recordPickerInstanceId={dropdownId}
|
||||||
|
onCancel={closeDropdown}
|
||||||
|
onCreate={shouldAllowCreateNew ? handleCreateNew : undefined}
|
||||||
|
layoutDirection={
|
||||||
|
dropdownPlacement?.includes('end')
|
||||||
|
? 'search-bar-on-bottom'
|
||||||
|
: 'search-bar-on-top'
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</DropdownScope>
|
||||||
|
);
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user