feat: add Relation Field Card plus button in Show Page (#3229)
Closes #3124
This commit is contained in:
@ -1,7 +1,5 @@
|
|||||||
import { useCallback, useContext, useState } from 'react';
|
import { useCallback, useContext, useState } from 'react';
|
||||||
import { useQuery } from '@apollo/client';
|
|
||||||
|
|
||||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
|
||||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||||
import { NewButton } from '@/object-record/record-board/components/NewButton';
|
import { NewButton } from '@/object-record/record-board/components/NewButton';
|
||||||
import { BoardColumnContext } from '@/object-record/record-board/contexts/BoardColumnContext';
|
import { BoardColumnContext } from '@/object-record/record-board/contexts/BoardColumnContext';
|
||||||
@ -54,18 +52,10 @@ export const NewOpportunityButton = () => {
|
|||||||
setIsCreatingCard(false);
|
setIsCreatingCard(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
const { relationPickerSearchFilter } = useRelationPicker();
|
const { relationPickerSearchFilter, identifiersMapper, searchQuery } =
|
||||||
|
useRelationPicker();
|
||||||
// TODO: refactor useFilteredSearchEntityQuery
|
|
||||||
const { findManyRecordsQuery } = useObjectMetadataItem({
|
|
||||||
objectNameSingular: CoreObjectNameSingular.Company,
|
|
||||||
});
|
|
||||||
const useFindManyQuery = (options: any) =>
|
|
||||||
useQuery(findManyRecordsQuery, options);
|
|
||||||
const { identifiersMapper, searchQuery } = useRelationPicker();
|
|
||||||
|
|
||||||
const filteredSearchEntityResults = useFilteredSearchEntityQuery({
|
const filteredSearchEntityResults = useFilteredSearchEntityQuery({
|
||||||
queryHook: useFindManyQuery,
|
|
||||||
filters: [
|
filters: [
|
||||||
{
|
{
|
||||||
fieldNames: searchQuery?.computeFilterFields?.('company') ?? [],
|
fieldNames: searchQuery?.computeFilterFields?.('company') ?? [],
|
||||||
|
|||||||
@ -1,10 +1,8 @@
|
|||||||
import { useEffect, useMemo, useRef, useState } from 'react';
|
import { useEffect, useMemo, useRef, useState } from 'react';
|
||||||
import { useQuery } from '@apollo/client';
|
|
||||||
import { useRecoilValue } from 'recoil';
|
import { useRecoilValue } from 'recoil';
|
||||||
|
|
||||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
|
||||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||||
import { SingleEntitySelectBase } from '@/object-record/relation-picker/components/SingleEntitySelectBase';
|
import { SingleEntitySelectMenuItems } from '@/object-record/relation-picker/components/SingleEntitySelectMenuItems';
|
||||||
import { useEntitySelectSearch } from '@/object-record/relation-picker/hooks/useEntitySelectSearch';
|
import { useEntitySelectSearch } from '@/object-record/relation-picker/hooks/useEntitySelectSearch';
|
||||||
import { useRelationPicker } from '@/object-record/relation-picker/hooks/useRelationPicker';
|
import { useRelationPicker } from '@/object-record/relation-picker/hooks/useRelationPicker';
|
||||||
import { EntityForSelect } from '@/object-record/relation-picker/types/EntityForSelect';
|
import { EntityForSelect } from '@/object-record/relation-picker/types/EntityForSelect';
|
||||||
@ -36,16 +34,9 @@ export const OpportunityPicker = ({
|
|||||||
|
|
||||||
const { searchFilter, handleSearchFilterChange } = useEntitySelectSearch();
|
const { searchFilter, handleSearchFilterChange } = useEntitySelectSearch();
|
||||||
|
|
||||||
// TODO: refactor useFilteredSearchEntityQuery
|
|
||||||
const { findManyRecordsQuery: findManyCompanies } = useObjectMetadataItem({
|
|
||||||
objectNameSingular: CoreObjectNameSingular.Company,
|
|
||||||
});
|
|
||||||
const useFindManyQuery = (options: any) =>
|
|
||||||
useQuery(findManyCompanies, options);
|
|
||||||
const { identifiersMapper, searchQuery } = useRelationPicker();
|
const { identifiersMapper, searchQuery } = useRelationPicker();
|
||||||
|
|
||||||
const filteredSearchEntityResults = useFilteredSearchEntityQuery({
|
const filteredSearchEntityResults = useFilteredSearchEntityQuery({
|
||||||
queryHook: useFindManyQuery,
|
|
||||||
filters: [
|
filters: [
|
||||||
{
|
{
|
||||||
fieldNames: searchQuery?.computeFilterFields?.('company') ?? [],
|
fieldNames: searchQuery?.computeFilterFields?.('company') ?? [],
|
||||||
@ -127,7 +118,7 @@ export const OpportunityPicker = ({
|
|||||||
/>
|
/>
|
||||||
<DropdownMenuSeparator />
|
<DropdownMenuSeparator />
|
||||||
<RecoilScope>
|
<RecoilScope>
|
||||||
<SingleEntitySelectBase
|
<SingleEntitySelectMenuItems
|
||||||
entitiesToSelect={filteredSearchEntityResults.entitiesToSelect}
|
entitiesToSelect={filteredSearchEntityResults.entitiesToSelect}
|
||||||
loading={filteredSearchEntityResults.loading}
|
loading={filteredSearchEntityResults.loading}
|
||||||
onCancel={onCancel}
|
onCancel={onCancel}
|
||||||
|
|||||||
@ -95,7 +95,7 @@ export const usePersistField = () => {
|
|||||||
where: { id: entityId },
|
where: { id: entityId },
|
||||||
updateOneRecordInput: {
|
updateOneRecordInput: {
|
||||||
[`${fieldName}Id`]: valueToPersist?.id ?? null,
|
[`${fieldName}Id`]: valueToPersist?.id ?? null,
|
||||||
[`${fieldName}`]: valueToPersist ?? null,
|
[fieldName]: valueToPersist ?? null,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@ -0,0 +1,24 @@
|
|||||||
|
import { useRecoilCallback } from 'recoil';
|
||||||
|
|
||||||
|
import { entityFieldsFamilySelector } from '@/object-record/field/states/selectors/entityFieldsFamilySelector';
|
||||||
|
import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
|
||||||
|
|
||||||
|
export const useUpsertRecordFieldFromState = () =>
|
||||||
|
useRecoilCallback(
|
||||||
|
({ set }) =>
|
||||||
|
<T extends { id: string }, F extends keyof T>({
|
||||||
|
record,
|
||||||
|
fieldName,
|
||||||
|
}: {
|
||||||
|
record: T;
|
||||||
|
fieldName: F extends string ? F : never;
|
||||||
|
}) =>
|
||||||
|
set(
|
||||||
|
entityFieldsFamilySelector({ entityId: record.id, fieldName }),
|
||||||
|
(previousField) =>
|
||||||
|
isDeeplyEqual(previousField, record[fieldName])
|
||||||
|
? previousField
|
||||||
|
: record[fieldName],
|
||||||
|
),
|
||||||
|
[],
|
||||||
|
);
|
||||||
@ -6,15 +6,10 @@ import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
|
|||||||
// TODO: refactor with scoped state later
|
// TODO: refactor with scoped state later
|
||||||
export const useUpsertRecordFromState = () =>
|
export const useUpsertRecordFromState = () =>
|
||||||
useRecoilCallback(
|
useRecoilCallback(
|
||||||
({ set, snapshot }) =>
|
({ set }) =>
|
||||||
<T extends { id: string }>(entity: T) => {
|
<T extends { id: string }>(record: T) =>
|
||||||
const currentEntity = snapshot
|
set(entityFieldsFamilyState(record.id), (previousRecord) =>
|
||||||
.getLoadable(entityFieldsFamilyState(entity.id))
|
isDeeplyEqual(previousRecord, record) ? previousRecord : record,
|
||||||
.valueOrThrow();
|
),
|
||||||
|
|
||||||
if (!isDeeplyEqual(currentEntity, entity)) {
|
|
||||||
set(entityFieldsFamilyState(entity.id), entity);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
[],
|
[],
|
||||||
);
|
);
|
||||||
|
|||||||
@ -2,7 +2,7 @@ import { useEffect, useState } from 'react';
|
|||||||
|
|
||||||
import { useFilterDropdown } from '@/object-record/object-filter-dropdown/hooks/useFilterDropdown';
|
import { useFilterDropdown } from '@/object-record/object-filter-dropdown/hooks/useFilterDropdown';
|
||||||
import { EntitiesForMultipleEntitySelect } from '@/object-record/relation-picker/components/MultipleEntitySelect';
|
import { EntitiesForMultipleEntitySelect } from '@/object-record/relation-picker/components/MultipleEntitySelect';
|
||||||
import { SingleEntitySelectBase } from '@/object-record/relation-picker/components/SingleEntitySelectBase';
|
import { SingleEntitySelectMenuItems } from '@/object-record/relation-picker/components/SingleEntitySelectMenuItems';
|
||||||
import { EntityForSelect } from '@/object-record/relation-picker/types/EntityForSelect';
|
import { EntityForSelect } from '@/object-record/relation-picker/types/EntityForSelect';
|
||||||
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
||||||
import { ViewFilterOperand } from '@/views/types/ViewFilterOperand';
|
import { ViewFilterOperand } from '@/views/types/ViewFilterOperand';
|
||||||
@ -99,18 +99,16 @@ export const ObjectFilterDropdownEntitySearchSelect = ({
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<SingleEntitySelectMenuItems
|
||||||
<SingleEntitySelectBase
|
entitiesToSelect={entitiesForSelect.entitiesToSelect}
|
||||||
entitiesToSelect={entitiesForSelect.entitiesToSelect}
|
selectedEntity={entitiesForSelect.selectedEntities[0]}
|
||||||
selectedEntity={entitiesForSelect.selectedEntities[0]}
|
loading={entitiesForSelect.loading}
|
||||||
loading={entitiesForSelect.loading}
|
onEntitySelected={handleRecordSelected}
|
||||||
onEntitySelected={handleRecordSelected}
|
SelectAllIcon={filterDefinitionUsedInDropdown?.SelectAllIcon}
|
||||||
SelectAllIcon={filterDefinitionUsedInDropdown?.SelectAllIcon}
|
selectAllLabel={filterDefinitionUsedInDropdown?.selectAllLabel}
|
||||||
selectAllLabel={filterDefinitionUsedInDropdown?.selectAllLabel}
|
isAllEntitySelected={isAllEntitySelected}
|
||||||
isAllEntitySelected={isAllEntitySelected}
|
isAllEntitySelectShown={isAllEntitySelectShown}
|
||||||
isAllEntitySelectShown={isAllEntitySelectShown}
|
onAllEntitySelected={handleAllEntitySelectClick}
|
||||||
onAllEntitySelected={handleAllEntitySelectClick}
|
/>
|
||||||
/>
|
|
||||||
</>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,31 +1,73 @@
|
|||||||
import { useContext, useEffect, useMemo } from 'react';
|
import { useCallback, useContext, useEffect, useMemo } from 'react';
|
||||||
|
import { css } from '@emotion/react';
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
import { useRecoilValue } from 'recoil';
|
import { useRecoilValue } from 'recoil';
|
||||||
|
|
||||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||||
import { FieldContext } from '@/object-record/field/contexts/FieldContext';
|
import { FieldContext } from '@/object-record/field/contexts/FieldContext';
|
||||||
|
import { usePersistField } from '@/object-record/field/hooks/usePersistField';
|
||||||
|
import { entityFieldsFamilyState } from '@/object-record/field/states/entityFieldsFamilyState';
|
||||||
import { entityFieldsFamilySelector } from '@/object-record/field/states/selectors/entityFieldsFamilySelector';
|
import { entityFieldsFamilySelector } from '@/object-record/field/states/selectors/entityFieldsFamilySelector';
|
||||||
import { FieldRelationMetadata } from '@/object-record/field/types/FieldMetadata';
|
import { FieldRelationMetadata } from '@/object-record/field/types/FieldMetadata';
|
||||||
import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords';
|
import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords';
|
||||||
import { useFindOneRecord } from '@/object-record/hooks/useFindOneRecord';
|
import { useFindOneRecord } from '@/object-record/hooks/useFindOneRecord';
|
||||||
|
import { useUpdateOneRecord } from '@/object-record/hooks/useUpdateOneRecord';
|
||||||
import { useUpsertRecordFromState } from '@/object-record/hooks/useUpsertRecordFromState';
|
import { useUpsertRecordFromState } from '@/object-record/hooks/useUpsertRecordFromState';
|
||||||
import { RecordRelationFieldCardContent } from '@/object-record/record-relation-card/components/RecordRelationFieldCardContent';
|
import { RecordRelationFieldCardContent } from '@/object-record/record-relation-card/components/RecordRelationFieldCardContent';
|
||||||
|
import { SingleEntitySelectMenuItemsWithSearch } from '@/object-record/relation-picker/components/SingleEntitySelectMenuItemsWithSearch';
|
||||||
|
import { useRelationPicker } from '@/object-record/relation-picker/hooks/useRelationPicker';
|
||||||
|
import { EntityForSelect } from '@/object-record/relation-picker/types/EntityForSelect';
|
||||||
|
import { useFilteredSearchEntityQuery } from '@/search/hooks/useFilteredSearchEntityQuery';
|
||||||
|
import { IconForbid, IconPlus } from '@/ui/display/icon';
|
||||||
|
import { LightIconButton } from '@/ui/input/button/components/LightIconButton';
|
||||||
import { Card } from '@/ui/layout/card/components/Card';
|
import { Card } from '@/ui/layout/card/components/Card';
|
||||||
|
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 { Section } from '@/ui/layout/section/components/Section';
|
import { Section } from '@/ui/layout/section/components/Section';
|
||||||
|
|
||||||
|
const StyledAddDropdown = styled(Dropdown)`
|
||||||
|
margin-left: auto;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const StyledHeader = styled.header<{ isDropdownOpen?: boolean }>`
|
||||||
|
align-items: center;
|
||||||
|
display: flex;
|
||||||
|
margin-bottom: ${({ theme }) => theme.spacing(2)};
|
||||||
|
|
||||||
|
${({ isDropdownOpen, theme }) =>
|
||||||
|
isDropdownOpen
|
||||||
|
? ''
|
||||||
|
: css`
|
||||||
|
.displayOnHover {
|
||||||
|
opacity: 0;
|
||||||
|
pointer-events: none;
|
||||||
|
transition: opacity ${theme.animation.duration.instant}s ease;
|
||||||
|
}
|
||||||
|
`}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
.displayOnHover {
|
||||||
|
opacity: 1;
|
||||||
|
pointer-events: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
const StyledTitle = styled.div`
|
const StyledTitle = styled.div`
|
||||||
font-weight: ${({ theme }) => theme.font.weight.medium};
|
font-weight: ${({ theme }) => theme.font.weight.medium};
|
||||||
margin-bottom: ${({ theme }) => theme.spacing(2)};
|
|
||||||
padding: ${({ theme }) => theme.spacing(0, 1)};
|
padding: ${({ theme }) => theme.spacing(0, 1)};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const RecordRelationFieldCardSection = () => {
|
export const RecordRelationFieldCardSection = () => {
|
||||||
const { entityId, fieldDefinition } = useContext(FieldContext);
|
const { entityId, fieldDefinition } = useContext(FieldContext);
|
||||||
const {
|
const {
|
||||||
|
fieldName,
|
||||||
relationFieldMetadataId,
|
relationFieldMetadataId,
|
||||||
relationObjectMetadataNameSingular,
|
relationObjectMetadataNameSingular,
|
||||||
relationType,
|
relationType,
|
||||||
} = fieldDefinition.metadata as FieldRelationMetadata;
|
} = fieldDefinition.metadata as FieldRelationMetadata;
|
||||||
|
const record = useRecoilValue(entityFieldsFamilyState(entityId));
|
||||||
|
|
||||||
const {
|
const {
|
||||||
labelIdentifierFieldMetadata: relationLabelIdentifierFieldMetadata,
|
labelIdentifierFieldMetadata: relationLabelIdentifierFieldMetadata,
|
||||||
@ -40,16 +82,11 @@ export const RecordRelationFieldCardSection = () => {
|
|||||||
|
|
||||||
const fieldValue = useRecoilValue<
|
const fieldValue = useRecoilValue<
|
||||||
({ id: string } & Record<string, any>) | null
|
({ id: string } & Record<string, any>) | null
|
||||||
>(
|
>(entityFieldsFamilySelector({ entityId, fieldName }));
|
||||||
entityFieldsFamilySelector({
|
|
||||||
entityId,
|
|
||||||
fieldName: fieldDefinition.metadata.fieldName,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
const isToOneObject = relationType === 'TO_ONE_OBJECT';
|
const isToOneObject = relationType === 'TO_ONE_OBJECT';
|
||||||
|
|
||||||
const { record: recordFromFieldValue } = useFindOneRecord({
|
const { record: relationRecordFromFieldValue } = useFindOneRecord({
|
||||||
objectNameSingular: relationObjectMetadataNameSingular,
|
objectNameSingular: relationObjectMetadataNameSingular,
|
||||||
objectRecordId: fieldValue?.id,
|
objectRecordId: fieldValue?.id,
|
||||||
skip: !relationLabelIdentifierFieldMetadata || !isToOneObject,
|
skip: !relationLabelIdentifierFieldMetadata || !isToOneObject,
|
||||||
@ -58,9 +95,8 @@ export const RecordRelationFieldCardSection = () => {
|
|||||||
// ONE_TO_MANY records cannot be retrieved from the field value,
|
// ONE_TO_MANY records cannot be retrieved from the field value,
|
||||||
// as the record's field is an empty "Connection" object.
|
// as the record's field is an empty "Connection" object.
|
||||||
// TODO: maybe the backend could return an array of related records instead?
|
// TODO: maybe the backend could return an array of related records instead?
|
||||||
const { records } = useFindManyRecords({
|
const { records: relationRecordsFromQuery } = useFindManyRecords({
|
||||||
objectNameSingular: relationObjectMetadataNameSingular,
|
objectNameSingular: relationObjectMetadataNameSingular,
|
||||||
limit: 5,
|
|
||||||
filter: {
|
filter: {
|
||||||
// TODO: this won't work for MANY_TO_MANY relations.
|
// TODO: this won't work for MANY_TO_MANY relations.
|
||||||
[`${relationFieldMetadataItem?.name}Id`]: {
|
[`${relationFieldMetadataItem?.name}Id`]: {
|
||||||
@ -74,28 +110,120 @@ export const RecordRelationFieldCardSection = () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const relationRecords = useMemo(
|
const relationRecords = useMemo(
|
||||||
() => (recordFromFieldValue ? [recordFromFieldValue] : records),
|
() =>
|
||||||
[recordFromFieldValue, records],
|
relationRecordFromFieldValue
|
||||||
|
? [relationRecordFromFieldValue]
|
||||||
|
: relationRecordsFromQuery,
|
||||||
|
[relationRecordFromFieldValue, relationRecordsFromQuery],
|
||||||
|
);
|
||||||
|
const relationRecordIds = useMemo(
|
||||||
|
() => relationRecords.map(({ id }) => id),
|
||||||
|
[relationRecords],
|
||||||
);
|
);
|
||||||
|
|
||||||
const upsertRecordFromState = useUpsertRecordFromState();
|
const upsertRecordFromState = useUpsertRecordFromState();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!relationRecords.length) return;
|
|
||||||
|
|
||||||
relationRecords.forEach((relationRecord) =>
|
relationRecords.forEach((relationRecord) =>
|
||||||
upsertRecordFromState(relationRecord),
|
upsertRecordFromState(relationRecord),
|
||||||
);
|
);
|
||||||
}, [relationRecords, upsertRecordFromState]);
|
}, [relationRecords, upsertRecordFromState]);
|
||||||
|
|
||||||
|
const dropdownScopeId = `record-field-card-relation-picker-${fieldDefinition.label}`;
|
||||||
|
|
||||||
|
const { closeDropdown, isDropdownOpen } = useDropdown(dropdownScopeId);
|
||||||
|
|
||||||
|
const {
|
||||||
|
identifiersMapper,
|
||||||
|
relationPickerSearchFilter,
|
||||||
|
searchQuery,
|
||||||
|
setRelationPickerSearchFilter,
|
||||||
|
} = useRelationPicker();
|
||||||
|
|
||||||
|
const entities = useFilteredSearchEntityQuery({
|
||||||
|
filters: [
|
||||||
|
{
|
||||||
|
fieldNames:
|
||||||
|
searchQuery?.computeFilterFields?.(
|
||||||
|
relationObjectMetadataNameSingular,
|
||||||
|
) ?? [],
|
||||||
|
filter: relationPickerSearchFilter,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
orderByField: 'createdAt',
|
||||||
|
mappingFunction: (recordToMap: any) =>
|
||||||
|
identifiersMapper?.(recordToMap, relationObjectMetadataNameSingular),
|
||||||
|
selectedIds: relationRecordIds,
|
||||||
|
excludeEntityIds: relationRecordIds,
|
||||||
|
objectNameSingular: relationObjectMetadataNameSingular,
|
||||||
|
});
|
||||||
|
|
||||||
|
const handleCloseRelationPickerDropdown = useCallback(() => {
|
||||||
|
setRelationPickerSearchFilter('');
|
||||||
|
}, [setRelationPickerSearchFilter]);
|
||||||
|
|
||||||
|
const persistField = usePersistField();
|
||||||
|
const { updateOneRecord } = useUpdateOneRecord({
|
||||||
|
objectNameSingular: relationObjectMetadataNameSingular,
|
||||||
|
});
|
||||||
|
|
||||||
|
const handleRelationPickerEntitySelected = (
|
||||||
|
selectedRelationEntity?: EntityForSelect,
|
||||||
|
) => {
|
||||||
|
closeDropdown();
|
||||||
|
|
||||||
|
if (!selectedRelationEntity?.id) return;
|
||||||
|
|
||||||
|
if (isToOneObject) {
|
||||||
|
persistField(selectedRelationEntity.record);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!relationFieldMetadataItem?.name) return;
|
||||||
|
|
||||||
|
updateOneRecord({
|
||||||
|
idToUpdate: selectedRelationEntity.id,
|
||||||
|
updateOneRecordInput: {
|
||||||
|
[`${relationFieldMetadataItem.name}Id`]: entityId,
|
||||||
|
[relationFieldMetadataItem.name]: record,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
if (!relationLabelIdentifierFieldMetadata) return null;
|
if (!relationLabelIdentifierFieldMetadata) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Section>
|
<Section>
|
||||||
<StyledTitle>{fieldDefinition.label}</StyledTitle>
|
<StyledHeader isDropdownOpen={isDropdownOpen}>
|
||||||
|
<StyledTitle>{fieldDefinition.label}</StyledTitle>
|
||||||
|
<DropdownScope dropdownScopeId={dropdownScopeId}>
|
||||||
|
<StyledAddDropdown
|
||||||
|
dropdownPlacement="right-start"
|
||||||
|
onClose={handleCloseRelationPickerDropdown}
|
||||||
|
clickableComponent={
|
||||||
|
<LightIconButton
|
||||||
|
className="displayOnHover"
|
||||||
|
Icon={IconPlus}
|
||||||
|
accent="tertiary"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
dropdownComponents={
|
||||||
|
<SingleEntitySelectMenuItemsWithSearch
|
||||||
|
EmptyIcon={IconForbid}
|
||||||
|
entitiesToSelect={entities.entitiesToSelect}
|
||||||
|
loading={entities.loading}
|
||||||
|
onEntitySelected={handleRelationPickerEntitySelected}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
dropdownHotkeyScope={{
|
||||||
|
scope: dropdownScopeId,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</DropdownScope>
|
||||||
|
</StyledHeader>
|
||||||
{!!relationRecords.length && (
|
{!!relationRecords.length && (
|
||||||
<Card>
|
<Card>
|
||||||
{relationRecords.map((relationRecord, index) => (
|
{relationRecords.slice(0, 5).map((relationRecord, index) => (
|
||||||
<RecordRelationFieldCardContent
|
<RecordRelationFieldCardContent
|
||||||
key={`${relationRecord.id}${relationLabelIdentifierFieldMetadata?.id}`}
|
key={`${relationRecord.id}${relationLabelIdentifierFieldMetadata?.id}`}
|
||||||
divider={index < relationRecords.length - 1}
|
divider={index < relationRecords.length - 1}
|
||||||
|
|||||||
@ -1,7 +1,5 @@
|
|||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
import { useQuery } from '@apollo/client';
|
|
||||||
|
|
||||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
|
||||||
import { useObjectNameSingularFromPlural } from '@/object-metadata/hooks/useObjectNameSingularFromPlural';
|
import { useObjectNameSingularFromPlural } from '@/object-metadata/hooks/useObjectNameSingularFromPlural';
|
||||||
import { FieldDefinition } from '@/object-record/field/types/FieldDefinition';
|
import { FieldDefinition } from '@/object-record/field/types/FieldDefinition';
|
||||||
import { FieldRelationMetadata } from '@/object-record/field/types/FieldMetadata';
|
import { FieldRelationMetadata } from '@/object-record/field/types/FieldMetadata';
|
||||||
@ -13,7 +11,7 @@ import { IconForbid } from '@/ui/display/icon';
|
|||||||
|
|
||||||
export type RelationPickerProps = {
|
export type RelationPickerProps = {
|
||||||
recordId?: string;
|
recordId?: string;
|
||||||
onSubmit: (newUser: EntityForSelect | null) => void;
|
onSubmit: (selectedEntity: EntityForSelect | null) => void;
|
||||||
onCancel?: () => void;
|
onCancel?: () => void;
|
||||||
width?: number;
|
width?: number;
|
||||||
excludeRecordIds?: string[];
|
excludeRecordIds?: string[];
|
||||||
@ -30,32 +28,24 @@ export const RelationPicker = ({
|
|||||||
initialSearchFilter,
|
initialSearchFilter,
|
||||||
fieldDefinition,
|
fieldDefinition,
|
||||||
}: RelationPickerProps) => {
|
}: RelationPickerProps) => {
|
||||||
const { relationPickerSearchFilter, setRelationPickerSearchFilter } =
|
const {
|
||||||
useRelationPicker();
|
relationPickerSearchFilter,
|
||||||
|
setRelationPickerSearchFilter,
|
||||||
|
identifiersMapper,
|
||||||
|
searchQuery,
|
||||||
|
} = useRelationPicker();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setRelationPickerSearchFilter(initialSearchFilter ?? '');
|
setRelationPickerSearchFilter(initialSearchFilter ?? '');
|
||||||
}, [initialSearchFilter, setRelationPickerSearchFilter]);
|
}, [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 } =
|
const { objectNameSingular: relationObjectNameSingular } =
|
||||||
useObjectNameSingularFromPlural({
|
useObjectNameSingularFromPlural({
|
||||||
objectNamePlural:
|
objectNamePlural:
|
||||||
fieldDefinition.metadata.relationObjectMetadataNamePlural,
|
fieldDefinition.metadata.relationObjectMetadataNamePlural,
|
||||||
});
|
});
|
||||||
|
|
||||||
const records = useFilteredSearchEntityQuery({
|
const entities = useFilteredSearchEntityQuery({
|
||||||
queryHook: useFindManyQuery,
|
|
||||||
filters: [
|
filters: [
|
||||||
{
|
{
|
||||||
fieldNames:
|
fieldNames:
|
||||||
@ -76,19 +66,18 @@ export const RelationPicker = ({
|
|||||||
objectNameSingular: relationObjectNameSingular,
|
objectNameSingular: relationObjectNameSingular,
|
||||||
});
|
});
|
||||||
|
|
||||||
const handleEntitySelected = async (selectedUser: any | null | undefined) => {
|
const handleEntitySelected = (selectedEntity: any | null | undefined) =>
|
||||||
onSubmit(selectedUser ?? null);
|
onSubmit(selectedEntity ?? null);
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SingleEntitySelect
|
<SingleEntitySelect
|
||||||
EmptyIcon={IconForbid}
|
EmptyIcon={IconForbid}
|
||||||
emptyLabel={'No ' + fieldDefinition.label}
|
emptyLabel={'No ' + fieldDefinition.label}
|
||||||
entitiesToSelect={records.entitiesToSelect}
|
entitiesToSelect={entities.entitiesToSelect}
|
||||||
loading={records.loading}
|
loading={entities.loading}
|
||||||
onCancel={onCancel}
|
onCancel={onCancel}
|
||||||
onEntitySelected={handleEntitySelected}
|
onEntitySelected={handleEntitySelected}
|
||||||
selectedEntity={records.selectedEntities[0]}
|
selectedEntity={entities.selectedEntities[0]}
|
||||||
width={width}
|
width={width}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -1,32 +1,16 @@
|
|||||||
import { useRef } from 'react';
|
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 {
|
import {
|
||||||
SingleEntitySelectBase,
|
SingleEntitySelectMenuItemsWithSearch,
|
||||||
SingleEntitySelectBaseProps,
|
SingleEntitySelectMenuItemsWithSearchProps,
|
||||||
} from './SingleEntitySelectBase';
|
} 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 = {
|
export type SingleEntitySelectProps = {
|
||||||
disableBackgroundBlur?: boolean;
|
disableBackgroundBlur?: boolean;
|
||||||
onCreate?: () => void;
|
|
||||||
width?: number;
|
width?: number;
|
||||||
} & Pick<
|
} & SingleEntitySelectMenuItemsWithSearchProps;
|
||||||
SingleEntitySelectBaseProps,
|
|
||||||
| 'EmptyIcon'
|
|
||||||
| 'emptyLabel'
|
|
||||||
| 'entitiesToSelect'
|
|
||||||
| 'loading'
|
|
||||||
| 'onCancel'
|
|
||||||
| 'onEntitySelected'
|
|
||||||
| 'selectedEntity'
|
|
||||||
>;
|
|
||||||
|
|
||||||
export const SingleEntitySelect = ({
|
export const SingleEntitySelect = ({
|
||||||
EmptyIcon,
|
EmptyIcon,
|
||||||
@ -42,10 +26,6 @@ export const SingleEntitySelect = ({
|
|||||||
}: SingleEntitySelectProps) => {
|
}: SingleEntitySelectProps) => {
|
||||||
const containerRef = useRef<HTMLDivElement>(null);
|
const containerRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
const { searchFilter, handleSearchFilterChange } = useEntitySelectSearch();
|
|
||||||
|
|
||||||
const showCreateButton = isDefined(onCreate) && searchFilter !== '';
|
|
||||||
|
|
||||||
useListenClickOutside({
|
useListenClickOutside({
|
||||||
refs: [containerRef],
|
refs: [containerRef],
|
||||||
callback: (event) => {
|
callback: (event) => {
|
||||||
@ -62,13 +42,7 @@ export const SingleEntitySelect = ({
|
|||||||
width={width}
|
width={width}
|
||||||
data-select-disable
|
data-select-disable
|
||||||
>
|
>
|
||||||
<DropdownMenuSearchInput
|
<SingleEntitySelectMenuItemsWithSearch
|
||||||
value={searchFilter}
|
|
||||||
onChange={handleSearchFilterChange}
|
|
||||||
autoFocus
|
|
||||||
/>
|
|
||||||
<DropdownMenuSeparator />
|
|
||||||
<SingleEntitySelectBase
|
|
||||||
{...{
|
{...{
|
||||||
EmptyIcon,
|
EmptyIcon,
|
||||||
emptyLabel,
|
emptyLabel,
|
||||||
@ -78,7 +52,6 @@ export const SingleEntitySelect = ({
|
|||||||
onCreate,
|
onCreate,
|
||||||
onEntitySelected,
|
onEntitySelected,
|
||||||
selectedEntity,
|
selectedEntity,
|
||||||
showCreateButton,
|
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</DropdownMenu>
|
</DropdownMenu>
|
||||||
|
|||||||
@ -5,6 +5,8 @@ import { Key } from 'ts-key-enum';
|
|||||||
import { SelectableMenuItemSelect } from '@/object-record/relation-picker/components/SelectableMenuItemSelect';
|
import { SelectableMenuItemSelect } from '@/object-record/relation-picker/components/SelectableMenuItemSelect';
|
||||||
import { IconPlus } from '@/ui/display/icon';
|
import { IconPlus } from '@/ui/display/icon';
|
||||||
import { IconComponent } from '@/ui/display/icon/types/IconComponent';
|
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 { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||||
import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
|
import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
|
||||||
import { SelectableList } from '@/ui/layout/selectable-list/components/SelectableList';
|
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 { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
|
||||||
import { assertNotNull } from '~/utils/assert';
|
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 { EntityForSelect } from '../types/EntityForSelect';
|
||||||
import { RelationPickerHotkeyScope } from '../types/RelationPickerHotkeyScope';
|
import { RelationPickerHotkeyScope } from '../types/RelationPickerHotkeyScope';
|
||||||
|
|
||||||
export type SingleEntitySelectBaseProps = {
|
export type SingleEntitySelectMenuItemsProps = {
|
||||||
EmptyIcon?: IconComponent;
|
EmptyIcon?: IconComponent;
|
||||||
emptyLabel?: string;
|
emptyLabel?: string;
|
||||||
entitiesToSelect: EntityForSelect[];
|
entitiesToSelect: EntityForSelect[];
|
||||||
@ -35,7 +35,7 @@ export type SingleEntitySelectBaseProps = {
|
|||||||
onAllEntitySelected?: () => void;
|
onAllEntitySelected?: () => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const SingleEntitySelectBase = ({
|
export const SingleEntitySelectMenuItems = ({
|
||||||
EmptyIcon,
|
EmptyIcon,
|
||||||
emptyLabel,
|
emptyLabel,
|
||||||
entitiesToSelect,
|
entitiesToSelect,
|
||||||
@ -50,7 +50,7 @@ export const SingleEntitySelectBase = ({
|
|||||||
isAllEntitySelected,
|
isAllEntitySelected,
|
||||||
isAllEntitySelectShown,
|
isAllEntitySelectShown,
|
||||||
onAllEntitySelected,
|
onAllEntitySelected,
|
||||||
}: SingleEntitySelectBaseProps) => {
|
}: SingleEntitySelectMenuItemsProps) => {
|
||||||
const containerRef = useRef<HTMLDivElement>(null);
|
const containerRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
const entitiesInDropdown = [selectedEntity, ...entitiesToSelect].filter(
|
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,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
@ -1,11 +1,9 @@
|
|||||||
import { QueryHookOptions, QueryResult } from '@apollo/client';
|
|
||||||
import { isNonEmptyString } from '@sniptt/guards';
|
import { isNonEmptyString } from '@sniptt/guards';
|
||||||
|
|
||||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
|
||||||
import { OrderBy } from '@/object-metadata/types/OrderBy';
|
import { OrderBy } from '@/object-metadata/types/OrderBy';
|
||||||
|
import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords';
|
||||||
import { EntitiesForMultipleEntitySelect } from '@/object-record/relation-picker/components/MultipleEntitySelect';
|
import { EntitiesForMultipleEntitySelect } from '@/object-record/relation-picker/components/MultipleEntitySelect';
|
||||||
import { EntityForSelect } from '@/object-record/relation-picker/types/EntityForSelect';
|
import { EntityForSelect } from '@/object-record/relation-picker/types/EntityForSelect';
|
||||||
import { mapPaginatedRecordsToRecords } from '@/object-record/utils/mapPaginatedRecordsToRecords';
|
|
||||||
import { assertNotNull } from '~/utils/assert';
|
import { assertNotNull } from '~/utils/assert';
|
||||||
import { isDefined } from '~/utils/isDefined';
|
import { isDefined } from '~/utils/isDefined';
|
||||||
|
|
||||||
@ -16,9 +14,7 @@ export const DEFAULT_SEARCH_REQUEST_LIMIT = 60;
|
|||||||
// TODO: use this for all search queries, because we need selectedEntities and entitiesToSelect each time we want to search
|
// TODO: use this for all search queries, because we need selectedEntities and entitiesToSelect each time we want to search
|
||||||
// Filtered entities to select are
|
// Filtered entities to select are
|
||||||
|
|
||||||
// TODO: replace query hooks by useFindManyRecords
|
|
||||||
export const useFilteredSearchEntityQuery = ({
|
export const useFilteredSearchEntityQuery = ({
|
||||||
queryHook,
|
|
||||||
orderByField,
|
orderByField,
|
||||||
filters,
|
filters,
|
||||||
sortOrder = 'AscNullsLast',
|
sortOrder = 'AscNullsLast',
|
||||||
@ -28,9 +24,6 @@ export const useFilteredSearchEntityQuery = ({
|
|||||||
excludeEntityIds = [],
|
excludeEntityIds = [],
|
||||||
objectNameSingular,
|
objectNameSingular,
|
||||||
}: {
|
}: {
|
||||||
queryHook: (
|
|
||||||
queryOptions?: QueryHookOptions<any, any>,
|
|
||||||
) => QueryResult<any, any>;
|
|
||||||
orderByField: string;
|
orderByField: string;
|
||||||
filters: SearchFilter[];
|
filters: SearchFilter[];
|
||||||
sortOrder?: OrderBy;
|
sortOrder?: OrderBy;
|
||||||
@ -40,22 +33,11 @@ export const useFilteredSearchEntityQuery = ({
|
|||||||
excludeEntityIds?: string[];
|
excludeEntityIds?: string[];
|
||||||
objectNameSingular: string;
|
objectNameSingular: string;
|
||||||
}): EntitiesForMultipleEntitySelect<EntityForSelect> => {
|
}): EntitiesForMultipleEntitySelect<EntityForSelect> => {
|
||||||
const { objectMetadataItem } = useObjectMetadataItem({
|
const { loading: selectedRecordsLoading, records: selectedRecords } =
|
||||||
objectNameSingular,
|
useFindManyRecords({
|
||||||
});
|
objectNameSingular,
|
||||||
|
filter: { id: { in: selectedIds } },
|
||||||
const { loading: selectedEntitiesLoading, data: selectedEntitiesData } =
|
orderBy: { [orderByField]: sortOrder },
|
||||||
queryHook({
|
|
||||||
variables: {
|
|
||||||
filter: {
|
|
||||||
id: {
|
|
||||||
in: selectedIds,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
orderBy: {
|
|
||||||
[orderByField]: sortOrder,
|
|
||||||
},
|
|
||||||
} as any,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const searchFilter = filters
|
const searchFilter = filters
|
||||||
@ -90,74 +72,40 @@ export const useFilteredSearchEntityQuery = ({
|
|||||||
.filter(isDefined);
|
.filter(isDefined);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
loading: filteredSelectedEntitiesLoading,
|
loading: filteredSelectedRecordsLoading,
|
||||||
data: filteredSelectedEntitiesData,
|
records: filteredSelectedRecords,
|
||||||
} = queryHook({
|
} = useFindManyRecords({
|
||||||
variables: {
|
objectNameSingular,
|
||||||
filter: {
|
filter: { and: [{ and: searchFilter }, { id: { in: selectedIds } }] },
|
||||||
and: [
|
orderBy: { [orderByField]: sortOrder },
|
||||||
{
|
|
||||||
and: searchFilter,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: {
|
|
||||||
in: selectedIds,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
orderBy: {
|
|
||||||
[orderByField]: sortOrder,
|
|
||||||
},
|
|
||||||
} as any,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const { loading: entitiesToSelectLoading, data: entitiesToSelectData } =
|
const { loading: recordsToSelectLoading, records: recordsToSelect } =
|
||||||
queryHook({
|
useFindManyRecords({
|
||||||
variables: {
|
objectNameSingular,
|
||||||
filter: {
|
filter: {
|
||||||
and: [
|
and: [
|
||||||
{
|
{ and: searchFilter },
|
||||||
and: searchFilter,
|
{ not: { id: { in: [...selectedIds, ...excludeEntityIds] } } },
|
||||||
},
|
],
|
||||||
{
|
},
|
||||||
not: {
|
limit: limit ?? DEFAULT_SEARCH_REQUEST_LIMIT,
|
||||||
id: {
|
orderBy: { [orderByField]: sortOrder },
|
||||||
in: [...selectedIds, ...excludeEntityIds],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
limit: limit ?? DEFAULT_SEARCH_REQUEST_LIMIT,
|
|
||||||
orderBy: {
|
|
||||||
[orderByField]: sortOrder,
|
|
||||||
},
|
|
||||||
} as any,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
selectedEntities: mapPaginatedRecordsToRecords({
|
selectedEntities: selectedRecords
|
||||||
objectNamePlural: objectMetadataItem.namePlural,
|
|
||||||
pagedRecords: selectedEntitiesData,
|
|
||||||
})
|
|
||||||
.map(mappingFunction)
|
.map(mappingFunction)
|
||||||
.filter(assertNotNull),
|
.filter(assertNotNull),
|
||||||
filteredSelectedEntities: mapPaginatedRecordsToRecords({
|
filteredSelectedEntities: filteredSelectedRecords
|
||||||
objectNamePlural: objectMetadataItem.namePlural,
|
|
||||||
pagedRecords: filteredSelectedEntitiesData,
|
|
||||||
})
|
|
||||||
.map(mappingFunction)
|
.map(mappingFunction)
|
||||||
.filter(assertNotNull),
|
.filter(assertNotNull),
|
||||||
entitiesToSelect: mapPaginatedRecordsToRecords({
|
entitiesToSelect: recordsToSelect
|
||||||
objectNamePlural: objectMetadataItem.namePlural,
|
|
||||||
pagedRecords: entitiesToSelectData,
|
|
||||||
})
|
|
||||||
.map(mappingFunction)
|
.map(mappingFunction)
|
||||||
.filter(assertNotNull),
|
.filter(assertNotNull),
|
||||||
loading:
|
loading:
|
||||||
entitiesToSelectLoading ||
|
recordsToSelectLoading ||
|
||||||
filteredSelectedEntitiesLoading ||
|
filteredSelectedRecordsLoading ||
|
||||||
selectedEntitiesLoading,
|
selectedRecordsLoading,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user