Added one request per column on board. (#5819)

- Changed to one find many request per column on board.
This commit is contained in:
Lucas Bordeau 2024-06-11 12:29:33 +02:00 committed by GitHub
parent 9307d206c5
commit 25a38dc693
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 287 additions and 60 deletions

View File

@ -2,6 +2,7 @@ import { useRecoilCallback } from 'recoil';
import { useRecordBoardStates } from '@/object-record/record-board/hooks/internal/useRecordBoardStates'; import { useRecordBoardStates } from '@/object-record/record-board/hooks/internal/useRecordBoardStates';
import { ObjectRecord } from '@/object-record/types/ObjectRecord'; import { ObjectRecord } from '@/object-record/types/ObjectRecord';
import { sortRecordsByPosition } from '@/object-record/utils/sortRecordsByPosition';
import { isDeeplyEqual } from '~/utils/isDeeplyEqual'; import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
export const useSetRecordBoardRecordIds = (recordBoardId?: string) => { export const useSetRecordBoardRecordIds = (recordBoardId?: string) => {
@ -60,21 +61,3 @@ export const useSetRecordBoardRecordIds = (recordBoardId?: string) => {
setRecordIds, 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;
}
};

View File

@ -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,
};
};

View File

@ -3,6 +3,7 @@ import { useSetRecoilState } from 'recoil';
import { useRecordBoardStates } from '@/object-record/record-board/hooks/internal/useRecordBoardStates'; import { useRecordBoardStates } from '@/object-record/record-board/hooks/internal/useRecordBoardStates';
import { useSetRecordBoardColumns } from '@/object-record/record-board/hooks/internal/useSetRecordBoardColumns'; import { useSetRecordBoardColumns } from '@/object-record/record-board/hooks/internal/useSetRecordBoardColumns';
import { useSetRecordBoardRecordIds } from '@/object-record/record-board/hooks/internal/useSetRecordBoardRecordIds'; 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) => { export const useRecordBoard = (recordBoardId?: string) => {
const { const {
@ -17,6 +18,8 @@ export const useRecordBoard = (recordBoardId?: string) => {
const { setColumns } = useSetRecordBoardColumns(recordBoardId); const { setColumns } = useSetRecordBoardColumns(recordBoardId);
const { setRecordIds } = useSetRecordBoardRecordIds(recordBoardId); const { setRecordIds } = useSetRecordBoardRecordIds(recordBoardId);
const { setRecordIdsForColumn } = useSetRecordIdsForColumn(recordBoardId);
const setFieldDefinitions = useSetRecoilState(fieldDefinitionsState); const setFieldDefinitions = useSetRecoilState(fieldDefinitionsState);
const setObjectSingularName = useSetRecoilState(objectSingularNameState); const setObjectSingularName = useSetRecoilState(objectSingularNameState);
const setKanbanFieldMetadataName = useSetRecoilState( const setKanbanFieldMetadataName = useSetRecoilState(
@ -33,5 +36,6 @@ export const useRecordBoard = (recordBoardId?: string) => {
selectedRecordIdsSelector, selectedRecordIdsSelector,
isCompactModeActiveState, isCompactModeActiveState,
shouldFetchMoreSelector, shouldFetchMoreSelector,
setRecordIdsForColumn,
}; };
}; };

View File

@ -23,15 +23,15 @@ export const RecordBoardColumnFetchMoreLoader = () => {
useRecordBoardStates(); useRecordBoardStates();
const isFetchingRecord = useRecoilValue(isFetchingRecordState); const isFetchingRecord = useRecoilValue(isFetchingRecordState);
const shouldFetchMore = useSetRecoilState( const setShouldFetchMore = useSetRecoilState(
shouldFetchMoreInColumnFamilyState(columnDefinition.id), shouldFetchMoreInColumnFamilyState(columnDefinition.id),
); );
const { ref, inView } = useInView(); const { ref, inView } = useInView();
useEffect(() => { useEffect(() => {
shouldFetchMore(inView); setShouldFetchMore(inView);
}, [shouldFetchMore, inView]); }, [setShouldFetchMore, inView]);
return ( return (
<div ref={ref}> <div ref={ref}>

View File

@ -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 <></>;
};

View File

@ -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]}
/>
))}
</>
);
};

View File

@ -1,51 +1,62 @@
import { useCallback, useEffect } from 'react'; import { useCallback, useEffect } from 'react';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import { useRecoilValue } from 'recoil'; import { useRecoilValue, useSetRecoilState } from 'recoil';
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
import { useRecordActionBar } from '@/object-record/record-action-bar/hooks/useRecordActionBar'; import { useRecordActionBar } from '@/object-record/record-action-bar/hooks/useRecordActionBar';
import { useRecordBoard } from '@/object-record/record-board/hooks/useRecordBoard'; import { useRecordBoard } from '@/object-record/record-board/hooks/useRecordBoard';
import { useRecordBoardSelection } from '@/object-record/record-board/hooks/useRecordBoardSelection'; 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 { 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 { recordIndexKanbanFieldMetadataIdState } from '@/object-record/record-index/states/recordIndexKanbanFieldMetadataIdState';
import { computeRecordBoardColumnDefinitionsFromObjectMetadata } from '@/object-record/utils/computeRecordBoardColumnDefinitionsFromObjectMetadata'; import { computeRecordBoardColumnDefinitionsFromObjectMetadata } from '@/object-record/utils/computeRecordBoardColumnDefinitionsFromObjectMetadata';
import { FieldMetadataType } from '~/generated-metadata/graphql'; import { FieldMetadataType } from '~/generated-metadata/graphql';
import { isDefined } from '~/utils/isDefined'; import { isDefined } from '~/utils/isDefined';
type RecordIndexBoardContainerEffectProps = { type RecordIndexBoardDataLoaderEffectProps = {
objectNameSingular: string; objectNameSingular: string;
recordBoardId: string; recordBoardId: string;
viewBarId: string;
}; };
export const RecordIndexBoardContainerEffect = ({ export const RecordIndexBoardDataLoaderEffect = ({
objectNameSingular, objectNameSingular,
recordBoardId, recordBoardId,
viewBarId, }: RecordIndexBoardDataLoaderEffectProps) => {
}: RecordIndexBoardContainerEffectProps) => {
const { objectMetadataItem } = useObjectMetadataItem({ const { objectMetadataItem } = useObjectMetadataItem({
objectNameSingular, 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 { const {
setColumns, setColumns,
setObjectSingularName, setObjectSingularName,
selectedRecordIdsSelector, selectedRecordIdsSelector,
setFieldDefinitions, setFieldDefinitions,
shouldFetchMoreSelector,
setKanbanFieldMetadataName, setKanbanFieldMetadataName,
} = useRecordBoard(recordBoardId); } = useRecordBoard(recordBoardId);
const { fetchMoreRecords, loading } = useLoadRecordIndexBoard({ useEffect(() => {
objectNameSingular, setFieldDefinitions(recordIndexFieldDefinitions);
recordBoardId, }, [recordIndexFieldDefinitions, setFieldDefinitions]);
viewBarId,
});
const recordIndexKanbanFieldMetadataId = useRecoilValue(
recordIndexKanbanFieldMetadataIdState,
);
const navigate = useNavigate(); const navigate = useNavigate();
@ -53,21 +64,6 @@ export const RecordIndexBoardContainerEffect = ({
navigate(`/settings/objects/${objectMetadataItem.namePlural}`); navigate(`/settings/objects/${objectMetadataItem.namePlural}`);
}, [navigate, 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); const { resetRecordSelection } = useRecordBoardSelection(recordBoardId);
useEffect(() => { useEffect(() => {
@ -90,10 +86,6 @@ export const RecordIndexBoardContainerEffect = ({
setColumns, setColumns,
]); ]);
const recordIndexFieldDefinitions = useRecoilValue(
recordIndexFieldDefinitionsState,
);
useEffect(() => { useEffect(() => {
setFieldDefinitions(recordIndexFieldDefinitions); setFieldDefinitions(recordIndexFieldDefinitions);
}, [objectMetadataItem, setFieldDefinitions, recordIndexFieldDefinitions]); }, [objectMetadataItem, setFieldDefinitions, recordIndexFieldDefinitions]);

View File

@ -5,7 +5,8 @@ import { useColumnDefinitionsFromFieldMetadata } from '@/object-metadata/hooks/u
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
import { useObjectNameSingularFromPlural } from '@/object-metadata/hooks/useObjectNameSingularFromPlural'; import { useObjectNameSingularFromPlural } from '@/object-metadata/hooks/useObjectNameSingularFromPlural';
import { RecordIndexBoardContainer } from '@/object-record/record-index/components/RecordIndexBoardContainer'; 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 { RecordIndexTableContainer } from '@/object-record/record-index/components/RecordIndexTableContainer';
import { RecordIndexTableContainerEffect } from '@/object-record/record-index/components/RecordIndexTableContainerEffect'; import { RecordIndexTableContainerEffect } from '@/object-record/record-index/components/RecordIndexTableContainerEffect';
import { RecordIndexViewBarEffect } from '@/object-record/record-index/components/RecordIndexViewBarEffect'; import { RecordIndexViewBarEffect } from '@/object-record/record-index/components/RecordIndexViewBarEffect';
@ -170,10 +171,13 @@ export const RecordIndexContainer = ({
objectNameSingular={objectNameSingular} objectNameSingular={objectNameSingular}
createRecord={createRecord} createRecord={createRecord}
/> />
<RecordIndexBoardContainerEffect <RecordIndexBoardDataLoader
objectNameSingular={objectNameSingular}
recordBoardId={recordIndexId}
/>
<RecordIndexBoardDataLoaderEffect
objectNameSingular={objectNameSingular} objectNameSingular={objectNameSingular}
recordBoardId={recordIndexId} recordBoardId={recordIndexId}
viewBarId={recordIndexId}
/> />
</> </>
)} )}

View File

@ -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,
};
};

View File

@ -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;
}
};