Create a new entry directly from a many picker (#6478)

Closes #6091
This commit is contained in:
Marie
2024-08-01 15:08:07 +02:00
committed by GitHub
parent 8c8f192765
commit 1a90df8961
2 changed files with 55 additions and 3 deletions

View File

@ -1,11 +1,15 @@
import { useContext } from 'react'; import { useContext } from 'react';
import { ObjectMetadataItemsRelationPickerEffect } from '@/object-metadata/components/ObjectMetadataItemsRelationPickerEffect'; import { ObjectMetadataItemsRelationPickerEffect } from '@/object-metadata/components/ObjectMetadataItemsRelationPickerEffect';
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext'; import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
import { RelationFromManyFieldInputMultiRecordsEffect } from '@/object-record/record-field/meta-types/input/components/RelationFromManyFieldInputMultiRecordsEffect'; import { RelationFromManyFieldInputMultiRecordsEffect } from '@/object-record/record-field/meta-types/input/components/RelationFromManyFieldInputMultiRecordsEffect';
import { useUpdateRelationFromManyFieldInput } from '@/object-record/record-field/meta-types/input/hooks/useUpdateRelationFromManyFieldInput'; import { useUpdateRelationFromManyFieldInput } from '@/object-record/record-field/meta-types/input/hooks/useUpdateRelationFromManyFieldInput';
import { FieldDefinition } from '@/object-record/record-field/types/FieldDefinition';
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 { MultiRecordSelect } from '@/object-record/relation-picker/components/MultiRecordSelect'; import { MultiRecordSelect } from '@/object-record/relation-picker/components/MultiRecordSelect';
import { useAddNewRecordAndOpenRightDrawer } from '@/object-record/relation-picker/hooks/useAddNewRecordAndOpenRightDrawer';
import { RelationPickerScope } from '@/object-record/relation-picker/scopes/RelationPickerScope'; import { RelationPickerScope } from '@/object-record/relation-picker/scopes/RelationPickerScope';
export type RelationFromManyFieldInputProps = { export type RelationFromManyFieldInputProps = {
@ -15,7 +19,7 @@ export type RelationFromManyFieldInputProps = {
export const RelationFromManyFieldInput = ({ export const RelationFromManyFieldInput = ({
onSubmit, onSubmit,
}: RelationFromManyFieldInputProps) => { }: RelationFromManyFieldInputProps) => {
const { fieldDefinition } = useContext(FieldContext); const { fieldDefinition, entityId } = useContext(FieldContext);
const relationPickerScopeId = `relation-picker-${fieldDefinition.fieldMetadataId}`; const relationPickerScopeId = `relation-picker-${fieldDefinition.fieldMetadataId}`;
const { updateRelation } = useUpdateRelationFromManyFieldInput({ const { updateRelation } = useUpdateRelationFromManyFieldInput({
scopeId: relationPickerScopeId, scopeId: relationPickerScopeId,
@ -25,12 +29,38 @@ export const RelationFromManyFieldInput = ({
onSubmit?.(() => {}); onSubmit?.(() => {});
}; };
const relationFieldDefinition =
fieldDefinition as FieldDefinition<FieldRelationMetadata>;
const { objectMetadataItem: relationObjectMetadataItem } =
useObjectMetadataItem({
objectNameSingular:
relationFieldDefinition.metadata.relationObjectMetadataNameSingular,
});
const relationFieldMetadataItem = relationObjectMetadataItem.fields.find(
({ id }) => id === relationFieldDefinition.metadata.relationFieldMetadataId,
);
const { createNewRecordAndOpenRightDrawer } =
useAddNewRecordAndOpenRightDrawer({
relationObjectMetadataNameSingular:
relationFieldDefinition.metadata.relationObjectMetadataNameSingular,
relationObjectMetadataItem,
relationFieldMetadataItem,
entityId,
});
return ( return (
<> <>
<RelationPickerScope relationPickerScopeId={relationPickerScopeId}> <RelationPickerScope relationPickerScopeId={relationPickerScopeId}>
<ObjectMetadataItemsRelationPickerEffect /> <ObjectMetadataItemsRelationPickerEffect />
<RelationFromManyFieldInputMultiRecordsEffect /> <RelationFromManyFieldInputMultiRecordsEffect />
<MultiRecordSelect onSubmit={handleSubmit} onChange={updateRelation} /> <MultiRecordSelect
onSubmit={handleSubmit}
onChange={updateRelation}
onCreate={createNewRecordAndOpenRightDrawer}
/>
</RelationPickerScope> </RelationPickerScope>
</> </>
); );

View File

@ -1,5 +1,5 @@
import { useCallback, useRef } from 'react';
import styled from '@emotion/styled'; import styled from '@emotion/styled';
import { useCallback, useRef } from 'react';
import { useRecoilValue, useSetRecoilState } from 'recoil'; import { useRecoilValue, useSetRecoilState } from 'recoil';
import { useDebouncedCallback } from 'use-debounce'; import { useDebouncedCallback } from 'use-debounce';
@ -10,6 +10,7 @@ import { MULTI_OBJECT_RECORD_SELECT_SELECTABLE_LIST_ID } from '@/object-record/r
import { useRelationPickerScopedStates } from '@/object-record/relation-picker/hooks/internal/useRelationPickerScopedStates'; import { useRelationPickerScopedStates } from '@/object-record/relation-picker/hooks/internal/useRelationPickerScopedStates';
import { RelationPickerScopeInternalContext } from '@/object-record/relation-picker/scopes/scope-internal-context/RelationPickerScopeInternalContext'; import { RelationPickerScopeInternalContext } from '@/object-record/relation-picker/scopes/scope-internal-context/RelationPickerScopeInternalContext';
import { RelationPickerHotkeyScope } from '@/object-record/relation-picker/types/RelationPickerHotkeyScope'; import { RelationPickerHotkeyScope } from '@/object-record/relation-picker/types/RelationPickerHotkeyScope';
import { CreateNewButton } from '@/ui/input/relation-picker/components/CreateNewButton';
import { DropdownMenu } from '@/ui/layout/dropdown/components/DropdownMenu'; import { DropdownMenu } from '@/ui/layout/dropdown/components/DropdownMenu';
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer'; import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
import { DropdownMenuSearchInput } from '@/ui/layout/dropdown/components/DropdownMenuSearchInput'; import { DropdownMenuSearchInput } from '@/ui/layout/dropdown/components/DropdownMenuSearchInput';
@ -18,6 +19,7 @@ import { SelectableItem } from '@/ui/layout/selectable-list/components/Selectabl
import { SelectableList } from '@/ui/layout/selectable-list/components/SelectableList'; import { SelectableList } from '@/ui/layout/selectable-list/components/SelectableList';
import { MenuItem } from '@/ui/navigation/menu-item/components/MenuItem'; import { MenuItem } from '@/ui/navigation/menu-item/components/MenuItem';
import { useAvailableScopeIdOrThrow } from '@/ui/utilities/recoil-scope/scopes-internal/hooks/useAvailableScopeId'; import { useAvailableScopeIdOrThrow } from '@/ui/utilities/recoil-scope/scopes-internal/hooks/useAvailableScopeId';
import { IconPlus, isDefined } from 'twenty-ui';
export const StyledSelectableItem = styled(SelectableItem)` export const StyledSelectableItem = styled(SelectableItem)`
height: 100%; height: 100%;
@ -26,9 +28,11 @@ export const StyledSelectableItem = styled(SelectableItem)`
export const MultiRecordSelect = ({ export const MultiRecordSelect = ({
onChange, onChange,
onSubmit, onSubmit,
onCreate,
}: { }: {
onChange?: (changedRecordForSelectId: string) => void; onChange?: (changedRecordForSelectId: string) => void;
onSubmit?: () => void; onSubmit?: () => void;
onCreate?: ((searchInput?: string) => void) | (() => void);
}) => { }) => {
const containerRef = useRef<HTMLDivElement>(null); const containerRef = useRef<HTMLDivElement>(null);
@ -58,12 +62,18 @@ export const MultiRecordSelect = ({
leading: true, leading: true,
}); });
const debouncedOnCreate = useDebouncedCallback(
() => onCreate?.(relationPickerSearchFilter),
500,
);
const handleFilterChange = useCallback( const handleFilterChange = useCallback(
(event: React.ChangeEvent<HTMLInputElement>) => { (event: React.ChangeEvent<HTMLInputElement>) => {
debouncedSetSearchFilter(event.currentTarget.value); debouncedSetSearchFilter(event.currentTarget.value);
}, },
[debouncedSetSearchFilter], [debouncedSetSearchFilter],
); );
return ( return (
<> <>
<MultipleObjectRecordOnClickOutsideEffect <MultipleObjectRecordOnClickOutsideEffect
@ -104,6 +114,18 @@ export const MultiRecordSelect = ({
)} )}
</> </>
)} )}
{isDefined(onCreate) && (
<>
{objectRecordsIdsMultiSelect.length > 0 && (
<DropdownMenuSeparator />
)}
<CreateNewButton
onClick={debouncedOnCreate}
LeftIcon={IconPlus}
text="Add New"
/>
</>
)}
</DropdownMenuItemsContainer> </DropdownMenuItemsContainer>
</DropdownMenu> </DropdownMenu>
</> </>