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:
@ -1,36 +1,42 @@
|
||||
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 { useDeleteCombinedViewSorts } from '@/views/hooks/useDeleteCombinedViewSorts';
|
||||
import { useUpsertCombinedViewSorts } from '@/views/hooks/useUpsertCombinedViewSorts';
|
||||
|
||||
type EditableSortChipProps = {
|
||||
viewSort: Sort;
|
||||
recordSort: RecordSort;
|
||||
};
|
||||
|
||||
export const EditableSortChip = ({ viewSort }: EditableSortChipProps) => {
|
||||
export const EditableSortChip = ({ recordSort }: EditableSortChipProps) => {
|
||||
const { deleteCombinedViewSort } = useDeleteCombinedViewSorts();
|
||||
|
||||
const { upsertCombinedViewSort } = useUpsertCombinedViewSorts();
|
||||
|
||||
const { upsertRecordSort } = useUpsertRecordSort();
|
||||
|
||||
const handleRemoveClick = () => {
|
||||
deleteCombinedViewSort(viewSort.fieldMetadataId);
|
||||
deleteCombinedViewSort(recordSort.fieldMetadataId);
|
||||
};
|
||||
|
||||
const handleClick = () => {
|
||||
upsertCombinedViewSort({
|
||||
...viewSort,
|
||||
direction: viewSort.direction === 'asc' ? 'desc' : 'asc',
|
||||
});
|
||||
const newSort: RecordSort = {
|
||||
...recordSort,
|
||||
direction: recordSort.direction === 'asc' ? 'desc' : 'asc',
|
||||
};
|
||||
|
||||
upsertCombinedViewSort(newSort);
|
||||
upsertRecordSort(newSort);
|
||||
};
|
||||
|
||||
return (
|
||||
<SortOrFilterChip
|
||||
key={viewSort.fieldMetadataId}
|
||||
testId={viewSort.fieldMetadataId}
|
||||
labelValue={viewSort.definition.label}
|
||||
Icon={viewSort.direction === 'desc' ? IconArrowDown : IconArrowUp}
|
||||
key={recordSort.fieldMetadataId}
|
||||
testId={recordSort.fieldMetadataId}
|
||||
labelValue={recordSort.definition.label}
|
||||
Icon={recordSort.direction === 'desc' ? IconArrowDown : IconArrowUp}
|
||||
onRemove={handleRemoveClick}
|
||||
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 { ObjectSortDropdownComponentInstanceContext } from '@/object-record/object-sort-dropdown/states/context/ObjectSortDropdownComponentInstanceContext';
|
||||
import { ViewBarRecordFilterEffect } from '@/views/components/ViewBarRecordFilterEffect';
|
||||
import { ViewBarRecordSortEffect } from '@/views/components/ViewBarRecordSortEffect';
|
||||
import { UpdateViewButtonGroup } from './UpdateViewButtonGroup';
|
||||
import { ViewBarDetails } from './ViewBarDetails';
|
||||
|
||||
@ -48,6 +49,7 @@ export const ViewBar = ({
|
||||
value={{ instanceId: VIEW_SORT_DROPDOWN_ID }}
|
||||
>
|
||||
<ViewBarRecordFilterEffect />
|
||||
<ViewBarRecordSortEffect />
|
||||
<ViewBarFilterEffect filterDropdownId={filterDropdownId} />
|
||||
<ViewBarSortEffect />
|
||||
<QueryParamsFiltersEffect />
|
||||
|
||||
@ -204,8 +204,11 @@ export const ViewBarDetails = ({
|
||||
{mapViewSortsToSorts(
|
||||
currentViewWithCombinedFiltersAndSorts?.viewSorts ?? [],
|
||||
availableSortDefinitions,
|
||||
).map((sort) => (
|
||||
<EditableSortChip key={sort.fieldMetadataId} viewSort={sort} />
|
||||
).map((recordSort) => (
|
||||
<EditableSortChip
|
||||
key={recordSort.fieldMetadataId}
|
||||
recordSort={recordSort}
|
||||
/>
|
||||
))}
|
||||
{isNonEmptyArray(recordFilters) &&
|
||||
isNonEmptyArray(
|
||||
|
||||
@ -21,6 +21,12 @@ export const ViewBarRecordFilterEffect = () => {
|
||||
contextStoreCurrentObjectMetadataItemComponentState,
|
||||
);
|
||||
|
||||
const currentView = useRecoilValue(
|
||||
prefetchViewFromViewIdFamilySelector({
|
||||
viewId: currentViewId ?? '',
|
||||
}),
|
||||
);
|
||||
|
||||
const [
|
||||
hasInitializedCurrentRecordFilters,
|
||||
setHasInitializedCurrentRecordFilters,
|
||||
@ -43,12 +49,6 @@ export const ViewBarRecordFilterEffect = () => {
|
||||
contextStoreCurrentObjectMetadataItem?.id,
|
||||
);
|
||||
|
||||
const currentView = useRecoilValue(
|
||||
prefetchViewFromViewIdFamilySelector({
|
||||
viewId: currentViewId ?? '',
|
||||
}),
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (isDefined(currentView) && !hasInitializedCurrentRecordFilters) {
|
||||
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 { 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 { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
||||
import { useUpsertCombinedViewSorts } from '@/views/hooks/useUpsertCombinedViewSorts';
|
||||
@ -16,6 +17,8 @@ export const ViewBarSortEffect = () => {
|
||||
availableSortDefinitionsComponentState,
|
||||
);
|
||||
|
||||
const { upsertRecordSort } = useUpsertRecordSort();
|
||||
|
||||
const setOnSortSelect = useSetRecoilComponentStateV2(
|
||||
onSortSelectComponentState,
|
||||
);
|
||||
@ -28,9 +31,10 @@ export const ViewBarSortEffect = () => {
|
||||
if (isDefined(availableSortDefinitions)) {
|
||||
setAvailableSortDefinitionsInSortDropdown(availableSortDefinitions);
|
||||
}
|
||||
setOnSortSelect(() => (sort: Sort | null) => {
|
||||
setOnSortSelect(() => (sort: RecordSort | null) => {
|
||||
if (isDefined(sort)) {
|
||||
upsertCombinedViewSort(sort);
|
||||
upsertRecordSort(sort);
|
||||
}
|
||||
});
|
||||
}, [
|
||||
@ -38,6 +42,7 @@ export const ViewBarSortEffect = () => {
|
||||
setAvailableSortDefinitionsInSortDropdown,
|
||||
setOnSortSelect,
|
||||
upsertCombinedViewSort,
|
||||
upsertRecordSort,
|
||||
]);
|
||||
|
||||
return <></>;
|
||||
|
||||
@ -2,7 +2,7 @@ import { useRecoilCallback } from 'recoil';
|
||||
import { v4 } from 'uuid';
|
||||
|
||||
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 { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
|
||||
import { useGetViewFromPrefetchState } from '@/views/hooks/useGetViewFromPrefetchState';
|
||||
@ -32,7 +32,7 @@ export const useUpsertCombinedViewSorts = (viewBarComponentId?: string) => {
|
||||
|
||||
const upsertCombinedViewSort = useRecoilCallback(
|
||||
({ snapshot, set }) =>
|
||||
async (upsertedSort: Sort) => {
|
||||
async (upsertedSort: RecordSort) => {
|
||||
const currentViewId = getSnapshotValue(
|
||||
snapshot,
|
||||
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 = {
|
||||
__typename: 'ViewSort';
|
||||
id: 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 { 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 { ViewField } from '@/views/types/ViewField';
|
||||
import { ViewFilter } from '@/views/types/ViewFilter';
|
||||
@ -39,8 +39,9 @@ describe('mapViewSortsToSorts', () => {
|
||||
direction: 'asc',
|
||||
},
|
||||
];
|
||||
const expectedSorts: Sort[] = [
|
||||
const expectedSorts: RecordSort[] = [
|
||||
{
|
||||
id: 'id',
|
||||
fieldMetadataId: '05731f68-6e7a-4903-8374-c0b6a9063482',
|
||||
direction: 'asc',
|
||||
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 { isDefined } from 'twenty-shared';
|
||||
|
||||
import { RecordSort } from '@/object-record/record-sort/types/RecordSort';
|
||||
import { ViewSort } from '../types/ViewSort';
|
||||
|
||||
export const mapViewSortsToSorts = (
|
||||
viewSorts: ViewSort[],
|
||||
availableSortDefinitions: SortDefinition[],
|
||||
): Sort[] => {
|
||||
): RecordSort[] => {
|
||||
return viewSorts
|
||||
.map((viewSort) => {
|
||||
const availableSortDefinition = availableSortDefinitions.find(
|
||||
@ -16,7 +16,9 @@ export const mapViewSortsToSorts = (
|
||||
);
|
||||
|
||||
if (!availableSortDefinition) return null;
|
||||
|
||||
return {
|
||||
id: viewSort.id,
|
||||
fieldMetadataId: viewSort.fieldMetadataId,
|
||||
direction: viewSort.direction,
|
||||
definition: availableSortDefinition,
|
||||
|
||||
Reference in New Issue
Block a user