Added parallel code path to set new record sorts state (#10345)
This PR implements a parallel code path to set record sorts without impacting the actual sort, like we did on record filter. We add a ViewBarRecordSortEffect which mirrors ViewBarRecordFilterEffect. It also adds availableFieldMetadataItemsForSortFamilySelector to replace sortDefinitions progressively.
This commit is contained in:
@ -0,0 +1,26 @@
|
|||||||
|
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
||||||
|
import { filterSortableFieldMetadataItems } from '@/object-metadata/utils/filterSortableFieldMetadataItems';
|
||||||
|
import { selectorFamily } from 'recoil';
|
||||||
|
import { isDefined } from 'twenty-shared';
|
||||||
|
|
||||||
|
export const availableFieldMetadataItemsForSortFamilySelector = selectorFamily({
|
||||||
|
key: 'availableFieldMetadataItemsForSortFamilySelector',
|
||||||
|
get:
|
||||||
|
({ objectMetadataItemId }: { objectMetadataItemId: string }) =>
|
||||||
|
({ get }) => {
|
||||||
|
const objectMetadataItems = get(objectMetadataItemsState);
|
||||||
|
|
||||||
|
const objectMetadataItem = objectMetadataItems.find(
|
||||||
|
(item) => item.id === objectMetadataItemId,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!isDefined(objectMetadataItem)) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
const availableFieldMetadataItemsForSort =
|
||||||
|
objectMetadataItem.fields.filter(filterSortableFieldMetadataItems);
|
||||||
|
|
||||||
|
return availableFieldMetadataItemsForSort;
|
||||||
|
},
|
||||||
|
});
|
||||||
@ -0,0 +1,13 @@
|
|||||||
|
import { SORTABLE_FIELD_METADATA_TYPES } from '@/object-metadata/constants/SortableFieldMetadataTypes';
|
||||||
|
import { FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
|
||||||
|
|
||||||
|
export const filterSortableFieldMetadataItems = (field: FieldMetadataItem) => {
|
||||||
|
const isSystemField = field.isSystem;
|
||||||
|
const isFieldActive = field.isActive;
|
||||||
|
|
||||||
|
const isFieldTypeSortable = SORTABLE_FIELD_METADATA_TYPES.includes(
|
||||||
|
field.type,
|
||||||
|
);
|
||||||
|
|
||||||
|
return !isSystemField && isFieldActive && isFieldTypeSortable;
|
||||||
|
};
|
||||||
@ -11,14 +11,6 @@ export const getRelationObjectMetadataNameSingular = ({
|
|||||||
return field.relationDefinition?.targetObjectMetadata.nameSingular;
|
return field.relationDefinition?.targetObjectMetadata.nameSingular;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getRelationObjectMetadataNamePlural = ({
|
|
||||||
field,
|
|
||||||
}: {
|
|
||||||
field: ObjectMetadataItem['fields'][0];
|
|
||||||
}): string | undefined => {
|
|
||||||
return field.relationDefinition?.targetObjectMetadata.namePlural;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getFilterTypeFromFieldType = (
|
export const getFilterTypeFromFieldType = (
|
||||||
fieldType: FieldMetadataType,
|
fieldType: FieldMetadataType,
|
||||||
): FilterableFieldType => {
|
): FilterableFieldType => {
|
||||||
|
|||||||
@ -6,12 +6,16 @@ import { useCloseSortDropdown } from '@/object-record/object-sort-dropdown/hooks
|
|||||||
import { useResetRecordSortDropdownSearchInput } from '@/object-record/object-sort-dropdown/hooks/useResetRecordSortDropdownSearchInput';
|
import { useResetRecordSortDropdownSearchInput } from '@/object-record/object-sort-dropdown/hooks/useResetRecordSortDropdownSearchInput';
|
||||||
import { useResetSortDropdown } from '@/object-record/object-sort-dropdown/hooks/useResetSortDropdown';
|
import { useResetSortDropdown } from '@/object-record/object-sort-dropdown/hooks/useResetSortDropdown';
|
||||||
import { useToggleSortDropdown } from '@/object-record/object-sort-dropdown/hooks/useToggleSortDropdown';
|
import { useToggleSortDropdown } from '@/object-record/object-sort-dropdown/hooks/useToggleSortDropdown';
|
||||||
import { isSortDirectionMenuUnfoldedComponentState } from '@/object-record/object-sort-dropdown/states/isSortDirectionMenuUnfoldedState';
|
import { isRecordSortDirectionMenuUnfoldedComponentState } from '@/object-record/object-sort-dropdown/states/isRecordSortDirectionMenuUnfoldedComponentState';
|
||||||
import { objectSortDropdownSearchInputComponentState } from '@/object-record/object-sort-dropdown/states/objectSortDropdownSearchInputComponentState';
|
import { objectSortDropdownSearchInputComponentState } from '@/object-record/object-sort-dropdown/states/objectSortDropdownSearchInputComponentState';
|
||||||
import { onSortSelectComponentState } from '@/object-record/object-sort-dropdown/states/onSortSelectScopedState';
|
import { onSortSelectComponentState } from '@/object-record/object-sort-dropdown/states/onSortSelectScopedState';
|
||||||
import { selectedSortDirectionComponentState } from '@/object-record/object-sort-dropdown/states/selectedSortDirectionState';
|
import { selectedRecordSortDirectionComponentState } from '@/object-record/object-sort-dropdown/states/selectedRecordSortDirectionComponentState';
|
||||||
import { SortDefinition } from '@/object-record/object-sort-dropdown/types/SortDefinition';
|
import { SortDefinition } from '@/object-record/object-sort-dropdown/types/SortDefinition';
|
||||||
import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext';
|
import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext';
|
||||||
|
import {
|
||||||
|
RECORD_SORT_DIRECTIONS,
|
||||||
|
RecordSortDirection,
|
||||||
|
} from '@/object-record/record-sort/types/RecordSortDirection';
|
||||||
import { hiddenTableColumnsComponentSelector } from '@/object-record/record-table/states/selectors/hiddenTableColumnsComponentSelector';
|
import { hiddenTableColumnsComponentSelector } from '@/object-record/record-table/states/selectors/hiddenTableColumnsComponentSelector';
|
||||||
import { visibleTableColumnsComponentSelector } from '@/object-record/record-table/states/selectors/visibleTableColumnsComponentSelector';
|
import { visibleTableColumnsComponentSelector } from '@/object-record/record-table/states/selectors/visibleTableColumnsComponentSelector';
|
||||||
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
||||||
@ -26,7 +30,7 @@ import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/
|
|||||||
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
||||||
import { availableSortDefinitionsComponentState } from '@/views/states/availableSortDefinitionsComponentState';
|
import { availableSortDefinitionsComponentState } from '@/views/states/availableSortDefinitionsComponentState';
|
||||||
import { Trans, useLingui } from '@lingui/react/macro';
|
import { Trans, useLingui } from '@lingui/react/macro';
|
||||||
import { SORT_DIRECTIONS, SortDirection } from '../types/SortDirection';
|
import { v4 } from 'uuid';
|
||||||
|
|
||||||
export const StyledInput = styled.input`
|
export const StyledInput = styled.input`
|
||||||
background: transparent;
|
background: transparent;
|
||||||
@ -79,8 +83,8 @@ export const ObjectSortDropdownButton = ({
|
|||||||
objectSortDropdownSearchInputComponentState,
|
objectSortDropdownSearchInputComponentState,
|
||||||
);
|
);
|
||||||
|
|
||||||
const isSortDirectionMenuUnfolded = useRecoilComponentValueV2(
|
const isRecordSortDirectionMenuUnfolded = useRecoilComponentValueV2(
|
||||||
isSortDirectionMenuUnfoldedComponentState,
|
isRecordSortDirectionMenuUnfoldedComponentState,
|
||||||
);
|
);
|
||||||
|
|
||||||
const { resetSortDropdown } = useResetSortDropdown();
|
const { resetSortDropdown } = useResetSortDropdown();
|
||||||
@ -153,22 +157,23 @@ export const ObjectSortDropdownButton = ({
|
|||||||
setObjectSortDropdownSearchInput('');
|
setObjectSortDropdownSearchInput('');
|
||||||
closeSortDropdown();
|
closeSortDropdown();
|
||||||
onSortSelect?.({
|
onSortSelect?.({
|
||||||
|
id: v4(),
|
||||||
fieldMetadataId: sortDefinition.fieldMetadataId,
|
fieldMetadataId: sortDefinition.fieldMetadataId,
|
||||||
direction: selectedSortDirection,
|
direction: selectedRecordSortDirection,
|
||||||
definition: sortDefinition,
|
definition: sortDefinition,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const [selectedSortDirection, setSelectedSortDirection] =
|
const [selectedRecordSortDirection, setSelectedRecordSortDirection] =
|
||||||
useRecoilComponentStateV2(selectedSortDirectionComponentState);
|
useRecoilComponentStateV2(selectedRecordSortDirectionComponentState);
|
||||||
|
|
||||||
const setIsSortDirectionMenuUnfolded = useSetRecoilComponentStateV2(
|
const setIsRecordSortDirectionMenuUnfolded = useSetRecoilComponentStateV2(
|
||||||
isSortDirectionMenuUnfoldedComponentState,
|
isRecordSortDirectionMenuUnfoldedComponentState,
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleSortDirectionClick = (sortDirection: SortDirection) => {
|
const handleSortDirectionClick = (sortDirection: RecordSortDirection) => {
|
||||||
setSelectedSortDirection(sortDirection);
|
setSelectedRecordSortDirection(sortDirection);
|
||||||
setIsSortDirectionMenuUnfolded(false);
|
setIsRecordSortDirectionMenuUnfolded(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
const { isDropdownOpen } = useDropdown(OBJECT_SORT_DROPDOWN_ID);
|
const { isDropdownOpen } = useDropdown(OBJECT_SORT_DROPDOWN_ID);
|
||||||
@ -190,10 +195,10 @@ export const ObjectSortDropdownButton = ({
|
|||||||
}
|
}
|
||||||
dropdownComponents={
|
dropdownComponents={
|
||||||
<>
|
<>
|
||||||
{isSortDirectionMenuUnfolded && (
|
{isRecordSortDirectionMenuUnfolded && (
|
||||||
<StyledSelectedSortDirectionContainer>
|
<StyledSelectedSortDirectionContainer>
|
||||||
<DropdownMenuItemsContainer>
|
<DropdownMenuItemsContainer>
|
||||||
{SORT_DIRECTIONS.map((sortDirection, index) => (
|
{RECORD_SORT_DIRECTIONS.map((sortDirection, index) => (
|
||||||
<MenuItem
|
<MenuItem
|
||||||
key={index}
|
key={index}
|
||||||
onClick={() => handleSortDirectionClick(sortDirection)}
|
onClick={() => handleSortDirectionClick(sortDirection)}
|
||||||
@ -208,10 +213,14 @@ export const ObjectSortDropdownButton = ({
|
|||||||
<DropdownMenuHeader
|
<DropdownMenuHeader
|
||||||
EndIcon={IconChevronDown}
|
EndIcon={IconChevronDown}
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
setIsSortDirectionMenuUnfolded(!isSortDirectionMenuUnfolded)
|
setIsRecordSortDirectionMenuUnfolded(
|
||||||
|
!isRecordSortDirectionMenuUnfolded,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
{selectedSortDirection === 'asc' ? t`Ascending` : t`Descending`}
|
{selectedRecordSortDirection === 'asc'
|
||||||
|
? t`Ascending`
|
||||||
|
: t`Descending`}
|
||||||
</DropdownMenuHeader>
|
</DropdownMenuHeader>
|
||||||
<StyledInput
|
<StyledInput
|
||||||
autoFocus
|
autoFocus
|
||||||
|
|||||||
@ -1,19 +1,19 @@
|
|||||||
import { isSortDirectionMenuUnfoldedComponentState } from '@/object-record/object-sort-dropdown/states/isSortDirectionMenuUnfoldedState';
|
import { isRecordSortDirectionMenuUnfoldedComponentState } from '@/object-record/object-sort-dropdown/states/isRecordSortDirectionMenuUnfoldedComponentState';
|
||||||
import { selectedSortDirectionComponentState } from '@/object-record/object-sort-dropdown/states/selectedSortDirectionState';
|
import { selectedRecordSortDirectionComponentState } from '@/object-record/object-sort-dropdown/states/selectedRecordSortDirectionComponentState';
|
||||||
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
||||||
|
|
||||||
export const useResetSortDropdown = () => {
|
export const useResetSortDropdown = () => {
|
||||||
const setIsSortDirectionMenuUnfolded = useSetRecoilComponentStateV2(
|
const setIsRecordSortDirectionMenuUnfolded = useSetRecoilComponentStateV2(
|
||||||
isSortDirectionMenuUnfoldedComponentState,
|
isRecordSortDirectionMenuUnfoldedComponentState,
|
||||||
);
|
);
|
||||||
|
|
||||||
const setSelectedSortDirection = useSetRecoilComponentStateV2(
|
const setSelectedRecordSortDirection = useSetRecoilComponentStateV2(
|
||||||
selectedSortDirectionComponentState,
|
selectedRecordSortDirectionComponentState,
|
||||||
);
|
);
|
||||||
|
|
||||||
const resetSortDropdown = () => {
|
const resetSortDropdown = () => {
|
||||||
setIsSortDirectionMenuUnfolded(false);
|
setIsRecordSortDirectionMenuUnfolded(false);
|
||||||
setSelectedSortDirection('asc');
|
setSelectedRecordSortDirection('asc');
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@ -1,24 +0,0 @@
|
|||||||
import { isSortSelectedComponentState } from '@/object-record/object-sort-dropdown/states/isSortSelectedScopedState';
|
|
||||||
import { objectSortDropdownSearchInputComponentState } from '@/object-record/object-sort-dropdown/states/objectSortDropdownSearchInputComponentState';
|
|
||||||
import { onSortSelectComponentState } from '@/object-record/object-sort-dropdown/states/onSortSelectScopedState';
|
|
||||||
|
|
||||||
export const useSortDropdownStates = (scopeId: string) => {
|
|
||||||
const isSortSelectedState = isSortSelectedComponentState.atomFamily({
|
|
||||||
instanceId: scopeId,
|
|
||||||
});
|
|
||||||
|
|
||||||
const onSortSelectState = onSortSelectComponentState.atomFamily({
|
|
||||||
instanceId: scopeId,
|
|
||||||
});
|
|
||||||
|
|
||||||
const objectSortDropdownSearchInputState =
|
|
||||||
objectSortDropdownSearchInputComponentState.atomFamily({
|
|
||||||
instanceId: scopeId,
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
|
||||||
isSortSelectedState,
|
|
||||||
onSortSelectState,
|
|
||||||
objectSortDropdownSearchInputState,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
@ -1,8 +1,9 @@
|
|||||||
import { ObjectSortDropdownComponentInstanceContext } from '@/object-record/object-sort-dropdown/states/context/ObjectSortDropdownComponentInstanceContext';
|
import { ObjectSortDropdownComponentInstanceContext } from '@/object-record/object-sort-dropdown/states/context/ObjectSortDropdownComponentInstanceContext';
|
||||||
import { createComponentStateV2 } from '@/ui/utilities/state/component-state/utils/createComponentStateV2';
|
import { createComponentStateV2 } from '@/ui/utilities/state/component-state/utils/createComponentStateV2';
|
||||||
|
|
||||||
export const isSortSelectedComponentState = createComponentStateV2<boolean>({
|
export const isRecordSortDirectionMenuUnfoldedComponentState =
|
||||||
key: 'isSortSelectedComponentState',
|
createComponentStateV2<boolean>({
|
||||||
defaultValue: false,
|
key: 'isRecordSortDirectionMenuUnfoldedComponentState',
|
||||||
componentInstanceContext: ObjectSortDropdownComponentInstanceContext,
|
defaultValue: false,
|
||||||
});
|
componentInstanceContext: ObjectSortDropdownComponentInstanceContext,
|
||||||
|
});
|
||||||
@ -1,9 +1,9 @@
|
|||||||
import { ObjectSortDropdownComponentInstanceContext } from '@/object-record/object-sort-dropdown/states/context/ObjectSortDropdownComponentInstanceContext';
|
import { ObjectSortDropdownComponentInstanceContext } from '@/object-record/object-sort-dropdown/states/context/ObjectSortDropdownComponentInstanceContext';
|
||||||
import { createComponentStateV2 } from '@/ui/utilities/state/component-state/utils/createComponentStateV2';
|
import { createComponentStateV2 } from '@/ui/utilities/state/component-state/utils/createComponentStateV2';
|
||||||
|
|
||||||
export const isSortDirectionMenuUnfoldedComponentState =
|
export const isRecordSortSelectedComponentState =
|
||||||
createComponentStateV2<boolean>({
|
createComponentStateV2<boolean>({
|
||||||
key: 'isSortDirectionMenuUnfoldedComponentState',
|
key: 'isRecordSortSelectedComponentState',
|
||||||
defaultValue: false,
|
defaultValue: false,
|
||||||
componentInstanceContext: ObjectSortDropdownComponentInstanceContext,
|
componentInstanceContext: ObjectSortDropdownComponentInstanceContext,
|
||||||
});
|
});
|
||||||
@ -1,9 +1,9 @@
|
|||||||
import { ObjectSortDropdownComponentInstanceContext } from '@/object-record/object-sort-dropdown/states/context/ObjectSortDropdownComponentInstanceContext';
|
import { ObjectSortDropdownComponentInstanceContext } from '@/object-record/object-sort-dropdown/states/context/ObjectSortDropdownComponentInstanceContext';
|
||||||
|
import { RecordSort } from '@/object-record/record-sort/types/RecordSort';
|
||||||
import { createComponentStateV2 } from '@/ui/utilities/state/component-state/utils/createComponentStateV2';
|
import { createComponentStateV2 } from '@/ui/utilities/state/component-state/utils/createComponentStateV2';
|
||||||
import { Sort } from '../types/Sort';
|
|
||||||
|
|
||||||
export const onSortSelectComponentState = createComponentStateV2<
|
export const onSortSelectComponentState = createComponentStateV2<
|
||||||
((sort: Sort) => void) | undefined
|
((sort: RecordSort) => void) | undefined
|
||||||
>({
|
>({
|
||||||
key: 'onSortSelectComponentState',
|
key: 'onSortSelectComponentState',
|
||||||
defaultValue: undefined,
|
defaultValue: undefined,
|
||||||
|
|||||||
@ -1,10 +1,10 @@
|
|||||||
import { ObjectSortDropdownComponentInstanceContext } from '@/object-record/object-sort-dropdown/states/context/ObjectSortDropdownComponentInstanceContext';
|
import { ObjectSortDropdownComponentInstanceContext } from '@/object-record/object-sort-dropdown/states/context/ObjectSortDropdownComponentInstanceContext';
|
||||||
import { SortDirection } from '@/object-record/object-sort-dropdown/types/SortDirection';
|
import { RecordSortDirection } from '@/object-record/record-sort/types/RecordSortDirection';
|
||||||
import { createComponentStateV2 } from '@/ui/utilities/state/component-state/utils/createComponentStateV2';
|
import { createComponentStateV2 } from '@/ui/utilities/state/component-state/utils/createComponentStateV2';
|
||||||
|
|
||||||
export const selectedSortDirectionComponentState =
|
export const selectedRecordSortDirectionComponentState =
|
||||||
createComponentStateV2<SortDirection>({
|
createComponentStateV2<RecordSortDirection>({
|
||||||
key: 'selectedSortDirectionComponentState',
|
key: 'selectedRecordSortDirectionComponentState',
|
||||||
defaultValue: 'asc',
|
defaultValue: 'asc',
|
||||||
componentInstanceContext: ObjectSortDropdownComponentInstanceContext,
|
componentInstanceContext: ObjectSortDropdownComponentInstanceContext,
|
||||||
});
|
});
|
||||||
@ -1,8 +0,0 @@
|
|||||||
import { SortDefinition } from './SortDefinition';
|
|
||||||
import { SortDirection } from './SortDirection';
|
|
||||||
|
|
||||||
export type Sort = {
|
|
||||||
fieldMetadataId: string;
|
|
||||||
direction: SortDirection;
|
|
||||||
definition: SortDefinition;
|
|
||||||
};
|
|
||||||
@ -1,8 +1,5 @@
|
|||||||
import { SortDirection } from './SortDirection';
|
|
||||||
|
|
||||||
export type SortDefinition = {
|
export type SortDefinition = {
|
||||||
fieldMetadataId: string;
|
fieldMetadataId: string;
|
||||||
label: string;
|
label: string;
|
||||||
iconName: string;
|
iconName: string;
|
||||||
getOrderByTemplate?: (direction: SortDirection) => any[];
|
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,3 +0,0 @@
|
|||||||
export const SORT_DIRECTIONS = ['asc', 'desc'] as const;
|
|
||||||
|
|
||||||
export type SortDirection = (typeof SORT_DIRECTIONS)[number];
|
|
||||||
@ -1,8 +1,8 @@
|
|||||||
import { FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
|
import { FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
|
||||||
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||||
import { Sort } from '@/object-record/object-sort-dropdown/types/Sort';
|
|
||||||
import { SortDefinition } from '@/object-record/object-sort-dropdown/types/SortDefinition';
|
import { SortDefinition } from '@/object-record/object-sort-dropdown/types/SortDefinition';
|
||||||
import { turnSortsIntoOrderBy } from '@/object-record/object-sort-dropdown/utils/turnSortsIntoOrderBy';
|
import { turnSortsIntoOrderBy } from '@/object-record/object-sort-dropdown/utils/turnSortsIntoOrderBy';
|
||||||
|
import { RecordSort } from '@/object-record/record-sort/types/RecordSort';
|
||||||
|
|
||||||
const sortDefinition: SortDefinition = {
|
const sortDefinition: SortDefinition = {
|
||||||
fieldMetadataId: 'id',
|
fieldMetadataId: 'id',
|
||||||
@ -42,8 +42,9 @@ describe('turnSortsIntoOrderBy', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should create OrderByField with single sort', () => {
|
it('should create OrderByField with single sort', () => {
|
||||||
const sorts: Sort[] = [
|
const sorts: RecordSort[] = [
|
||||||
{
|
{
|
||||||
|
id: 'id',
|
||||||
fieldMetadataId: 'field1',
|
fieldMetadataId: 'field1',
|
||||||
direction: 'asc',
|
direction: 'asc',
|
||||||
definition: sortDefinition,
|
definition: sortDefinition,
|
||||||
@ -56,13 +57,15 @@ describe('turnSortsIntoOrderBy', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should create OrderByField with multiple sorts', () => {
|
it('should create OrderByField with multiple sorts', () => {
|
||||||
const sorts: Sort[] = [
|
const sorts: RecordSort[] = [
|
||||||
{
|
{
|
||||||
|
id: 'id',
|
||||||
fieldMetadataId: 'field1',
|
fieldMetadataId: 'field1',
|
||||||
direction: 'asc',
|
direction: 'asc',
|
||||||
definition: sortDefinition,
|
definition: sortDefinition,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
id: 'id',
|
||||||
fieldMetadataId: 'field2',
|
fieldMetadataId: 'field2',
|
||||||
direction: 'desc',
|
direction: 'desc',
|
||||||
definition: sortDefinition,
|
definition: sortDefinition,
|
||||||
@ -82,8 +85,9 @@ describe('turnSortsIntoOrderBy', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should ignore if field not found', () => {
|
it('should ignore if field not found', () => {
|
||||||
const sorts: Sort[] = [
|
const sorts: RecordSort[] = [
|
||||||
{
|
{
|
||||||
|
id: 'id',
|
||||||
fieldMetadataId: 'invalidField',
|
fieldMetadataId: 'invalidField',
|
||||||
direction: 'asc',
|
direction: 'asc',
|
||||||
definition: sortDefinition,
|
definition: sortDefinition,
|
||||||
@ -95,8 +99,9 @@ describe('turnSortsIntoOrderBy', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should not return position for remotes', () => {
|
it('should not return position for remotes', () => {
|
||||||
const sorts: Sort[] = [
|
const sorts: RecordSort[] = [
|
||||||
{
|
{
|
||||||
|
id: 'id',
|
||||||
fieldMetadataId: 'invalidField',
|
fieldMetadataId: 'invalidField',
|
||||||
direction: 'asc',
|
direction: 'asc',
|
||||||
definition: sortDefinition,
|
definition: sortDefinition,
|
||||||
|
|||||||
@ -8,12 +8,12 @@ import { isUndefinedOrNull } from '~/utils/isUndefinedOrNull';
|
|||||||
|
|
||||||
import { FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
|
import { FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
|
||||||
import { getOrderByForFieldMetadataType } from '@/object-metadata/utils/getOrderByForFieldMetadataType';
|
import { getOrderByForFieldMetadataType } from '@/object-metadata/utils/getOrderByForFieldMetadataType';
|
||||||
|
import { RecordSort } from '@/object-record/record-sort/types/RecordSort';
|
||||||
import { OrderBy } from '@/types/OrderBy';
|
import { OrderBy } from '@/types/OrderBy';
|
||||||
import { Sort } from '../types/Sort';
|
|
||||||
|
|
||||||
export const turnSortsIntoOrderBy = (
|
export const turnSortsIntoOrderBy = (
|
||||||
objectMetadataItem: ObjectMetadataItem,
|
objectMetadataItem: ObjectMetadataItem,
|
||||||
sorts: Sort[],
|
sorts: RecordSort[],
|
||||||
): RecordGqlOperationOrderBy => {
|
): RecordGqlOperationOrderBy => {
|
||||||
const fields: Pick<FieldMetadataItem, 'id' | 'name' | 'type'>[] =
|
const fields: Pick<FieldMetadataItem, 'id' | 'name' | 'type'>[] =
|
||||||
objectMetadataItem?.fields ?? [];
|
objectMetadataItem?.fields ?? [];
|
||||||
|
|||||||
@ -2,9 +2,11 @@ import { useCallback } from 'react';
|
|||||||
|
|
||||||
import { useColumnDefinitionsFromFieldMetadata } from '@/object-metadata/hooks/useColumnDefinitionsFromFieldMetadata';
|
import { useColumnDefinitionsFromFieldMetadata } from '@/object-metadata/hooks/useColumnDefinitionsFromFieldMetadata';
|
||||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||||
import { Sort } from '@/object-record/object-sort-dropdown/types/Sort';
|
import { useUpsertRecordSort } from '@/object-record/record-sort/hooks/useUpsertRecordSort';
|
||||||
|
import { RecordSort } from '@/object-record/record-sort/types/RecordSort';
|
||||||
import { useUpsertCombinedViewSorts } from '@/views/hooks/useUpsertCombinedViewSorts';
|
import { useUpsertCombinedViewSorts } from '@/views/hooks/useUpsertCombinedViewSorts';
|
||||||
import { isDefined } from 'twenty-shared';
|
import { isDefined } from 'twenty-shared';
|
||||||
|
import { v4 } from 'uuid';
|
||||||
|
|
||||||
type UseHandleToggleColumnSortProps = {
|
type UseHandleToggleColumnSortProps = {
|
||||||
objectNameSingular: string;
|
objectNameSingular: string;
|
||||||
@ -24,6 +26,8 @@ export const useHandleToggleColumnSort = ({
|
|||||||
|
|
||||||
const { upsertCombinedViewSort } = useUpsertCombinedViewSorts(viewBarId);
|
const { upsertCombinedViewSort } = useUpsertCombinedViewSorts(viewBarId);
|
||||||
|
|
||||||
|
const { upsertRecordSort } = useUpsertRecordSort();
|
||||||
|
|
||||||
const handleToggleColumnSort = useCallback(
|
const handleToggleColumnSort = useCallback(
|
||||||
(fieldMetadataId: string) => {
|
(fieldMetadataId: string) => {
|
||||||
const correspondingColumnDefinition = columnDefinitions.find(
|
const correspondingColumnDefinition = columnDefinitions.find(
|
||||||
@ -33,7 +37,8 @@ export const useHandleToggleColumnSort = ({
|
|||||||
|
|
||||||
if (!isDefined(correspondingColumnDefinition)) return;
|
if (!isDefined(correspondingColumnDefinition)) return;
|
||||||
|
|
||||||
const newSort: Sort = {
|
const newSort: RecordSort = {
|
||||||
|
id: v4(),
|
||||||
fieldMetadataId,
|
fieldMetadataId,
|
||||||
definition: {
|
definition: {
|
||||||
fieldMetadataId,
|
fieldMetadataId,
|
||||||
@ -44,8 +49,9 @@ export const useHandleToggleColumnSort = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
upsertCombinedViewSort(newSort);
|
upsertCombinedViewSort(newSort);
|
||||||
|
upsertRecordSort(newSort);
|
||||||
},
|
},
|
||||||
[columnDefinitions, upsertCombinedViewSort],
|
[columnDefinitions, upsertCombinedViewSort, upsertRecordSort],
|
||||||
);
|
);
|
||||||
|
|
||||||
return handleToggleColumnSort;
|
return handleToggleColumnSort;
|
||||||
|
|||||||
@ -1,8 +1,7 @@
|
|||||||
|
import { RecordSort } from '@/object-record/record-sort/types/RecordSort';
|
||||||
import { createState } from '@ui/utilities/state/utils/createState';
|
import { createState } from '@ui/utilities/state/utils/createState';
|
||||||
|
|
||||||
import { Sort } from '@/object-record/object-sort-dropdown/types/Sort';
|
export const recordIndexSortsState = createState<RecordSort[]>({
|
||||||
|
|
||||||
export const recordIndexSortsState = createState<Sort[]>({
|
|
||||||
key: 'recordIndexSortsState',
|
key: 'recordIndexSortsState',
|
||||||
defaultValue: [],
|
defaultValue: [],
|
||||||
});
|
});
|
||||||
|
|||||||
@ -0,0 +1,15 @@
|
|||||||
|
import { availableFieldMetadataItemsForSortFamilySelector } from '@/object-metadata/states/availableFieldMetadataItemsForSortFamilySelector';
|
||||||
|
import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext';
|
||||||
|
import { useRecoilValue } from 'recoil';
|
||||||
|
|
||||||
|
export const useSortableFieldMetadataItemsInRecordIndexContext = () => {
|
||||||
|
const { objectMetadataItem } = useRecordIndexContextOrThrow();
|
||||||
|
|
||||||
|
const sortableFieldMetadataItems = useRecoilValue(
|
||||||
|
availableFieldMetadataItemsForSortFamilySelector({
|
||||||
|
objectMetadataItemId: objectMetadataItem.id,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
return { sortableFieldMetadataItems };
|
||||||
|
};
|
||||||
@ -0,0 +1,58 @@
|
|||||||
|
import { currentRecordSortsComponentState } from '@/object-record/record-sort/states/currentRecordSortsComponentState';
|
||||||
|
import { RecordSort } from '@/object-record/record-sort/types/RecordSort';
|
||||||
|
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
|
||||||
|
import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue';
|
||||||
|
import { useRecoilCallback } from 'recoil';
|
||||||
|
|
||||||
|
export const useUpsertRecordSort = () => {
|
||||||
|
const currentRecordSortsCallbackState = useRecoilComponentCallbackStateV2(
|
||||||
|
currentRecordSortsComponentState,
|
||||||
|
);
|
||||||
|
|
||||||
|
const upsertRecordSort = useRecoilCallback(
|
||||||
|
({ set, snapshot }) =>
|
||||||
|
(recordSortToSet: RecordSort) => {
|
||||||
|
const currentRecordSorts = getSnapshotValue(
|
||||||
|
snapshot,
|
||||||
|
currentRecordSortsCallbackState,
|
||||||
|
);
|
||||||
|
|
||||||
|
const hasFoundRecordSortInCurrentRecordSorts = currentRecordSorts.some(
|
||||||
|
(existingSort) =>
|
||||||
|
existingSort.fieldMetadataId === recordSortToSet.fieldMetadataId,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!hasFoundRecordSortInCurrentRecordSorts) {
|
||||||
|
set(currentRecordSortsCallbackState, [
|
||||||
|
...currentRecordSorts,
|
||||||
|
recordSortToSet,
|
||||||
|
]);
|
||||||
|
} else {
|
||||||
|
set(currentRecordSortsCallbackState, (currentRecordSorts) => {
|
||||||
|
const newCurrentRecordSorts = [...currentRecordSorts];
|
||||||
|
|
||||||
|
const indexOfSortToUpdate = newCurrentRecordSorts.findIndex(
|
||||||
|
(existingSort) =>
|
||||||
|
existingSort.fieldMetadataId ===
|
||||||
|
recordSortToSet.fieldMetadataId,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (indexOfSortToUpdate < 0) {
|
||||||
|
return newCurrentRecordSorts;
|
||||||
|
}
|
||||||
|
|
||||||
|
newCurrentRecordSorts[indexOfSortToUpdate] = {
|
||||||
|
...recordSortToSet,
|
||||||
|
};
|
||||||
|
|
||||||
|
return newCurrentRecordSorts;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[currentRecordSortsCallbackState],
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
upsertRecordSort,
|
||||||
|
};
|
||||||
|
};
|
||||||
@ -1,8 +1,8 @@
|
|||||||
|
import { RecordSort } from '@/object-record/record-sort/types/RecordSort';
|
||||||
import { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext';
|
import { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext';
|
||||||
import { createComponentStateV2 } from '@/ui/utilities/state/component-state/utils/createComponentStateV2';
|
import { createComponentStateV2 } from '@/ui/utilities/state/component-state/utils/createComponentStateV2';
|
||||||
import { Sort } from '../../object-sort-dropdown/types/Sort';
|
|
||||||
|
|
||||||
export const tableSortsComponentState = createComponentStateV2<Sort[]>({
|
export const tableSortsComponentState = createComponentStateV2<RecordSort[]>({
|
||||||
key: 'tableSortsComponentState',
|
key: 'tableSortsComponentState',
|
||||||
defaultValue: [],
|
defaultValue: [],
|
||||||
componentInstanceContext: RecordTableComponentInstanceContext,
|
componentInstanceContext: RecordTableComponentInstanceContext,
|
||||||
|
|||||||
@ -1,36 +1,42 @@
|
|||||||
import { IconArrowDown, IconArrowUp } from 'twenty-ui';
|
import { IconArrowDown, IconArrowUp } from 'twenty-ui';
|
||||||
|
|
||||||
import { Sort } from '@/object-record/object-sort-dropdown/types/Sort';
|
import { useUpsertRecordSort } from '@/object-record/record-sort/hooks/useUpsertRecordSort';
|
||||||
|
import { RecordSort } from '@/object-record/record-sort/types/RecordSort';
|
||||||
import { SortOrFilterChip } from '@/views/components/SortOrFilterChip';
|
import { SortOrFilterChip } from '@/views/components/SortOrFilterChip';
|
||||||
import { useDeleteCombinedViewSorts } from '@/views/hooks/useDeleteCombinedViewSorts';
|
import { useDeleteCombinedViewSorts } from '@/views/hooks/useDeleteCombinedViewSorts';
|
||||||
import { useUpsertCombinedViewSorts } from '@/views/hooks/useUpsertCombinedViewSorts';
|
import { useUpsertCombinedViewSorts } from '@/views/hooks/useUpsertCombinedViewSorts';
|
||||||
|
|
||||||
type EditableSortChipProps = {
|
type EditableSortChipProps = {
|
||||||
viewSort: Sort;
|
recordSort: RecordSort;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const EditableSortChip = ({ viewSort }: EditableSortChipProps) => {
|
export const EditableSortChip = ({ recordSort }: EditableSortChipProps) => {
|
||||||
const { deleteCombinedViewSort } = useDeleteCombinedViewSorts();
|
const { deleteCombinedViewSort } = useDeleteCombinedViewSorts();
|
||||||
|
|
||||||
const { upsertCombinedViewSort } = useUpsertCombinedViewSorts();
|
const { upsertCombinedViewSort } = useUpsertCombinedViewSorts();
|
||||||
|
|
||||||
|
const { upsertRecordSort } = useUpsertRecordSort();
|
||||||
|
|
||||||
const handleRemoveClick = () => {
|
const handleRemoveClick = () => {
|
||||||
deleteCombinedViewSort(viewSort.fieldMetadataId);
|
deleteCombinedViewSort(recordSort.fieldMetadataId);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleClick = () => {
|
const handleClick = () => {
|
||||||
upsertCombinedViewSort({
|
const newSort: RecordSort = {
|
||||||
...viewSort,
|
...recordSort,
|
||||||
direction: viewSort.direction === 'asc' ? 'desc' : 'asc',
|
direction: recordSort.direction === 'asc' ? 'desc' : 'asc',
|
||||||
});
|
};
|
||||||
|
|
||||||
|
upsertCombinedViewSort(newSort);
|
||||||
|
upsertRecordSort(newSort);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SortOrFilterChip
|
<SortOrFilterChip
|
||||||
key={viewSort.fieldMetadataId}
|
key={recordSort.fieldMetadataId}
|
||||||
testId={viewSort.fieldMetadataId}
|
testId={recordSort.fieldMetadataId}
|
||||||
labelValue={viewSort.definition.label}
|
labelValue={recordSort.definition.label}
|
||||||
Icon={viewSort.direction === 'desc' ? IconArrowDown : IconArrowUp}
|
Icon={recordSort.direction === 'desc' ? IconArrowDown : IconArrowUp}
|
||||||
onRemove={handleRemoveClick}
|
onRemove={handleRemoveClick}
|
||||||
onClick={handleClick}
|
onClick={handleClick}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@ -19,6 +19,7 @@ import { FiltersHotkeyScope } from '@/object-record/object-filter-dropdown/types
|
|||||||
import { VIEW_SORT_DROPDOWN_ID } from '@/object-record/object-sort-dropdown/constants/ViewSortDropdownId';
|
import { VIEW_SORT_DROPDOWN_ID } from '@/object-record/object-sort-dropdown/constants/ViewSortDropdownId';
|
||||||
import { ObjectSortDropdownComponentInstanceContext } from '@/object-record/object-sort-dropdown/states/context/ObjectSortDropdownComponentInstanceContext';
|
import { ObjectSortDropdownComponentInstanceContext } from '@/object-record/object-sort-dropdown/states/context/ObjectSortDropdownComponentInstanceContext';
|
||||||
import { ViewBarRecordFilterEffect } from '@/views/components/ViewBarRecordFilterEffect';
|
import { ViewBarRecordFilterEffect } from '@/views/components/ViewBarRecordFilterEffect';
|
||||||
|
import { ViewBarRecordSortEffect } from '@/views/components/ViewBarRecordSortEffect';
|
||||||
import { UpdateViewButtonGroup } from './UpdateViewButtonGroup';
|
import { UpdateViewButtonGroup } from './UpdateViewButtonGroup';
|
||||||
import { ViewBarDetails } from './ViewBarDetails';
|
import { ViewBarDetails } from './ViewBarDetails';
|
||||||
|
|
||||||
@ -48,6 +49,7 @@ export const ViewBar = ({
|
|||||||
value={{ instanceId: VIEW_SORT_DROPDOWN_ID }}
|
value={{ instanceId: VIEW_SORT_DROPDOWN_ID }}
|
||||||
>
|
>
|
||||||
<ViewBarRecordFilterEffect />
|
<ViewBarRecordFilterEffect />
|
||||||
|
<ViewBarRecordSortEffect />
|
||||||
<ViewBarFilterEffect filterDropdownId={filterDropdownId} />
|
<ViewBarFilterEffect filterDropdownId={filterDropdownId} />
|
||||||
<ViewBarSortEffect />
|
<ViewBarSortEffect />
|
||||||
<QueryParamsFiltersEffect />
|
<QueryParamsFiltersEffect />
|
||||||
|
|||||||
@ -204,8 +204,11 @@ export const ViewBarDetails = ({
|
|||||||
{mapViewSortsToSorts(
|
{mapViewSortsToSorts(
|
||||||
currentViewWithCombinedFiltersAndSorts?.viewSorts ?? [],
|
currentViewWithCombinedFiltersAndSorts?.viewSorts ?? [],
|
||||||
availableSortDefinitions,
|
availableSortDefinitions,
|
||||||
).map((sort) => (
|
).map((recordSort) => (
|
||||||
<EditableSortChip key={sort.fieldMetadataId} viewSort={sort} />
|
<EditableSortChip
|
||||||
|
key={recordSort.fieldMetadataId}
|
||||||
|
recordSort={recordSort}
|
||||||
|
/>
|
||||||
))}
|
))}
|
||||||
{isNonEmptyArray(recordFilters) &&
|
{isNonEmptyArray(recordFilters) &&
|
||||||
isNonEmptyArray(
|
isNonEmptyArray(
|
||||||
|
|||||||
@ -21,6 +21,12 @@ export const ViewBarRecordFilterEffect = () => {
|
|||||||
contextStoreCurrentObjectMetadataItemComponentState,
|
contextStoreCurrentObjectMetadataItemComponentState,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const currentView = useRecoilValue(
|
||||||
|
prefetchViewFromViewIdFamilySelector({
|
||||||
|
viewId: currentViewId ?? '',
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
const [
|
const [
|
||||||
hasInitializedCurrentRecordFilters,
|
hasInitializedCurrentRecordFilters,
|
||||||
setHasInitializedCurrentRecordFilters,
|
setHasInitializedCurrentRecordFilters,
|
||||||
@ -43,12 +49,6 @@ export const ViewBarRecordFilterEffect = () => {
|
|||||||
contextStoreCurrentObjectMetadataItem?.id,
|
contextStoreCurrentObjectMetadataItem?.id,
|
||||||
);
|
);
|
||||||
|
|
||||||
const currentView = useRecoilValue(
|
|
||||||
prefetchViewFromViewIdFamilySelector({
|
|
||||||
viewId: currentViewId ?? '',
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isDefined(currentView) && !hasInitializedCurrentRecordFilters) {
|
if (isDefined(currentView) && !hasInitializedCurrentRecordFilters) {
|
||||||
if (
|
if (
|
||||||
|
|||||||
@ -0,0 +1,83 @@
|
|||||||
|
import { contextStoreCurrentObjectMetadataItemComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataItemComponentState';
|
||||||
|
import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState';
|
||||||
|
import { availableFieldMetadataItemsForSortFamilySelector } from '@/object-metadata/states/availableFieldMetadataItemsForSortFamilySelector';
|
||||||
|
import { formatFieldMetadataItemsAsSortDefinitions } from '@/object-metadata/utils/formatFieldMetadataItemsAsSortDefinitions';
|
||||||
|
import { currentRecordSortsComponentState } from '@/object-record/record-sort/states/currentRecordSortsComponentState';
|
||||||
|
import { prefetchViewFromViewIdFamilySelector } from '@/prefetch/states/selector/prefetchViewFromViewIdFamilySelector';
|
||||||
|
import { useRecoilComponentFamilyStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyStateV2';
|
||||||
|
|
||||||
|
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||||
|
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
||||||
|
import { hasInitializedCurrentRecordSortsComponentFamilyState } from '@/views/states/hasInitializedCurrentRecordSortsComponentFamilyState';
|
||||||
|
|
||||||
|
import { mapViewSortsToSorts } from '@/views/utils/mapViewSortsToSorts';
|
||||||
|
import { useEffect } from 'react';
|
||||||
|
import { useRecoilValue } from 'recoil';
|
||||||
|
import { isDefined } from 'twenty-shared';
|
||||||
|
|
||||||
|
export const ViewBarRecordSortEffect = () => {
|
||||||
|
const currentViewId = useRecoilComponentValueV2(
|
||||||
|
contextStoreCurrentViewIdComponentState,
|
||||||
|
);
|
||||||
|
|
||||||
|
const contextStoreCurrentObjectMetadataItem = useRecoilComponentValueV2(
|
||||||
|
contextStoreCurrentObjectMetadataItemComponentState,
|
||||||
|
);
|
||||||
|
|
||||||
|
const currentView = useRecoilValue(
|
||||||
|
prefetchViewFromViewIdFamilySelector({
|
||||||
|
viewId: currentViewId ?? '',
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
const [
|
||||||
|
hasInitializedCurrentRecordSorts,
|
||||||
|
setHasInitializedCurrentRecordSorts,
|
||||||
|
] = useRecoilComponentFamilyStateV2(
|
||||||
|
hasInitializedCurrentRecordSortsComponentFamilyState,
|
||||||
|
{
|
||||||
|
viewId: currentViewId ?? undefined,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
const setCurrentRecordSorts = useSetRecoilComponentStateV2(
|
||||||
|
currentRecordSortsComponentState,
|
||||||
|
);
|
||||||
|
|
||||||
|
const sortableFieldMetadataItems = useRecoilValue(
|
||||||
|
availableFieldMetadataItemsForSortFamilySelector({
|
||||||
|
objectMetadataItemId: contextStoreCurrentObjectMetadataItem?.id,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (isDefined(currentView) && !hasInitializedCurrentRecordSorts) {
|
||||||
|
if (
|
||||||
|
currentView.objectMetadataId !==
|
||||||
|
contextStoreCurrentObjectMetadataItem?.id
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const sortDefinitions = formatFieldMetadataItemsAsSortDefinitions({
|
||||||
|
fields: sortableFieldMetadataItems,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (isDefined(currentView)) {
|
||||||
|
setCurrentRecordSorts(
|
||||||
|
mapViewSortsToSorts(currentView.viewSorts, sortDefinitions),
|
||||||
|
);
|
||||||
|
setHasInitializedCurrentRecordSorts(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [
|
||||||
|
hasInitializedCurrentRecordSorts,
|
||||||
|
currentView,
|
||||||
|
sortableFieldMetadataItems,
|
||||||
|
setCurrentRecordSorts,
|
||||||
|
contextStoreCurrentObjectMetadataItem,
|
||||||
|
setHasInitializedCurrentRecordSorts,
|
||||||
|
]);
|
||||||
|
|
||||||
|
return null;
|
||||||
|
};
|
||||||
@ -1,7 +1,8 @@
|
|||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
|
|
||||||
import { onSortSelectComponentState } from '@/object-record/object-sort-dropdown/states/onSortSelectScopedState';
|
import { onSortSelectComponentState } from '@/object-record/object-sort-dropdown/states/onSortSelectScopedState';
|
||||||
import { Sort } from '@/object-record/object-sort-dropdown/types/Sort';
|
import { useUpsertRecordSort } from '@/object-record/record-sort/hooks/useUpsertRecordSort';
|
||||||
|
import { RecordSort } from '@/object-record/record-sort/types/RecordSort';
|
||||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||||
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
||||||
import { useUpsertCombinedViewSorts } from '@/views/hooks/useUpsertCombinedViewSorts';
|
import { useUpsertCombinedViewSorts } from '@/views/hooks/useUpsertCombinedViewSorts';
|
||||||
@ -16,6 +17,8 @@ export const ViewBarSortEffect = () => {
|
|||||||
availableSortDefinitionsComponentState,
|
availableSortDefinitionsComponentState,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const { upsertRecordSort } = useUpsertRecordSort();
|
||||||
|
|
||||||
const setOnSortSelect = useSetRecoilComponentStateV2(
|
const setOnSortSelect = useSetRecoilComponentStateV2(
|
||||||
onSortSelectComponentState,
|
onSortSelectComponentState,
|
||||||
);
|
);
|
||||||
@ -28,9 +31,10 @@ export const ViewBarSortEffect = () => {
|
|||||||
if (isDefined(availableSortDefinitions)) {
|
if (isDefined(availableSortDefinitions)) {
|
||||||
setAvailableSortDefinitionsInSortDropdown(availableSortDefinitions);
|
setAvailableSortDefinitionsInSortDropdown(availableSortDefinitions);
|
||||||
}
|
}
|
||||||
setOnSortSelect(() => (sort: Sort | null) => {
|
setOnSortSelect(() => (sort: RecordSort | null) => {
|
||||||
if (isDefined(sort)) {
|
if (isDefined(sort)) {
|
||||||
upsertCombinedViewSort(sort);
|
upsertCombinedViewSort(sort);
|
||||||
|
upsertRecordSort(sort);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}, [
|
}, [
|
||||||
@ -38,6 +42,7 @@ export const ViewBarSortEffect = () => {
|
|||||||
setAvailableSortDefinitionsInSortDropdown,
|
setAvailableSortDefinitionsInSortDropdown,
|
||||||
setOnSortSelect,
|
setOnSortSelect,
|
||||||
upsertCombinedViewSort,
|
upsertCombinedViewSort,
|
||||||
|
upsertRecordSort,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return <></>;
|
return <></>;
|
||||||
|
|||||||
@ -2,7 +2,7 @@ import { useRecoilCallback } from 'recoil';
|
|||||||
import { v4 } from 'uuid';
|
import { v4 } from 'uuid';
|
||||||
|
|
||||||
import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState';
|
import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState';
|
||||||
import { Sort } from '@/object-record/object-sort-dropdown/types/Sort';
|
import { RecordSort } from '@/object-record/record-sort/types/RecordSort';
|
||||||
import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue';
|
import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue';
|
||||||
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
|
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
|
||||||
import { useGetViewFromPrefetchState } from '@/views/hooks/useGetViewFromPrefetchState';
|
import { useGetViewFromPrefetchState } from '@/views/hooks/useGetViewFromPrefetchState';
|
||||||
@ -32,7 +32,7 @@ export const useUpsertCombinedViewSorts = (viewBarComponentId?: string) => {
|
|||||||
|
|
||||||
const upsertCombinedViewSort = useRecoilCallback(
|
const upsertCombinedViewSort = useRecoilCallback(
|
||||||
({ snapshot, set }) =>
|
({ snapshot, set }) =>
|
||||||
async (upsertedSort: Sort) => {
|
async (upsertedSort: RecordSort) => {
|
||||||
const currentViewId = getSnapshotValue(
|
const currentViewId = getSnapshotValue(
|
||||||
snapshot,
|
snapshot,
|
||||||
currentViewIdCallbackState,
|
currentViewIdCallbackState,
|
||||||
|
|||||||
@ -0,0 +1,9 @@
|
|||||||
|
import { RecordSortsComponentInstanceContext } from '@/object-record/record-sort/states/context/RecordSortsComponentInstanceContext';
|
||||||
|
import { createComponentFamilyStateV2 } from '@/ui/utilities/state/component-state/utils/createComponentFamilyStateV2';
|
||||||
|
|
||||||
|
export const hasInitializedCurrentRecordSortsComponentFamilyState =
|
||||||
|
createComponentFamilyStateV2<boolean, { viewId?: string }>({
|
||||||
|
key: 'hasInitializedCurrentRecordSortsComponentFamilyState',
|
||||||
|
defaultValue: false,
|
||||||
|
componentInstanceContext: RecordSortsComponentInstanceContext,
|
||||||
|
});
|
||||||
@ -1,8 +1,8 @@
|
|||||||
import { SortDirection } from '@/object-record/object-sort-dropdown/types/SortDirection';
|
import { RecordSortDirection } from '@/object-record/record-sort/types/RecordSortDirection';
|
||||||
|
|
||||||
export type ViewSort = {
|
export type ViewSort = {
|
||||||
__typename: 'ViewSort';
|
__typename: 'ViewSort';
|
||||||
id: string;
|
id: string;
|
||||||
fieldMetadataId: string;
|
fieldMetadataId: string;
|
||||||
direction: SortDirection;
|
direction: RecordSortDirection;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import { Sort } from '@/object-record/object-sort-dropdown/types/Sort';
|
|
||||||
import { FieldMetadata } from '@/object-record/record-field/types/FieldMetadata';
|
import { FieldMetadata } from '@/object-record/record-field/types/FieldMetadata';
|
||||||
import { RecordFilter } from '@/object-record/record-filter/types/RecordFilter';
|
import { RecordFilter } from '@/object-record/record-filter/types/RecordFilter';
|
||||||
|
import { RecordSort } from '@/object-record/record-sort/types/RecordSort';
|
||||||
import { ColumnDefinition } from '@/object-record/record-table/types/ColumnDefinition';
|
import { ColumnDefinition } from '@/object-record/record-table/types/ColumnDefinition';
|
||||||
import { ViewField } from '@/views/types/ViewField';
|
import { ViewField } from '@/views/types/ViewField';
|
||||||
import { ViewFilter } from '@/views/types/ViewFilter';
|
import { ViewFilter } from '@/views/types/ViewFilter';
|
||||||
@ -39,8 +39,9 @@ describe('mapViewSortsToSorts', () => {
|
|||||||
direction: 'asc',
|
direction: 'asc',
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
const expectedSorts: Sort[] = [
|
const expectedSorts: RecordSort[] = [
|
||||||
{
|
{
|
||||||
|
id: 'id',
|
||||||
fieldMetadataId: '05731f68-6e7a-4903-8374-c0b6a9063482',
|
fieldMetadataId: '05731f68-6e7a-4903-8374-c0b6a9063482',
|
||||||
direction: 'asc',
|
direction: 'asc',
|
||||||
definition: baseDefinition,
|
definition: baseDefinition,
|
||||||
|
|||||||
@ -1,13 +1,13 @@
|
|||||||
import { Sort } from '@/object-record/object-sort-dropdown/types/Sort';
|
|
||||||
import { SortDefinition } from '@/object-record/object-sort-dropdown/types/SortDefinition';
|
import { SortDefinition } from '@/object-record/object-sort-dropdown/types/SortDefinition';
|
||||||
import { isDefined } from 'twenty-shared';
|
import { isDefined } from 'twenty-shared';
|
||||||
|
|
||||||
|
import { RecordSort } from '@/object-record/record-sort/types/RecordSort';
|
||||||
import { ViewSort } from '../types/ViewSort';
|
import { ViewSort } from '../types/ViewSort';
|
||||||
|
|
||||||
export const mapViewSortsToSorts = (
|
export const mapViewSortsToSorts = (
|
||||||
viewSorts: ViewSort[],
|
viewSorts: ViewSort[],
|
||||||
availableSortDefinitions: SortDefinition[],
|
availableSortDefinitions: SortDefinition[],
|
||||||
): Sort[] => {
|
): RecordSort[] => {
|
||||||
return viewSorts
|
return viewSorts
|
||||||
.map((viewSort) => {
|
.map((viewSort) => {
|
||||||
const availableSortDefinition = availableSortDefinitions.find(
|
const availableSortDefinition = availableSortDefinitions.find(
|
||||||
@ -16,7 +16,9 @@ export const mapViewSortsToSorts = (
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (!availableSortDefinition) return null;
|
if (!availableSortDefinition) return null;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
id: viewSort.id,
|
||||||
fieldMetadataId: viewSort.fieldMetadataId,
|
fieldMetadataId: viewSort.fieldMetadataId,
|
||||||
direction: viewSort.direction,
|
direction: viewSort.direction,
|
||||||
definition: availableSortDefinition,
|
definition: availableSortDefinition,
|
||||||
|
|||||||
Reference in New Issue
Block a user