feat: add Relation Field Card plus button in Show Page (#3229)
Closes #3124
This commit is contained in:
@ -1,7 +1,5 @@
|
||||
import { useEffect } from 'react';
|
||||
import { useQuery } from '@apollo/client';
|
||||
|
||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||
import { useObjectNameSingularFromPlural } from '@/object-metadata/hooks/useObjectNameSingularFromPlural';
|
||||
import { FieldDefinition } from '@/object-record/field/types/FieldDefinition';
|
||||
import { FieldRelationMetadata } from '@/object-record/field/types/FieldMetadata';
|
||||
@ -13,7 +11,7 @@ import { IconForbid } from '@/ui/display/icon';
|
||||
|
||||
export type RelationPickerProps = {
|
||||
recordId?: string;
|
||||
onSubmit: (newUser: EntityForSelect | null) => void;
|
||||
onSubmit: (selectedEntity: EntityForSelect | null) => void;
|
||||
onCancel?: () => void;
|
||||
width?: number;
|
||||
excludeRecordIds?: string[];
|
||||
@ -30,32 +28,24 @@ export const RelationPicker = ({
|
||||
initialSearchFilter,
|
||||
fieldDefinition,
|
||||
}: RelationPickerProps) => {
|
||||
const { relationPickerSearchFilter, setRelationPickerSearchFilter } =
|
||||
useRelationPicker();
|
||||
const {
|
||||
relationPickerSearchFilter,
|
||||
setRelationPickerSearchFilter,
|
||||
identifiersMapper,
|
||||
searchQuery,
|
||||
} = useRelationPicker();
|
||||
|
||||
useEffect(() => {
|
||||
setRelationPickerSearchFilter(initialSearchFilter ?? '');
|
||||
}, [initialSearchFilter, setRelationPickerSearchFilter]);
|
||||
|
||||
// TODO: refactor useFilteredSearchEntityQuery
|
||||
const { findManyRecordsQuery } = useObjectMetadataItem({
|
||||
objectNameSingular:
|
||||
fieldDefinition.metadata.relationObjectMetadataNameSingular,
|
||||
});
|
||||
|
||||
const useFindManyQuery = (options: any) =>
|
||||
useQuery(findManyRecordsQuery, options);
|
||||
|
||||
const { identifiersMapper, searchQuery } = useRelationPicker();
|
||||
|
||||
const { objectNameSingular: relationObjectNameSingular } =
|
||||
useObjectNameSingularFromPlural({
|
||||
objectNamePlural:
|
||||
fieldDefinition.metadata.relationObjectMetadataNamePlural,
|
||||
});
|
||||
|
||||
const records = useFilteredSearchEntityQuery({
|
||||
queryHook: useFindManyQuery,
|
||||
const entities = useFilteredSearchEntityQuery({
|
||||
filters: [
|
||||
{
|
||||
fieldNames:
|
||||
@ -76,19 +66,18 @@ export const RelationPicker = ({
|
||||
objectNameSingular: relationObjectNameSingular,
|
||||
});
|
||||
|
||||
const handleEntitySelected = async (selectedUser: any | null | undefined) => {
|
||||
onSubmit(selectedUser ?? null);
|
||||
};
|
||||
const handleEntitySelected = (selectedEntity: any | null | undefined) =>
|
||||
onSubmit(selectedEntity ?? null);
|
||||
|
||||
return (
|
||||
<SingleEntitySelect
|
||||
EmptyIcon={IconForbid}
|
||||
emptyLabel={'No ' + fieldDefinition.label}
|
||||
entitiesToSelect={records.entitiesToSelect}
|
||||
loading={records.loading}
|
||||
entitiesToSelect={entities.entitiesToSelect}
|
||||
loading={entities.loading}
|
||||
onCancel={onCancel}
|
||||
onEntitySelected={handleEntitySelected}
|
||||
selectedEntity={records.selectedEntities[0]}
|
||||
selectedEntity={entities.selectedEntities[0]}
|
||||
width={width}
|
||||
/>
|
||||
);
|
||||
|
||||
@ -1,32 +1,16 @@
|
||||
import { useRef } from 'react';
|
||||
|
||||
import { DropdownMenu } from '@/ui/layout/dropdown/components/DropdownMenu';
|
||||
import { DropdownMenuSearchInput } from '@/ui/layout/dropdown/components/DropdownMenuSearchInput';
|
||||
import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
|
||||
import { useListenClickOutside } from '@/ui/utilities/pointer-event/hooks/useListenClickOutside';
|
||||
import { isDefined } from '~/utils/isDefined';
|
||||
|
||||
import { useEntitySelectSearch } from '../hooks/useEntitySelectSearch';
|
||||
|
||||
import {
|
||||
SingleEntitySelectBase,
|
||||
SingleEntitySelectBaseProps,
|
||||
} from './SingleEntitySelectBase';
|
||||
SingleEntitySelectMenuItemsWithSearch,
|
||||
SingleEntitySelectMenuItemsWithSearchProps,
|
||||
} from '@/object-record/relation-picker/components/SingleEntitySelectMenuItemsWithSearch';
|
||||
import { DropdownMenu } from '@/ui/layout/dropdown/components/DropdownMenu';
|
||||
import { useListenClickOutside } from '@/ui/utilities/pointer-event/hooks/useListenClickOutside';
|
||||
|
||||
export type SingleEntitySelectProps = {
|
||||
disableBackgroundBlur?: boolean;
|
||||
onCreate?: () => void;
|
||||
width?: number;
|
||||
} & Pick<
|
||||
SingleEntitySelectBaseProps,
|
||||
| 'EmptyIcon'
|
||||
| 'emptyLabel'
|
||||
| 'entitiesToSelect'
|
||||
| 'loading'
|
||||
| 'onCancel'
|
||||
| 'onEntitySelected'
|
||||
| 'selectedEntity'
|
||||
>;
|
||||
} & SingleEntitySelectMenuItemsWithSearchProps;
|
||||
|
||||
export const SingleEntitySelect = ({
|
||||
EmptyIcon,
|
||||
@ -42,10 +26,6 @@ export const SingleEntitySelect = ({
|
||||
}: SingleEntitySelectProps) => {
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
const { searchFilter, handleSearchFilterChange } = useEntitySelectSearch();
|
||||
|
||||
const showCreateButton = isDefined(onCreate) && searchFilter !== '';
|
||||
|
||||
useListenClickOutside({
|
||||
refs: [containerRef],
|
||||
callback: (event) => {
|
||||
@ -62,13 +42,7 @@ export const SingleEntitySelect = ({
|
||||
width={width}
|
||||
data-select-disable
|
||||
>
|
||||
<DropdownMenuSearchInput
|
||||
value={searchFilter}
|
||||
onChange={handleSearchFilterChange}
|
||||
autoFocus
|
||||
/>
|
||||
<DropdownMenuSeparator />
|
||||
<SingleEntitySelectBase
|
||||
<SingleEntitySelectMenuItemsWithSearch
|
||||
{...{
|
||||
EmptyIcon,
|
||||
emptyLabel,
|
||||
@ -78,7 +52,6 @@ export const SingleEntitySelect = ({
|
||||
onCreate,
|
||||
onEntitySelected,
|
||||
selectedEntity,
|
||||
showCreateButton,
|
||||
}}
|
||||
/>
|
||||
</DropdownMenu>
|
||||
|
||||
@ -5,6 +5,8 @@ import { Key } from 'ts-key-enum';
|
||||
import { SelectableMenuItemSelect } from '@/object-record/relation-picker/components/SelectableMenuItemSelect';
|
||||
import { IconPlus } from '@/ui/display/icon';
|
||||
import { IconComponent } from '@/ui/display/icon/types/IconComponent';
|
||||
import { CreateNewButton } from '@/ui/input/relation-picker/components/CreateNewButton';
|
||||
import { DropdownMenuSkeletonItem } from '@/ui/input/relation-picker/components/skeletons/DropdownMenuSkeletonItem';
|
||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||
import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
|
||||
import { SelectableList } from '@/ui/layout/selectable-list/components/SelectableList';
|
||||
@ -13,12 +15,10 @@ import { MenuItemSelect } from '@/ui/navigation/menu-item/components/MenuItemSel
|
||||
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
|
||||
import { assertNotNull } from '~/utils/assert';
|
||||
|
||||
import { CreateNewButton } from '../../../ui/input/relation-picker/components/CreateNewButton';
|
||||
import { DropdownMenuSkeletonItem } from '../../../ui/input/relation-picker/components/skeletons/DropdownMenuSkeletonItem';
|
||||
import { EntityForSelect } from '../types/EntityForSelect';
|
||||
import { RelationPickerHotkeyScope } from '../types/RelationPickerHotkeyScope';
|
||||
|
||||
export type SingleEntitySelectBaseProps = {
|
||||
export type SingleEntitySelectMenuItemsProps = {
|
||||
EmptyIcon?: IconComponent;
|
||||
emptyLabel?: string;
|
||||
entitiesToSelect: EntityForSelect[];
|
||||
@ -35,7 +35,7 @@ export type SingleEntitySelectBaseProps = {
|
||||
onAllEntitySelected?: () => void;
|
||||
};
|
||||
|
||||
export const SingleEntitySelectBase = ({
|
||||
export const SingleEntitySelectMenuItems = ({
|
||||
EmptyIcon,
|
||||
emptyLabel,
|
||||
entitiesToSelect,
|
||||
@ -50,7 +50,7 @@ export const SingleEntitySelectBase = ({
|
||||
isAllEntitySelected,
|
||||
isAllEntitySelectShown,
|
||||
onAllEntitySelected,
|
||||
}: SingleEntitySelectBaseProps) => {
|
||||
}: SingleEntitySelectMenuItemsProps) => {
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
const entitiesInDropdown = [selectedEntity, ...entitiesToSelect].filter(
|
||||
@ -0,0 +1,61 @@
|
||||
import {
|
||||
SingleEntitySelectMenuItems,
|
||||
SingleEntitySelectMenuItemsProps,
|
||||
} from '@/object-record/relation-picker/components/SingleEntitySelectMenuItems';
|
||||
import { DropdownMenuSearchInput } from '@/ui/layout/dropdown/components/DropdownMenuSearchInput';
|
||||
import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
|
||||
import { isDefined } from '~/utils/isDefined';
|
||||
|
||||
import { useEntitySelectSearch } from '../hooks/useEntitySelectSearch';
|
||||
|
||||
export type SingleEntitySelectMenuItemsWithSearchProps = {
|
||||
onCreate?: () => void;
|
||||
} & Pick<
|
||||
SingleEntitySelectMenuItemsProps,
|
||||
| 'EmptyIcon'
|
||||
| 'emptyLabel'
|
||||
| 'entitiesToSelect'
|
||||
| 'loading'
|
||||
| 'onCancel'
|
||||
| 'onEntitySelected'
|
||||
| 'selectedEntity'
|
||||
>;
|
||||
|
||||
export const SingleEntitySelectMenuItemsWithSearch = ({
|
||||
EmptyIcon,
|
||||
emptyLabel,
|
||||
entitiesToSelect,
|
||||
loading,
|
||||
onCancel,
|
||||
onCreate,
|
||||
onEntitySelected,
|
||||
selectedEntity,
|
||||
}: SingleEntitySelectMenuItemsWithSearchProps) => {
|
||||
const { searchFilter, handleSearchFilterChange } = useEntitySelectSearch();
|
||||
|
||||
const showCreateButton = isDefined(onCreate) && searchFilter !== '';
|
||||
|
||||
return (
|
||||
<>
|
||||
<DropdownMenuSearchInput
|
||||
value={searchFilter}
|
||||
onChange={handleSearchFilterChange}
|
||||
autoFocus
|
||||
/>
|
||||
<DropdownMenuSeparator />
|
||||
<SingleEntitySelectMenuItems
|
||||
{...{
|
||||
EmptyIcon,
|
||||
emptyLabel,
|
||||
entitiesToSelect,
|
||||
loading,
|
||||
onCancel,
|
||||
onCreate,
|
||||
onEntitySelected,
|
||||
selectedEntity,
|
||||
showCreateButton,
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user