Picker and MultiSelect fixes (#2883)

* Fixed orderBy bug

* Fixed gitch select multiple record filter

* Fixed RelationPicker search

* Fixed OrderBy type
This commit is contained in:
Lucas Bordeau
2023-12-08 17:42:40 +01:00
committed by GitHub
parent 9b7d7b29ed
commit 52859e18ed
16 changed files with 103 additions and 62 deletions

View File

@ -19,7 +19,7 @@ export const useNotes = (entity: ActivityTargetableEntity) => {
}; };
const orderBy = { const orderBy = {
createdAt: 'AscNullsFirst', createdAt: 'AscNullsFirst',
}; } as any; // TODO: finish typing
const { records: notes } = useFindManyRecords({ const { records: notes } = useFindManyRecords({
skip: !activityTargets?.length, skip: !activityTargets?.length,

View File

@ -0,0 +1,14 @@
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
import { OrderBy } from '@/object-metadata/types/OrderBy';
import { OrderByField } from '@/object-metadata/types/OrderByField';
import { getObjectOrderByField } from '@/object-metadata/utils/getObjectOrderByField';
export const useGetObjectOrderByField = ({
objectMetadataItem,
}: {
objectMetadataItem: ObjectMetadataItem;
}) => {
return (orderBy: OrderBy): OrderByField => {
return getObjectOrderByField(objectMetadataItem, orderBy);
};
};

View File

@ -1,6 +1,7 @@
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
import { ObjectRecordIdentifier } from '@/object-record/types/ObjectRecordIdentifier'; import { ObjectRecordIdentifier } from '@/object-record/types/ObjectRecordIdentifier';
import { FieldMetadataType } from '~/generated-metadata/graphql';
import { getLogoUrlFromDomainName } from '~/utils'; import { getLogoUrlFromDomainName } from '~/utils';
export const useMapToObjectRecordIdentifier = ({ export const useMapToObjectRecordIdentifier = ({
@ -10,17 +11,6 @@ export const useMapToObjectRecordIdentifier = ({
}) => { }) => {
return (record: any): ObjectRecordIdentifier => { return (record: any): ObjectRecordIdentifier => {
switch (objectMetadataItem.nameSingular) { switch (objectMetadataItem.nameSingular) {
case CoreObjectNameSingular.WorkspaceMember:
case CoreObjectNameSingular.Person:
return {
id: record.id,
name:
(record.name?.firstName ?? '') +
' ' +
(record.name?.lastName ?? ''),
avatarUrl: record.avatarUrl,
avatarType: 'rounded',
};
case CoreObjectNameSingular.Opportunity: case CoreObjectNameSingular.Opportunity:
return { return {
id: record.id, id: record.id,
@ -36,9 +26,20 @@ export const useMapToObjectRecordIdentifier = ({
field.name === 'name', field.name === 'name',
); );
const labelIdentifierFieldValue = labelIdentifierFieldMetadata let labelIdentifierFieldValue = '';
? record[labelIdentifierFieldMetadata.name]
: null; switch (labelIdentifierFieldMetadata?.type) {
case FieldMetadataType.FullName: {
labelIdentifierFieldValue = `${record.name?.firstName ?? ''} ${
record.name?.lastName ?? ''
}`;
break;
}
default:
labelIdentifierFieldValue = labelIdentifierFieldMetadata
? record[labelIdentifierFieldMetadata.name]
: '';
}
const imageIdentifierFieldMetadata = objectMetadataItem.fields.find( const imageIdentifierFieldMetadata = objectMetadataItem.fields.find(
(field) => field.id === objectMetadataItem.imageIdentifierFieldMetadataId, (field) => field.id === objectMetadataItem.imageIdentifierFieldMetadataId,

View File

@ -3,6 +3,7 @@ import { useRecoilValue } from 'recoil';
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState'; import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
import { ObjectMetadataItemNotFoundError } from '@/object-metadata/errors/ObjectMetadataNotFoundError'; import { ObjectMetadataItemNotFoundError } from '@/object-metadata/errors/ObjectMetadataNotFoundError';
import { useGetObjectOrderByField } from '@/object-metadata/hooks/useGetObjectOrderByField';
import { useMapToObjectRecordIdentifier } from '@/object-metadata/hooks/useMapToObjectRecordIdentifier'; import { useMapToObjectRecordIdentifier } from '@/object-metadata/hooks/useMapToObjectRecordIdentifier';
import { objectMetadataItemFamilySelector } from '@/object-metadata/states/objectMetadataItemFamilySelector'; import { objectMetadataItemFamilySelector } from '@/object-metadata/states/objectMetadataItemFamilySelector';
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState'; import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
@ -66,6 +67,10 @@ export const useObjectMetadataItem = (
objectMetadataItem, objectMetadataItem,
}); });
const getObjectOrderByField = useGetObjectOrderByField({
objectMetadataItem,
});
const getRecordFromCache = useGetRecordFromCache({ const getRecordFromCache = useGetRecordFromCache({
objectMetadataItem, objectMetadataItem,
}); });
@ -114,5 +119,6 @@ export const useObjectMetadataItem = (
updateOneRecordMutation, updateOneRecordMutation,
deleteOneRecordMutation, deleteOneRecordMutation,
mapToObjectRecordIdentifier, mapToObjectRecordIdentifier,
getObjectOrderByField,
}; };
}; };

View File

@ -0,0 +1,5 @@
export type OrderBy =
| 'AscNullsLast'
| 'DescNullsLast'
| 'AscNullsFirst'
| 'DescNullsFirst';

View File

@ -0,0 +1,5 @@
import { OrderBy } from '@/object-metadata/types/OrderBy';
export type OrderByField = {
[fieldName: string]: OrderBy | { [subFieldName: string]: OrderBy };
};

View File

@ -0,0 +1,35 @@
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
import { OrderBy } from '@/object-metadata/types/OrderBy';
import { OrderByField } from '@/object-metadata/types/OrderByField';
import { FieldMetadataType } from '~/generated-metadata/graphql';
export const getObjectOrderByField = (
objectMetadataItem: ObjectMetadataItem,
orderBy: OrderBy,
): OrderByField => {
const labelIdentifierFieldMetadata = objectMetadataItem.fields.find(
(field) =>
field.id === objectMetadataItem.labelIdentifierFieldMetadataId ||
field.name === 'name',
);
if (labelIdentifierFieldMetadata) {
switch (labelIdentifierFieldMetadata.type) {
case FieldMetadataType.FullName:
return {
[labelIdentifierFieldMetadata.name]: {
firstName: orderBy,
lastName: orderBy,
},
};
default:
return {
[labelIdentifierFieldMetadata.name]: orderBy,
};
}
} else {
return {
createdAt: orderBy,
};
}
};

View File

@ -8,6 +8,7 @@ import { useOptimisticEffect } from '@/apollo/optimistic-effect/hooks/useOptimis
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState'; import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
import { ObjectMetadataItemIdentifier } from '@/object-metadata/types/ObjectMetadataItemIdentifier'; import { ObjectMetadataItemIdentifier } from '@/object-metadata/types/ObjectMetadataItemIdentifier';
import { OrderByField } from '@/object-metadata/types/OrderByField';
import { getRecordOptimisticEffectDefinition } from '@/object-record/graphql/optimistic-effect-definition/getRecordOptimisticEffectDefinition'; import { getRecordOptimisticEffectDefinition } from '@/object-record/graphql/optimistic-effect-definition/getRecordOptimisticEffectDefinition';
import { filterUniqueRecordEdgesByCursor } from '@/object-record/utils/filterUniqueRecordEdgesByCursor'; import { filterUniqueRecordEdgesByCursor } from '@/object-record/utils/filterUniqueRecordEdgesByCursor';
import { DEFAULT_SEARCH_REQUEST_LIMIT } from '@/search/hooks/useFilteredSearchEntityQuery'; import { DEFAULT_SEARCH_REQUEST_LIMIT } from '@/search/hooks/useFilteredSearchEntityQuery';
@ -36,7 +37,7 @@ export const useFindManyRecords = <
skip, skip,
}: ObjectMetadataItemIdentifier & { }: ObjectMetadataItemIdentifier & {
filter?: any; filter?: any;
orderBy?: any; orderBy?: OrderByField;
limit?: number; limit?: number;
onCompleted?: (data: PaginatedRecordTypeResults<RecordType>) => void; onCompleted?: (data: PaginatedRecordTypeResults<RecordType>) => void;
skip?: boolean; skip?: boolean;

View File

@ -71,7 +71,7 @@ export const useObjectRecordBoard = () => {
skip: !savedPipelineSteps.length, skip: !savedPipelineSteps.length,
objectNameSingular: 'opportunity', objectNameSingular: 'opportunity',
filter: filter, filter: filter,
orderBy: orderBy, orderBy: orderBy as any, // TODO: finish typing
onCompleted: useCallback(() => { onCompleted: useCallback(() => {
setIsBoardLoaded(true); setIsBoardLoaded(true);
}, [setIsBoardLoaded]), }, [setIsBoardLoaded]),

View File

@ -71,7 +71,7 @@ export const useObjectRecordBoard = () => {
skip: !savedPipelineSteps.length, skip: !savedPipelineSteps.length,
objectNameSingular: 'opportunity', objectNameSingular: 'opportunity',
filter: filter, filter: filter,
orderBy: orderBy, orderBy: orderBy as any, // TODO: finish typing
onCompleted: useCallback(() => { onCompleted: useCallback(() => {
setIsBoardLoaded(true); setIsBoardLoaded(true);
}, [setIsBoardLoaded]), }, [setIsBoardLoaded]),

View File

@ -35,10 +35,12 @@ export const useObjectRecordTable = () => {
tableFilters, tableFilters,
foundObjectMetadataItem?.fields ?? [], foundObjectMetadataItem?.fields ?? [],
); );
// TODO: finish typing
const orderBy = turnSortsIntoOrderBy( const orderBy = turnSortsIntoOrderBy(
tableSorts, tableSorts,
foundObjectMetadataItem?.fields ?? [], foundObjectMetadataItem?.fields ?? [],
); ) as any;
const { records, loading, fetchMoreRecords, queryStateIdentifier } = const { records, loading, fetchMoreRecords, queryStateIdentifier } =
useFindManyRecords({ useFindManyRecords({

View File

@ -31,6 +31,10 @@ export const ObjectFilterDropdownRecordSelect = () => {
recordToSelect: SelectableRecord, recordToSelect: SelectableRecord,
newSelectedValue: boolean, newSelectedValue: boolean,
) => { ) => {
if (loading) {
return;
}
const newSelectedRecordIds = newSelectedValue const newSelectedRecordIds = newSelectedValue
? [...objectFilterDropdownSelectedRecordIds, recordToSelect.id] ? [...objectFilterDropdownSelectedRecordIds, recordToSelect.id]
: objectFilterDropdownSelectedRecordIds.filter( : objectFilterDropdownSelectedRecordIds.filter(

View File

@ -1,6 +1,5 @@
import debounce from 'lodash.debounce'; import debounce from 'lodash.debounce';
import { RelationPickerRecoilScopeContext } from '@/object-record/relation-picker/states/recoil-scope-contexts/RelationPickerRecoilScopeContext';
import { relationPickerPreselectedIdScopedState } from '@/object-record/relation-picker/states/relationPickerPreselectedIdScopedState'; import { relationPickerPreselectedIdScopedState } from '@/object-record/relation-picker/states/relationPickerPreselectedIdScopedState';
import { relationPickerSearchFilterScopedState } from '@/object-record/relation-picker/states/relationPickerSearchFilterScopedState'; import { relationPickerSearchFilterScopedState } from '@/object-record/relation-picker/states/relationPickerSearchFilterScopedState';
import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState'; import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState';
@ -8,14 +7,10 @@ import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoi
export const useEntitySelectSearch = () => { export const useEntitySelectSearch = () => {
const [, setRelationPickerPreselectedId] = useRecoilScopedState( const [, setRelationPickerPreselectedId] = useRecoilScopedState(
relationPickerPreselectedIdScopedState, relationPickerPreselectedIdScopedState,
RelationPickerRecoilScopeContext,
); );
const [relationPickerSearchFilter, setRelationPickerSearchFilter] = const [relationPickerSearchFilter, setRelationPickerSearchFilter] =
useRecoilScopedState( useRecoilScopedState(relationPickerSearchFilterScopedState);
relationPickerSearchFilterScopedState,
RelationPickerRecoilScopeContext,
);
const debouncedSetSearchFilter = debounce( const debouncedSetSearchFilter = debounce(
setRelationPickerSearchFilter, setRelationPickerSearchFilter,

View File

@ -1,18 +1,12 @@
import { isNonEmptyString } from '@sniptt/guards'; import { isNonEmptyString } from '@sniptt/guards';
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
import { OrderBy } from '@/object-metadata/types/OrderBy';
import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords'; import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords';
import { SelectableRecord } from '@/object-record/select/types/SelectableRecord'; import { SelectableRecord } from '@/object-record/select/types/SelectableRecord';
import { getObjectFilterFields } from '@/object-record/select/utils/getObjectFilterFields'; import { getObjectFilterFields } from '@/object-record/select/utils/getObjectFilterFields';
import { getObjectOrderByField } from '@/object-record/select/utils/getObjectOrderByField';
import { isDefined } from '~/utils/isDefined'; import { isDefined } from '~/utils/isDefined';
export type OrderBy =
| 'AscNullsLast'
| 'DescNullsLast'
| 'AscNullsFirst'
| 'DescNullsFirst';
export const DEFAULT_SEARCH_REQUEST_LIMIT = 60; export const DEFAULT_SEARCH_REQUEST_LIMIT = 60;
export const useRecordsForSelect = ({ export const useRecordsForSelect = ({
@ -30,9 +24,10 @@ export const useRecordsForSelect = ({
excludeEntityIds?: string[]; excludeEntityIds?: string[];
objectNameSingular: string; objectNameSingular: string;
}) => { }) => {
const { mapToObjectRecordIdentifier } = useObjectMetadataItem({ const { mapToObjectRecordIdentifier, getObjectOrderByField } =
objectNameSingular, useObjectMetadataItem({
}); objectNameSingular,
});
const filters = [ const filters = [
{ {
@ -41,7 +36,7 @@ export const useRecordsForSelect = ({
}, },
]; ];
const orderByField = getObjectOrderByField(objectNameSingular); const orderByField = getObjectOrderByField(sortOrder);
const { loading: selectedRecordsLoading, records: selectedRecordsData } = const { loading: selectedRecordsLoading, records: selectedRecordsData } =
useFindManyRecords({ useFindManyRecords({
@ -50,9 +45,7 @@ export const useRecordsForSelect = ({
in: selectedIds, in: selectedIds,
}, },
}, },
orderBy: { orderBy: orderByField,
[orderByField]: sortOrder,
},
objectNameSingular, objectNameSingular,
}); });
@ -103,9 +96,7 @@ export const useRecordsForSelect = ({
}, },
], ],
}, },
orderBy: { orderBy: orderByField,
[orderByField]: sortOrder,
},
objectNameSingular, objectNameSingular,
}); });
@ -126,9 +117,7 @@ export const useRecordsForSelect = ({
], ],
}, },
limit: limit ?? DEFAULT_SEARCH_REQUEST_LIMIT, limit: limit ?? DEFAULT_SEARCH_REQUEST_LIMIT,
orderBy: { orderBy: orderByField,
[orderByField]: sortOrder,
},
objectNameSingular, objectNameSingular,
}); });

View File

@ -1,11 +0,0 @@
export const getObjectOrderByField = (objectSingleName: string): string => {
if (objectSingleName === 'company') {
return 'name';
}
if (['workspaceMember', 'person'].includes(objectSingleName)) {
return 'name.firstName';
}
return 'createdAt';
};

View File

@ -2,6 +2,7 @@ import { QueryHookOptions, QueryResult } from '@apollo/client';
import { isNonEmptyString } from '@sniptt/guards'; import { isNonEmptyString } from '@sniptt/guards';
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
import { OrderBy } from '@/object-metadata/types/OrderBy';
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 { mapPaginatedRecordsToRecords } from '@/object-record/utils/mapPaginatedRecordsToRecords';
@ -10,12 +11,6 @@ import { isDefined } from '~/utils/isDefined';
type SearchFilter = { fieldNames: string[]; filter: string | number }; type SearchFilter = { fieldNames: string[]; filter: string | number };
export type OrderBy =
| 'AscNullsLast'
| 'DescNullsLast'
| 'AscNullsFirst'
| 'DescNullsFirst';
export const DEFAULT_SEARCH_REQUEST_LIMIT = 60; 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