mirror of
https://github.com/twentyhq/twenty.git
synced 2024-12-26 13:31:45 +03:00
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:
parent
9b7d7b29ed
commit
52859e18ed
@ -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,
|
||||
|
@ -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);
|
||||
};
|
||||
};
|
@ -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,
|
||||
|
@ -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,
|
||||
};
|
||||
};
|
||||
|
5
front/src/modules/object-metadata/types/OrderBy.ts
Normal file
5
front/src/modules/object-metadata/types/OrderBy.ts
Normal file
@ -0,0 +1,5 @@
|
||||
export type OrderBy =
|
||||
| 'AscNullsLast'
|
||||
| 'DescNullsLast'
|
||||
| 'AscNullsFirst'
|
||||
| 'DescNullsFirst';
|
5
front/src/modules/object-metadata/types/OrderByField.ts
Normal file
5
front/src/modules/object-metadata/types/OrderByField.ts
Normal file
@ -0,0 +1,5 @@
|
||||
import { OrderBy } from '@/object-metadata/types/OrderBy';
|
||||
|
||||
export type OrderByField = {
|
||||
[fieldName: string]: OrderBy | { [subFieldName: string]: OrderBy };
|
||||
};
|
@ -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,
|
||||
};
|
||||
}
|
||||
};
|
@ -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;
|
||||
|
@ -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]),
|
||||
|
@ -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]),
|
||||
|
@ -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({
|
||||
|
@ -31,6 +31,10 @@ export const ObjectFilterDropdownRecordSelect = () => {
|
||||
recordToSelect: SelectableRecord,
|
||||
newSelectedValue: boolean,
|
||||
) => {
|
||||
if (loading) {
|
||||
return;
|
||||
}
|
||||
|
||||
const newSelectedRecordIds = newSelectedValue
|
||||
? [...objectFilterDropdownSelectedRecordIds, recordToSelect.id]
|
||||
: objectFilterDropdownSelectedRecordIds.filter(
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
});
|
||||
|
||||
|
@ -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';
|
||||
};
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user