mirror of
https://github.com/twentyhq/twenty.git
synced 2024-12-26 13:31:45 +03:00
Added one request per column on board. (#5819)
- Changed to one find many request per column on board.
This commit is contained in:
parent
9307d206c5
commit
25a38dc693
@ -2,6 +2,7 @@ import { useRecoilCallback } from 'recoil';
|
||||
|
||||
import { useRecordBoardStates } from '@/object-record/record-board/hooks/internal/useRecordBoardStates';
|
||||
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
|
||||
import { sortRecordsByPosition } from '@/object-record/utils/sortRecordsByPosition';
|
||||
import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
|
||||
|
||||
export const useSetRecordBoardRecordIds = (recordBoardId?: string) => {
|
||||
@ -60,21 +61,3 @@ export const useSetRecordBoardRecordIds = (recordBoardId?: string) => {
|
||||
setRecordIds,
|
||||
};
|
||||
};
|
||||
|
||||
const sortRecordsByPosition = (
|
||||
record1: ObjectRecord,
|
||||
record2: ObjectRecord,
|
||||
) => {
|
||||
if (
|
||||
typeof record1.position == 'number' &&
|
||||
typeof record2.position == 'number'
|
||||
) {
|
||||
return record1.position - record2.position;
|
||||
} else if (record1.position === 'first' || record2.position === 'last') {
|
||||
return -1;
|
||||
} else if (record2.position === 'first' || record1.position === 'last') {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
@ -0,0 +1,55 @@
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
|
||||
import { useRecordBoardStates } from '@/object-record/record-board/hooks/internal/useRecordBoardStates';
|
||||
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
|
||||
import { sortRecordsByPosition } from '@/object-record/utils/sortRecordsByPosition';
|
||||
import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
|
||||
|
||||
export const useSetRecordIdsForColumn = (recordBoardId?: string) => {
|
||||
const {
|
||||
scopeId,
|
||||
recordIdsByColumnIdFamilyState,
|
||||
columnsFamilySelector,
|
||||
kanbanFieldMetadataNameState,
|
||||
} = useRecordBoardStates(recordBoardId);
|
||||
|
||||
const setRecordIdsForColumn = useRecoilCallback(
|
||||
({ set, snapshot }) =>
|
||||
(columnId: string, records: ObjectRecord[]) => {
|
||||
const column = snapshot
|
||||
.getLoadable(columnsFamilySelector(columnId))
|
||||
.getValue();
|
||||
|
||||
const existingColumnRecordIds = snapshot
|
||||
.getLoadable(recordIdsByColumnIdFamilyState(columnId))
|
||||
.getValue();
|
||||
|
||||
const kanbanFieldMetadataName = snapshot
|
||||
.getLoadable(kanbanFieldMetadataNameState)
|
||||
.getValue();
|
||||
|
||||
if (!kanbanFieldMetadataName) {
|
||||
return;
|
||||
}
|
||||
|
||||
const columnRecordIds = records
|
||||
.filter((record) => record[kanbanFieldMetadataName] === column?.value)
|
||||
.sort(sortRecordsByPosition)
|
||||
.map((record) => record.id);
|
||||
|
||||
if (!isDeeplyEqual(existingColumnRecordIds, columnRecordIds)) {
|
||||
set(recordIdsByColumnIdFamilyState(columnId), columnRecordIds);
|
||||
}
|
||||
},
|
||||
[
|
||||
columnsFamilySelector,
|
||||
recordIdsByColumnIdFamilyState,
|
||||
kanbanFieldMetadataNameState,
|
||||
],
|
||||
);
|
||||
|
||||
return {
|
||||
scopeId,
|
||||
setRecordIdsForColumn,
|
||||
};
|
||||
};
|
@ -3,6 +3,7 @@ import { useSetRecoilState } from 'recoil';
|
||||
import { useRecordBoardStates } from '@/object-record/record-board/hooks/internal/useRecordBoardStates';
|
||||
import { useSetRecordBoardColumns } from '@/object-record/record-board/hooks/internal/useSetRecordBoardColumns';
|
||||
import { useSetRecordBoardRecordIds } from '@/object-record/record-board/hooks/internal/useSetRecordBoardRecordIds';
|
||||
import { useSetRecordIdsForColumn } from '@/object-record/record-board/hooks/internal/useSetRecordIdsForColumn';
|
||||
|
||||
export const useRecordBoard = (recordBoardId?: string) => {
|
||||
const {
|
||||
@ -17,6 +18,8 @@ export const useRecordBoard = (recordBoardId?: string) => {
|
||||
|
||||
const { setColumns } = useSetRecordBoardColumns(recordBoardId);
|
||||
const { setRecordIds } = useSetRecordBoardRecordIds(recordBoardId);
|
||||
const { setRecordIdsForColumn } = useSetRecordIdsForColumn(recordBoardId);
|
||||
|
||||
const setFieldDefinitions = useSetRecoilState(fieldDefinitionsState);
|
||||
const setObjectSingularName = useSetRecoilState(objectSingularNameState);
|
||||
const setKanbanFieldMetadataName = useSetRecoilState(
|
||||
@ -33,5 +36,6 @@ export const useRecordBoard = (recordBoardId?: string) => {
|
||||
selectedRecordIdsSelector,
|
||||
isCompactModeActiveState,
|
||||
shouldFetchMoreSelector,
|
||||
setRecordIdsForColumn,
|
||||
};
|
||||
};
|
||||
|
@ -23,15 +23,15 @@ export const RecordBoardColumnFetchMoreLoader = () => {
|
||||
useRecordBoardStates();
|
||||
const isFetchingRecord = useRecoilValue(isFetchingRecordState);
|
||||
|
||||
const shouldFetchMore = useSetRecoilState(
|
||||
const setShouldFetchMore = useSetRecoilState(
|
||||
shouldFetchMoreInColumnFamilyState(columnDefinition.id),
|
||||
);
|
||||
|
||||
const { ref, inView } = useInView();
|
||||
|
||||
useEffect(() => {
|
||||
shouldFetchMore(inView);
|
||||
}, [shouldFetchMore, inView]);
|
||||
setShouldFetchMore(inView);
|
||||
}, [setShouldFetchMore, inView]);
|
||||
|
||||
return (
|
||||
<div ref={ref}>
|
||||
|
@ -0,0 +1,39 @@
|
||||
import { useEffect } from 'react';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
|
||||
import { useRecordBoard } from '@/object-record/record-board/hooks/useRecordBoard';
|
||||
import { useLoadRecordIndexBoardColumn } from '@/object-record/record-index/hooks/useLoadRecordIndexBoardColumn';
|
||||
|
||||
export const RecordIndexBoardColumnLoaderEffect = ({
|
||||
objectNameSingular,
|
||||
boardFieldSelectValue,
|
||||
boardFieldMetadataId,
|
||||
recordBoardId,
|
||||
columnId,
|
||||
}: {
|
||||
recordBoardId: string;
|
||||
objectNameSingular: string;
|
||||
boardFieldSelectValue: string;
|
||||
boardFieldMetadataId: string | null;
|
||||
columnId: string;
|
||||
}) => {
|
||||
const { shouldFetchMoreSelector } = useRecordBoard(recordBoardId);
|
||||
|
||||
const shouldFetchMore = useRecoilValue(shouldFetchMoreSelector());
|
||||
|
||||
const { fetchMoreRecords, loading } = useLoadRecordIndexBoardColumn({
|
||||
objectNameSingular,
|
||||
recordBoardId,
|
||||
boardFieldMetadataId,
|
||||
columnFieldSelectValue: boardFieldSelectValue,
|
||||
columnId,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (!loading && shouldFetchMore) {
|
||||
fetchMoreRecords?.();
|
||||
}
|
||||
}, [fetchMoreRecords, loading, shouldFetchMore, boardFieldSelectValue]);
|
||||
|
||||
return <></>;
|
||||
};
|
@ -0,0 +1,50 @@
|
||||
import { useRecoilValue } from 'recoil';
|
||||
|
||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||
import { useRecordBoardStates } from '@/object-record/record-board/hooks/internal/useRecordBoardStates';
|
||||
import { RecordIndexBoardColumnLoaderEffect } from '@/object-record/record-index/components/RecordIndexBoardColumnLoaderEffect';
|
||||
import { recordIndexKanbanFieldMetadataIdState } from '@/object-record/record-index/states/recordIndexKanbanFieldMetadataIdState';
|
||||
|
||||
type RecordIndexBoardDataLoaderProps = {
|
||||
objectNameSingular: string;
|
||||
recordBoardId: string;
|
||||
};
|
||||
|
||||
export const RecordIndexBoardDataLoader = ({
|
||||
objectNameSingular,
|
||||
recordBoardId,
|
||||
}: RecordIndexBoardDataLoaderProps) => {
|
||||
const { objectMetadataItem } = useObjectMetadataItem({
|
||||
objectNameSingular,
|
||||
});
|
||||
|
||||
const recordIndexKanbanFieldMetadataId = useRecoilValue(
|
||||
recordIndexKanbanFieldMetadataIdState,
|
||||
);
|
||||
|
||||
const recordIndexKanbanFieldMetadataItem = objectMetadataItem.fields.find(
|
||||
(field) => field.id === recordIndexKanbanFieldMetadataId,
|
||||
);
|
||||
|
||||
const possibleKanbanSelectFieldValues =
|
||||
recordIndexKanbanFieldMetadataItem?.options ?? [];
|
||||
|
||||
const { columnIdsState } = useRecordBoardStates(recordBoardId);
|
||||
|
||||
// TODO: we should make sure there's no way to have a mismatch between columnIds and possibleKanbanSelectFieldValues order
|
||||
const columnIds = useRecoilValue(columnIdsState);
|
||||
|
||||
return (
|
||||
<>
|
||||
{possibleKanbanSelectFieldValues.map((option, index) => (
|
||||
<RecordIndexBoardColumnLoaderEffect
|
||||
objectNameSingular={objectNameSingular}
|
||||
boardFieldMetadataId={recordIndexKanbanFieldMetadataId}
|
||||
boardFieldSelectValue={option.value}
|
||||
recordBoardId={recordBoardId}
|
||||
columnId={columnIds[index]}
|
||||
/>
|
||||
))}
|
||||
</>
|
||||
);
|
||||
};
|
@ -1,51 +1,62 @@
|
||||
import { useCallback, useEffect } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import { useRecoilValue, useSetRecoilState } from 'recoil';
|
||||
|
||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||
import { useRecordActionBar } from '@/object-record/record-action-bar/hooks/useRecordActionBar';
|
||||
import { useRecordBoard } from '@/object-record/record-board/hooks/useRecordBoard';
|
||||
import { useRecordBoardSelection } from '@/object-record/record-board/hooks/useRecordBoardSelection';
|
||||
import { useLoadRecordIndexBoard } from '@/object-record/record-index/hooks/useLoadRecordIndexBoard';
|
||||
import { recordIndexFieldDefinitionsState } from '@/object-record/record-index/states/recordIndexFieldDefinitionsState';
|
||||
import { recordIndexIsCompactModeActiveState } from '@/object-record/record-index/states/recordIndexIsCompactModeActiveState';
|
||||
import { recordIndexKanbanFieldMetadataIdState } from '@/object-record/record-index/states/recordIndexKanbanFieldMetadataIdState';
|
||||
import { computeRecordBoardColumnDefinitionsFromObjectMetadata } from '@/object-record/utils/computeRecordBoardColumnDefinitionsFromObjectMetadata';
|
||||
import { FieldMetadataType } from '~/generated-metadata/graphql';
|
||||
import { isDefined } from '~/utils/isDefined';
|
||||
|
||||
type RecordIndexBoardContainerEffectProps = {
|
||||
type RecordIndexBoardDataLoaderEffectProps = {
|
||||
objectNameSingular: string;
|
||||
recordBoardId: string;
|
||||
viewBarId: string;
|
||||
};
|
||||
|
||||
export const RecordIndexBoardContainerEffect = ({
|
||||
export const RecordIndexBoardDataLoaderEffect = ({
|
||||
objectNameSingular,
|
||||
recordBoardId,
|
||||
viewBarId,
|
||||
}: RecordIndexBoardContainerEffectProps) => {
|
||||
}: RecordIndexBoardDataLoaderEffectProps) => {
|
||||
const { objectMetadataItem } = useObjectMetadataItem({
|
||||
objectNameSingular,
|
||||
});
|
||||
|
||||
const recordIndexFieldDefinitions = useRecoilValue(
|
||||
recordIndexFieldDefinitionsState,
|
||||
);
|
||||
|
||||
const recordIndexKanbanFieldMetadataId = useRecoilValue(
|
||||
recordIndexKanbanFieldMetadataIdState,
|
||||
);
|
||||
|
||||
const recordIndexIsCompactModeActive = useRecoilValue(
|
||||
recordIndexIsCompactModeActiveState,
|
||||
);
|
||||
|
||||
const { isCompactModeActiveState } = useRecordBoard(recordBoardId);
|
||||
|
||||
const setIsCompactModeActive = useSetRecoilState(isCompactModeActiveState);
|
||||
|
||||
useEffect(() => {
|
||||
setIsCompactModeActive(recordIndexIsCompactModeActive);
|
||||
}, [recordIndexIsCompactModeActive, setIsCompactModeActive]);
|
||||
|
||||
const {
|
||||
setColumns,
|
||||
setObjectSingularName,
|
||||
selectedRecordIdsSelector,
|
||||
setFieldDefinitions,
|
||||
shouldFetchMoreSelector,
|
||||
setKanbanFieldMetadataName,
|
||||
} = useRecordBoard(recordBoardId);
|
||||
|
||||
const { fetchMoreRecords, loading } = useLoadRecordIndexBoard({
|
||||
objectNameSingular,
|
||||
recordBoardId,
|
||||
viewBarId,
|
||||
});
|
||||
|
||||
const recordIndexKanbanFieldMetadataId = useRecoilValue(
|
||||
recordIndexKanbanFieldMetadataIdState,
|
||||
);
|
||||
useEffect(() => {
|
||||
setFieldDefinitions(recordIndexFieldDefinitions);
|
||||
}, [recordIndexFieldDefinitions, setFieldDefinitions]);
|
||||
|
||||
const navigate = useNavigate();
|
||||
|
||||
@ -53,21 +64,6 @@ export const RecordIndexBoardContainerEffect = ({
|
||||
navigate(`/settings/objects/${objectMetadataItem.namePlural}`);
|
||||
}, [navigate, objectMetadataItem.namePlural]);
|
||||
|
||||
const columnDefinitions =
|
||||
computeRecordBoardColumnDefinitionsFromObjectMetadata(
|
||||
objectMetadataItem,
|
||||
recordIndexKanbanFieldMetadataId ?? '',
|
||||
navigateToSelectSettings,
|
||||
);
|
||||
|
||||
const shouldFetchMore = useRecoilValue(shouldFetchMoreSelector());
|
||||
|
||||
useEffect(() => {
|
||||
if (!loading && shouldFetchMore) {
|
||||
fetchMoreRecords?.();
|
||||
}
|
||||
}, [columnDefinitions, fetchMoreRecords, loading, shouldFetchMore]);
|
||||
|
||||
const { resetRecordSelection } = useRecordBoardSelection(recordBoardId);
|
||||
|
||||
useEffect(() => {
|
||||
@ -90,10 +86,6 @@ export const RecordIndexBoardContainerEffect = ({
|
||||
setColumns,
|
||||
]);
|
||||
|
||||
const recordIndexFieldDefinitions = useRecoilValue(
|
||||
recordIndexFieldDefinitionsState,
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
setFieldDefinitions(recordIndexFieldDefinitions);
|
||||
}, [objectMetadataItem, setFieldDefinitions, recordIndexFieldDefinitions]);
|
@ -5,7 +5,8 @@ import { useColumnDefinitionsFromFieldMetadata } from '@/object-metadata/hooks/u
|
||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||
import { useObjectNameSingularFromPlural } from '@/object-metadata/hooks/useObjectNameSingularFromPlural';
|
||||
import { RecordIndexBoardContainer } from '@/object-record/record-index/components/RecordIndexBoardContainer';
|
||||
import { RecordIndexBoardContainerEffect } from '@/object-record/record-index/components/RecordIndexBoardContainerEffect';
|
||||
import { RecordIndexBoardDataLoader } from '@/object-record/record-index/components/RecordIndexBoardDataLoader';
|
||||
import { RecordIndexBoardDataLoaderEffect } from '@/object-record/record-index/components/RecordIndexBoardDataLoaderEffect';
|
||||
import { RecordIndexTableContainer } from '@/object-record/record-index/components/RecordIndexTableContainer';
|
||||
import { RecordIndexTableContainerEffect } from '@/object-record/record-index/components/RecordIndexTableContainerEffect';
|
||||
import { RecordIndexViewBarEffect } from '@/object-record/record-index/components/RecordIndexViewBarEffect';
|
||||
@ -170,10 +171,13 @@ export const RecordIndexContainer = ({
|
||||
objectNameSingular={objectNameSingular}
|
||||
createRecord={createRecord}
|
||||
/>
|
||||
<RecordIndexBoardContainerEffect
|
||||
<RecordIndexBoardDataLoader
|
||||
objectNameSingular={objectNameSingular}
|
||||
recordBoardId={recordIndexId}
|
||||
/>
|
||||
<RecordIndexBoardDataLoaderEffect
|
||||
objectNameSingular={objectNameSingular}
|
||||
recordBoardId={recordIndexId}
|
||||
viewBarId={recordIndexId}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
|
@ -0,0 +1,81 @@
|
||||
import { useEffect } from 'react';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
|
||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||
import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords';
|
||||
import { turnSortsIntoOrderBy } from '@/object-record/object-sort-dropdown/utils/turnSortsIntoOrderBy';
|
||||
import { useRecordBoard } from '@/object-record/record-board/hooks/useRecordBoard';
|
||||
import { turnObjectDropdownFilterIntoQueryFilter } from '@/object-record/record-filter/utils/turnObjectDropdownFilterIntoQueryFilter';
|
||||
import { useRecordBoardRecordGqlFields } from '@/object-record/record-index/hooks/useRecordBoardRecordGqlFields';
|
||||
import { recordIndexFiltersState } from '@/object-record/record-index/states/recordIndexFiltersState';
|
||||
import { recordIndexSortsState } from '@/object-record/record-index/states/recordIndexSortsState';
|
||||
import { useSetRecordInStore } from '@/object-record/record-store/hooks/useSetRecordInStore';
|
||||
|
||||
type UseLoadRecordIndexBoardProps = {
|
||||
objectNameSingular: string;
|
||||
boardFieldMetadataId: string | null;
|
||||
recordBoardId: string;
|
||||
columnFieldSelectValue: string;
|
||||
columnId: string;
|
||||
};
|
||||
|
||||
export const useLoadRecordIndexBoardColumn = ({
|
||||
objectNameSingular,
|
||||
boardFieldMetadataId,
|
||||
recordBoardId,
|
||||
columnFieldSelectValue,
|
||||
columnId,
|
||||
}: UseLoadRecordIndexBoardProps) => {
|
||||
const { objectMetadataItem } = useObjectMetadataItem({
|
||||
objectNameSingular,
|
||||
});
|
||||
const { setRecordIdsForColumn } = useRecordBoard(recordBoardId);
|
||||
const { setRecords: setRecordsInStore } = useSetRecordInStore();
|
||||
|
||||
const recordIndexFilters = useRecoilValue(recordIndexFiltersState);
|
||||
const recordIndexSorts = useRecoilValue(recordIndexSortsState);
|
||||
const requestFilters = turnObjectDropdownFilterIntoQueryFilter(
|
||||
recordIndexFilters,
|
||||
objectMetadataItem?.fields ?? [],
|
||||
);
|
||||
const orderBy = turnSortsIntoOrderBy(objectMetadataItem, recordIndexSorts);
|
||||
|
||||
const recordGqlFields = useRecordBoardRecordGqlFields({
|
||||
objectMetadataItem,
|
||||
recordBoardId,
|
||||
});
|
||||
|
||||
const recordIndexKanbanFieldMetadataItem = objectMetadataItem.fields.find(
|
||||
(field) => field.id === boardFieldMetadataId,
|
||||
);
|
||||
|
||||
const filter = {
|
||||
...requestFilters,
|
||||
[recordIndexKanbanFieldMetadataItem?.name ?? '']: {
|
||||
in: [columnFieldSelectValue],
|
||||
},
|
||||
};
|
||||
|
||||
const { records, loading, fetchMoreRecords, queryStateIdentifier } =
|
||||
useFindManyRecords({
|
||||
objectNameSingular,
|
||||
filter,
|
||||
orderBy,
|
||||
recordGqlFields,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
setRecordIdsForColumn(columnId, records);
|
||||
}, [records, setRecordIdsForColumn, columnId]);
|
||||
|
||||
useEffect(() => {
|
||||
setRecordsInStore(records);
|
||||
}, [records, setRecordsInStore]);
|
||||
|
||||
return {
|
||||
records,
|
||||
loading,
|
||||
fetchMoreRecords,
|
||||
queryStateIdentifier,
|
||||
};
|
||||
};
|
@ -0,0 +1,19 @@
|
||||
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
|
||||
|
||||
export const sortRecordsByPosition = (
|
||||
record1: ObjectRecord,
|
||||
record2: ObjectRecord,
|
||||
) => {
|
||||
if (
|
||||
typeof record1.position == 'number' &&
|
||||
typeof record2.position == 'number'
|
||||
) {
|
||||
return record1.position - record2.position;
|
||||
} else if (record1.position === 'first' || record2.position === 'last') {
|
||||
return -1;
|
||||
} else if (record2.position === 'first' || record1.position === 'last') {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
};
|
Loading…
Reference in New Issue
Block a user