Load all data on record boards (#5070)
## Context For users with many records, only the first n*60 records were loaded on board views (n being the number of visible columns). This was because of the following behavior: - watch for end of column visibility changes. If an end of column is visible, try to fetch more. However, watching for visbility changes is not reliable enough. ## What we want If an end of column is visible, try to fetch more. If no more records is availble in pagination, do not fetch more
This commit is contained in:
@ -4,16 +4,17 @@ import { isLastRecordBoardColumnComponentFamilyState } from '@/object-record/rec
|
|||||||
import { isRecordBoardCardSelectedComponentFamilyState } from '@/object-record/record-board/states/isRecordBoardCardSelectedComponentFamilyState';
|
import { isRecordBoardCardSelectedComponentFamilyState } from '@/object-record/record-board/states/isRecordBoardCardSelectedComponentFamilyState';
|
||||||
import { isRecordBoardCompactModeActiveComponentState } from '@/object-record/record-board/states/isRecordBoardCompactModeActiveComponentState';
|
import { isRecordBoardCompactModeActiveComponentState } from '@/object-record/record-board/states/isRecordBoardCompactModeActiveComponentState';
|
||||||
import { isRecordBoardFetchingRecordsComponentState } from '@/object-record/record-board/states/isRecordBoardFetchingRecordsComponentState';
|
import { isRecordBoardFetchingRecordsComponentState } from '@/object-record/record-board/states/isRecordBoardFetchingRecordsComponentState';
|
||||||
import { onRecordBoardFetchMoreVisibilityChangeComponentState } from '@/object-record/record-board/states/onRecordBoardFetchMoreVisibilityChangeComponentState';
|
|
||||||
import { recordBoardColumnIdsComponentState } from '@/object-record/record-board/states/recordBoardColumnIdsComponentState';
|
import { recordBoardColumnIdsComponentState } from '@/object-record/record-board/states/recordBoardColumnIdsComponentState';
|
||||||
import { recordBoardFieldDefinitionsComponentState } from '@/object-record/record-board/states/recordBoardFieldDefinitionsComponentState';
|
import { recordBoardFieldDefinitionsComponentState } from '@/object-record/record-board/states/recordBoardFieldDefinitionsComponentState';
|
||||||
import { recordBoardFiltersComponentState } from '@/object-record/record-board/states/recordBoardFiltersComponentState';
|
import { recordBoardFiltersComponentState } from '@/object-record/record-board/states/recordBoardFiltersComponentState';
|
||||||
import { recordBoardKanbanFieldMetadataNameComponentState } from '@/object-record/record-board/states/recordBoardKanbanFieldMetadataNameComponentState';
|
import { recordBoardKanbanFieldMetadataNameComponentState } from '@/object-record/record-board/states/recordBoardKanbanFieldMetadataNameComponentState';
|
||||||
import { recordBoardObjectSingularNameComponentState } from '@/object-record/record-board/states/recordBoardObjectSingularNameComponentState';
|
import { recordBoardObjectSingularNameComponentState } from '@/object-record/record-board/states/recordBoardObjectSingularNameComponentState';
|
||||||
import { recordBoardRecordIdsByColumnIdComponentFamilyState } from '@/object-record/record-board/states/recordBoardRecordIdsByColumnIdComponentFamilyState';
|
import { recordBoardRecordIdsByColumnIdComponentFamilyState } from '@/object-record/record-board/states/recordBoardRecordIdsByColumnIdComponentFamilyState';
|
||||||
|
import { recordBoardShouldFetchMoreInColumnComponentFamilyState } from '@/object-record/record-board/states/recordBoardShouldFetchMoreInColumnComponentFamilyState';
|
||||||
import { recordBoardSortsComponentState } from '@/object-record/record-board/states/recordBoardSortsComponentState';
|
import { recordBoardSortsComponentState } from '@/object-record/record-board/states/recordBoardSortsComponentState';
|
||||||
import { recordBoardColumnsComponentFamilySelector } from '@/object-record/record-board/states/selectors/recordBoardColumnsComponentFamilySelector';
|
import { recordBoardColumnsComponentFamilySelector } from '@/object-record/record-board/states/selectors/recordBoardColumnsComponentFamilySelector';
|
||||||
import { recordBoardSelectedRecordIdsComponentSelector } from '@/object-record/record-board/states/selectors/recordBoardSelectedRecordIdsComponentSelector';
|
import { recordBoardSelectedRecordIdsComponentSelector } from '@/object-record/record-board/states/selectors/recordBoardSelectedRecordIdsComponentSelector';
|
||||||
|
import { recordBoardShouldFetchMoreComponentSelector } from '@/object-record/record-board/states/selectors/recordBoardShouldFetchMoreComponentFamilySelector';
|
||||||
import { recordBoardVisibleFieldDefinitionsComponentSelector } from '@/object-record/record-board/states/selectors/recordBoardVisibleFieldDefinitionsComponentSelector';
|
import { recordBoardVisibleFieldDefinitionsComponentSelector } from '@/object-record/record-board/states/selectors/recordBoardVisibleFieldDefinitionsComponentSelector';
|
||||||
import { useAvailableScopeIdOrThrow } from '@/ui/utilities/recoil-scope/scopes-internal/hooks/useAvailableScopeId';
|
import { useAvailableScopeIdOrThrow } from '@/ui/utilities/recoil-scope/scopes-internal/hooks/useAvailableScopeId';
|
||||||
import { getScopeIdOrUndefinedFromComponentId } from '@/ui/utilities/recoil-scope/utils/getScopeIdOrUndefinedFromComponentId';
|
import { getScopeIdOrUndefinedFromComponentId } from '@/ui/utilities/recoil-scope/utils/getScopeIdOrUndefinedFromComponentId';
|
||||||
@ -90,8 +91,12 @@ export const useRecordBoardStates = (recordBoardId?: string) => {
|
|||||||
scopeId,
|
scopeId,
|
||||||
),
|
),
|
||||||
|
|
||||||
onFetchMoreVisibilityChangeState: extractComponentState(
|
shouldFetchMoreInColumnFamilyState: extractComponentFamilyState(
|
||||||
onRecordBoardFetchMoreVisibilityChangeComponentState,
|
recordBoardShouldFetchMoreInColumnComponentFamilyState,
|
||||||
|
scopeId,
|
||||||
|
),
|
||||||
|
shouldFetchMoreSelector: extractComponentReadOnlySelector(
|
||||||
|
recordBoardShouldFetchMoreComponentSelector,
|
||||||
scopeId,
|
scopeId,
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
|
|||||||
@ -11,8 +11,8 @@ export const useRecordBoard = (recordBoardId?: string) => {
|
|||||||
objectSingularNameState,
|
objectSingularNameState,
|
||||||
selectedRecordIdsSelector,
|
selectedRecordIdsSelector,
|
||||||
isCompactModeActiveState,
|
isCompactModeActiveState,
|
||||||
onFetchMoreVisibilityChangeState,
|
|
||||||
kanbanFieldMetadataNameState,
|
kanbanFieldMetadataNameState,
|
||||||
|
shouldFetchMoreSelector,
|
||||||
} = useRecordBoardStates(recordBoardId);
|
} = useRecordBoardStates(recordBoardId);
|
||||||
|
|
||||||
const { setColumns } = useSetRecordBoardColumns(recordBoardId);
|
const { setColumns } = useSetRecordBoardColumns(recordBoardId);
|
||||||
@ -32,6 +32,6 @@ export const useRecordBoard = (recordBoardId?: string) => {
|
|||||||
setKanbanFieldMetadataName,
|
setKanbanFieldMetadataName,
|
||||||
selectedRecordIdsSelector,
|
selectedRecordIdsSelector,
|
||||||
isCompactModeActiveState,
|
isCompactModeActiveState,
|
||||||
onFetchMoreVisibilityChangeState,
|
shouldFetchMoreSelector,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,8 +1,10 @@
|
|||||||
|
import { useContext, useEffect } from 'react';
|
||||||
import { useInView } from 'react-intersection-observer';
|
import { useInView } from 'react-intersection-observer';
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
import { useRecoilValue } from 'recoil';
|
import { useRecoilValue, useSetRecoilState } from 'recoil';
|
||||||
|
|
||||||
import { useRecordBoardStates } from '@/object-record/record-board/hooks/internal/useRecordBoardStates';
|
import { useRecordBoardStates } from '@/object-record/record-board/hooks/internal/useRecordBoardStates';
|
||||||
|
import { RecordBoardColumnContext } from '@/object-record/record-board/record-board-column/contexts/RecordBoardColumnContext';
|
||||||
import { GRAY_SCALE } from '@/ui/theme/constants/GrayScale';
|
import { GRAY_SCALE } from '@/ui/theme/constants/GrayScale';
|
||||||
|
|
||||||
const StyledText = styled.div`
|
const StyledText = styled.div`
|
||||||
@ -16,17 +18,20 @@ const StyledText = styled.div`
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
export const RecordBoardColumnFetchMoreLoader = () => {
|
export const RecordBoardColumnFetchMoreLoader = () => {
|
||||||
const { isFetchingRecordState, onFetchMoreVisibilityChangeState } =
|
const { columnDefinition } = useContext(RecordBoardColumnContext);
|
||||||
|
const { isFetchingRecordState, shouldFetchMoreInColumnFamilyState } =
|
||||||
useRecordBoardStates();
|
useRecordBoardStates();
|
||||||
const isFetchingRecord = useRecoilValue(isFetchingRecordState);
|
const isFetchingRecord = useRecoilValue(isFetchingRecordState);
|
||||||
|
|
||||||
const onFetchMoreVisibilityChange = useRecoilValue(
|
const shouldFetchMore = useSetRecoilState(
|
||||||
onFetchMoreVisibilityChangeState,
|
shouldFetchMoreInColumnFamilyState(columnDefinition.id),
|
||||||
);
|
);
|
||||||
|
|
||||||
const { ref } = useInView({
|
const { ref, inView } = useInView();
|
||||||
onChange: onFetchMoreVisibilityChange,
|
|
||||||
});
|
useEffect(() => {
|
||||||
|
shouldFetchMore(inView);
|
||||||
|
}, [shouldFetchMore, inView]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div ref={ref}>
|
<div ref={ref}>
|
||||||
|
|||||||
@ -1,7 +0,0 @@
|
|||||||
import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState';
|
|
||||||
|
|
||||||
export const onRecordBoardFetchMoreVisibilityChangeComponentState =
|
|
||||||
createComponentState<(visbility: boolean) => void>({
|
|
||||||
key: 'onRecordBoardFetchMoreVisibilityChangeComponentState',
|
|
||||||
defaultValue: () => {},
|
|
||||||
});
|
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
import { createComponentFamilyState } from '@/ui/utilities/state/component-state/utils/createComponentFamilyState';
|
||||||
|
|
||||||
|
export const recordBoardShouldFetchMoreInColumnComponentFamilyState =
|
||||||
|
createComponentFamilyState<boolean, string>({
|
||||||
|
key: 'onRecordBoardFetchMoreIrecordBoardShouldFetchMoreInColumnComponentFamilyStatesVisibleComponentFamilyState',
|
||||||
|
defaultValue: false,
|
||||||
|
});
|
||||||
@ -0,0 +1,28 @@
|
|||||||
|
import { recordBoardColumnIdsComponentState } from '@/object-record/record-board/states/recordBoardColumnIdsComponentState';
|
||||||
|
import { recordBoardShouldFetchMoreInColumnComponentFamilyState } from '@/object-record/record-board/states/recordBoardShouldFetchMoreInColumnComponentFamilyState';
|
||||||
|
import { createComponentReadOnlySelector } from '@/ui/utilities/state/component-state/utils/createComponentReadOnlySelector';
|
||||||
|
|
||||||
|
export const recordBoardShouldFetchMoreComponentSelector =
|
||||||
|
createComponentReadOnlySelector<boolean>({
|
||||||
|
key: 'recordBoardShouldFetchMoreComponentSelector',
|
||||||
|
get:
|
||||||
|
({ scopeId }: { scopeId: string }) =>
|
||||||
|
({ get }) => {
|
||||||
|
const columnIds = get(
|
||||||
|
recordBoardColumnIdsComponentState({
|
||||||
|
scopeId,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
const shouldFetchMoreInColumns = columnIds.map((columnId) => {
|
||||||
|
return get(
|
||||||
|
recordBoardShouldFetchMoreInColumnComponentFamilyState({
|
||||||
|
scopeId,
|
||||||
|
familyKey: columnId,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
return shouldFetchMoreInColumns.some(Boolean);
|
||||||
|
},
|
||||||
|
});
|
||||||
@ -1,6 +1,6 @@
|
|||||||
import { useCallback, useEffect } from 'react';
|
import { useCallback, useEffect } from 'react';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
import { useRecoilValue, useSetRecoilState } from 'recoil';
|
import { useRecoilValue } 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';
|
||||||
@ -33,7 +33,7 @@ export const RecordIndexBoardContainerEffect = ({
|
|||||||
setObjectSingularName,
|
setObjectSingularName,
|
||||||
selectedRecordIdsSelector,
|
selectedRecordIdsSelector,
|
||||||
setFieldDefinitions,
|
setFieldDefinitions,
|
||||||
onFetchMoreVisibilityChangeState,
|
shouldFetchMoreSelector,
|
||||||
setKanbanFieldMetadataName,
|
setKanbanFieldMetadataName,
|
||||||
} = useRecordBoard(recordBoardId);
|
} = useRecordBoard(recordBoardId);
|
||||||
|
|
||||||
@ -43,28 +43,31 @@ export const RecordIndexBoardContainerEffect = ({
|
|||||||
viewBarId,
|
viewBarId,
|
||||||
});
|
});
|
||||||
|
|
||||||
const setOnFetchMoreVisibilityChange = useSetRecoilState(
|
|
||||||
onFetchMoreVisibilityChangeState,
|
|
||||||
);
|
|
||||||
|
|
||||||
const recordIndexKanbanFieldMetadataId = useRecoilValue(
|
const recordIndexKanbanFieldMetadataId = useRecoilValue(
|
||||||
recordIndexKanbanFieldMetadataIdState,
|
recordIndexKanbanFieldMetadataIdState,
|
||||||
);
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
setOnFetchMoreVisibilityChange(() => () => {
|
|
||||||
if (!loading) {
|
|
||||||
fetchMoreRecords?.();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}, [fetchMoreRecords, loading, setOnFetchMoreVisibilityChange]);
|
|
||||||
|
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
|
||||||
const navigateToSelectSettings = useCallback(() => {
|
const navigateToSelectSettings = useCallback(() => {
|
||||||
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(() => {
|
||||||
|
|||||||
@ -166,7 +166,10 @@ export const ViewPickerCreateOrEditContent = () => {
|
|||||||
label="Stages"
|
label="Stages"
|
||||||
fullWidth
|
fullWidth
|
||||||
value={viewPickerKanbanFieldMetadataId}
|
value={viewPickerKanbanFieldMetadataId}
|
||||||
onChange={(value) => setViewPickerKanbanFieldMetadataId(value)}
|
onChange={(value) => {
|
||||||
|
setViewPickerIsDirty(true);
|
||||||
|
setViewPickerKanbanFieldMetadataId(value);
|
||||||
|
}}
|
||||||
options={
|
options={
|
||||||
availableFieldsForKanban.length > 0
|
availableFieldsForKanban.length > 0
|
||||||
? availableFieldsForKanban.map((field) => ({
|
? availableFieldsForKanban.map((field) => ({
|
||||||
|
|||||||
@ -64,10 +64,14 @@ export const ViewPickerCreateOrEditContentEffect = () => {
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (availableFieldsForKanban.length > 0) {
|
if (availableFieldsForKanban.length > 0 && !viewPickerIsDirty) {
|
||||||
setViewPickerKanbanFieldMetadataId(availableFieldsForKanban[0].id);
|
setViewPickerKanbanFieldMetadataId(availableFieldsForKanban[0].id);
|
||||||
}
|
}
|
||||||
}, [availableFieldsForKanban, setViewPickerKanbanFieldMetadataId]);
|
}, [
|
||||||
|
availableFieldsForKanban,
|
||||||
|
setViewPickerKanbanFieldMetadataId,
|
||||||
|
viewPickerIsDirty,
|
||||||
|
]);
|
||||||
|
|
||||||
return <></>;
|
return <></>;
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user