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
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 103 additions and 62 deletions

View File

@ -19,7 +19,7 @@ export const useNotes = (entity: ActivityTargetableEntity) => {
};
const orderBy = {
createdAt: 'AscNullsFirst',
};
} as any; // TODO: finish typing
const { records: notes } = useFindManyRecords({
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 { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
import { ObjectRecordIdentifier } from '@/object-record/types/ObjectRecordIdentifier';
import { FieldMetadataType } from '~/generated-metadata/graphql';
import { getLogoUrlFromDomainName } from '~/utils';
export const useMapToObjectRecordIdentifier = ({
@ -10,17 +11,6 @@ export const useMapToObjectRecordIdentifier = ({
}) => {
return (record: any): ObjectRecordIdentifier => {
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:
return {
id: record.id,
@ -36,9 +26,20 @@ export const useMapToObjectRecordIdentifier = ({
field.name === 'name',
);
const labelIdentifierFieldValue = labelIdentifierFieldMetadata
let labelIdentifierFieldValue = '';
switch (labelIdentifierFieldMetadata?.type) {
case FieldMetadataType.FullName: {
labelIdentifierFieldValue = `${record.name?.firstName ?? ''} ${
record.name?.lastName ?? ''
}`;
break;
}
default:
labelIdentifierFieldValue = labelIdentifierFieldMetadata
? record[labelIdentifierFieldMetadata.name]
: null;
: '';
}
const imageIdentifierFieldMetadata = objectMetadataItem.fields.find(
(field) => field.id === objectMetadataItem.imageIdentifierFieldMetadataId,

View File

@ -3,6 +3,7 @@ import { useRecoilValue } from 'recoil';
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
import { ObjectMetadataItemNotFoundError } from '@/object-metadata/errors/ObjectMetadataNotFoundError';
import { useGetObjectOrderByField } from '@/object-metadata/hooks/useGetObjectOrderByField';
import { useMapToObjectRecordIdentifier } from '@/object-metadata/hooks/useMapToObjectRecordIdentifier';
import { objectMetadataItemFamilySelector } from '@/object-metadata/states/objectMetadataItemFamilySelector';
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
@ -66,6 +67,10 @@ export const useObjectMetadataItem = (
objectMetadataItem,
});
const getObjectOrderByField = useGetObjectOrderByField({
objectMetadataItem,
});
const getRecordFromCache = useGetRecordFromCache({
objectMetadataItem,
});
@ -114,5 +119,6 @@ export const useObjectMetadataItem = (
updateOneRecordMutation,
deleteOneRecordMutation,
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 { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
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 { filterUniqueRecordEdgesByCursor } from '@/object-record/utils/filterUniqueRecordEdgesByCursor';
import { DEFAULT_SEARCH_REQUEST_LIMIT } from '@/search/hooks/useFilteredSearchEntityQuery';
@ -36,7 +37,7 @@ export const useFindManyRecords = <
skip,
}: ObjectMetadataItemIdentifier & {
filter?: any;
orderBy?: any;
orderBy?: OrderByField;
limit?: number;
onCompleted?: (data: PaginatedRecordTypeResults<RecordType>) => void;
skip?: boolean;

View File

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

View File

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

View File

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

View File

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

View File

@ -1,6 +1,5 @@
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 { relationPickerSearchFilterScopedState } from '@/object-record/relation-picker/states/relationPickerSearchFilterScopedState';
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 = () => {
const [, setRelationPickerPreselectedId] = useRecoilScopedState(
relationPickerPreselectedIdScopedState,
RelationPickerRecoilScopeContext,
);
const [relationPickerSearchFilter, setRelationPickerSearchFilter] =
useRecoilScopedState(
relationPickerSearchFilterScopedState,
RelationPickerRecoilScopeContext,
);
useRecoilScopedState(relationPickerSearchFilterScopedState);
const debouncedSetSearchFilter = debounce(
setRelationPickerSearchFilter,

View File

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