Fix table virtualization data load < 120 records (#15203)
This PR fixes two bugs : - Data loading not working between 60 and 120 records on an object - Table not refreshing when creating a record in an empty table. Fixes https://github.com/twentyhq/twenty/issues/15196
This commit is contained in:
+2
@@ -14,6 +14,7 @@ import { recordTableWidthComponentState } from '@/object-record/record-table/sta
|
||||
import { resizedFieldMetadataIdComponentState } from '@/object-record/record-table/states/resizedFieldMetadataIdComponentState';
|
||||
import { resizeFieldOffsetComponentState } from '@/object-record/record-table/states/resizeFieldOffsetComponentState';
|
||||
import { computeVisibleRecordFieldsWidthOnTable } from '@/object-record/record-table/utils/computeVisibleRecordFieldsWidthOnTable';
|
||||
import { RecordTableVirtualizedDataChangedEffect } from '@/object-record/record-table/virtualization/components/RecordTableVirtualizedDataChangedEffect';
|
||||
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
|
||||
import styled from '@emotion/styled';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
@@ -94,6 +95,7 @@ export const RecordTableEmpty = ({ tableBodyRef }: RecordTableEmptyProps) => {
|
||||
<RecordTableEmptyState />
|
||||
<RecordTableColumnWidthEffect />
|
||||
<RecordTableWidthEffect />
|
||||
<RecordTableVirtualizedDataChangedEffect />
|
||||
</StyledEmptyStateContainer>
|
||||
);
|
||||
};
|
||||
|
||||
+20
-21
@@ -11,17 +11,30 @@ import styled from '@emotion/styled';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
const StyledDebugRow = styled.div`
|
||||
position: absolute;
|
||||
left: 250px;
|
||||
top: ${({ theme }) => theme.spacing(1.25)};
|
||||
z-index: 20;
|
||||
color: ${({ theme }) => theme.font.color.primary};
|
||||
background-color: ${({ theme }) => theme.adaptiveColors.gray1};
|
||||
border: 1px solid ${({ theme }) => theme.adaptiveColors.blue4};
|
||||
padding: ${({ theme }) => theme.spacing(0.5)};
|
||||
display: flex;
|
||||
max-height: ${({ theme }) => theme.spacing(4)};
|
||||
|
||||
overflow: hidden;
|
||||
`;
|
||||
|
||||
const StyledDebugColumn = styled.div<{ width: number }>`
|
||||
height: 25px;
|
||||
max-height: 25px;
|
||||
min-width: ${({ width }) => width}px;
|
||||
max-width: ${({ width }) => width}px;
|
||||
overflow: scroll;
|
||||
overflow: hidden;
|
||||
|
||||
display: flex;
|
||||
text-wrap-mode: nowrap;
|
||||
padding-right: 2px;
|
||||
padding-left: 2px;
|
||||
padding-right: ${({ theme }) => theme.spacing(0.5)};
|
||||
padding-left: ${({ theme }) => theme.spacing(0.5)};
|
||||
`;
|
||||
|
||||
type RecordTableRowVirtualizedDebugRowHelperProps = {
|
||||
@@ -62,21 +75,7 @@ export const RecordTableRowVirtualizedDebugRowHelper = ({
|
||||
const position = record?.position;
|
||||
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
position: 'absolute',
|
||||
left: 250,
|
||||
top: 5,
|
||||
zIndex: 20,
|
||||
color: 'darkblue',
|
||||
backgroundColor: 'white',
|
||||
border: '1px solid blue',
|
||||
padding: 2,
|
||||
display: 'flex',
|
||||
maxHeight: 16,
|
||||
overflow: 'clip',
|
||||
}}
|
||||
>
|
||||
<StyledDebugRow>
|
||||
<StyledDebugColumn width={70}>virtual :{virtualIndex}</StyledDebugColumn>
|
||||
<StyledDebugColumn width={70}>real :{realIndex}</StyledDebugColumn>
|
||||
<StyledDebugColumn width={100}>pos :{position}</StyledDebugColumn>
|
||||
@@ -91,6 +90,6 @@ export const RecordTableRowVirtualizedDebugRowHelper = ({
|
||||
id:
|
||||
{recordId}
|
||||
</StyledDebugColumn>
|
||||
</div>
|
||||
</StyledDebugRow>
|
||||
);
|
||||
};
|
||||
|
||||
-44
@@ -1,44 +0,0 @@
|
||||
import { NUMBER_OF_VIRTUALIZED_ROWS } from '@/object-record/record-table/virtualization/constants/NumberOfVirtualizedRows';
|
||||
import { totalNumberOfRecordsToVirtualizeComponentState } from '@/object-record/record-table/virtualization/states/totalNumberOfRecordsToVirtualizeComponentState';
|
||||
import { type ObjectRecord } from '@/object-record/types/ObjectRecord';
|
||||
import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState';
|
||||
import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue';
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
|
||||
export const useResetNumberOfRecordsToVirtualize = () => {
|
||||
const totalNumberOfRecordsToVirtualizeCallbackState =
|
||||
useRecoilComponentCallbackState(
|
||||
totalNumberOfRecordsToVirtualizeComponentState,
|
||||
);
|
||||
|
||||
const resetNumberOfRecordsToVirtualize = useRecoilCallback(
|
||||
({ snapshot, set }) =>
|
||||
({
|
||||
records,
|
||||
totalCount,
|
||||
}: {
|
||||
records: ObjectRecord[];
|
||||
totalCount: number;
|
||||
}) => {
|
||||
const totalNumberOfRecordsToVirtualize = getSnapshotValue(
|
||||
snapshot,
|
||||
totalNumberOfRecordsToVirtualizeCallbackState,
|
||||
);
|
||||
|
||||
if (totalCount > NUMBER_OF_VIRTUALIZED_ROWS) {
|
||||
if (totalNumberOfRecordsToVirtualize !== totalCount) {
|
||||
set(totalNumberOfRecordsToVirtualizeCallbackState, totalCount);
|
||||
}
|
||||
} else {
|
||||
if (totalNumberOfRecordsToVirtualize !== records.length) {
|
||||
set(totalNumberOfRecordsToVirtualizeCallbackState, records.length);
|
||||
}
|
||||
}
|
||||
},
|
||||
[totalNumberOfRecordsToVirtualizeCallbackState],
|
||||
);
|
||||
|
||||
return {
|
||||
resetNumberOfRecordsToVirtualize,
|
||||
};
|
||||
};
|
||||
+12
-9
@@ -11,7 +11,7 @@ import { isRecordTableScrolledVerticallyComponentState } from '@/object-record/r
|
||||
import { updateRecordTableCSSVariable } from '@/object-record/record-table/utils/updateRecordTableCSSVariable';
|
||||
import { useLoadRecordsToVirtualRows } from '@/object-record/record-table/virtualization/hooks/useLoadRecordsToVirtualRows';
|
||||
import { useReapplyRowSelection } from '@/object-record/record-table/virtualization/hooks/useReapplyRowSelection';
|
||||
import { useResetNumberOfRecordsToVirtualize } from '@/object-record/record-table/virtualization/hooks/useResetNumberOfRecordsToVirtualize';
|
||||
|
||||
import { useResetTableFocuses } from '@/object-record/record-table/virtualization/hooks/useResetTableFocuses';
|
||||
import { useResetVirtualizedRowTreadmill } from '@/object-record/record-table/virtualization/hooks/useResetVirtualizedRowTreadmill';
|
||||
import { dataLoadingStatusByRealIndexComponentFamilyState } from '@/object-record/record-table/virtualization/states/dataLoadingStatusByRealIndexComponentFamilyState';
|
||||
@@ -21,6 +21,7 @@ import { lastRealIndexSetComponentState } from '@/object-record/record-table/vir
|
||||
import { lastScrollPositionComponentState } from '@/object-record/record-table/virtualization/states/lastScrollPositionComponentState';
|
||||
import { recordIdByRealIndexComponentFamilyState } from '@/object-record/record-table/virtualization/states/recordIdByRealIndexComponentFamilyState';
|
||||
import { scrollAtRealIndexComponentState } from '@/object-record/record-table/virtualization/states/scrollAtRealIndexComponentState';
|
||||
import { totalNumberOfRecordsToVirtualizeComponentState } from '@/object-record/record-table/virtualization/states/totalNumberOfRecordsToVirtualizeComponentState';
|
||||
import { type ObjectRecord } from '@/object-record/types/ObjectRecord';
|
||||
import { SIGN_IN_BACKGROUND_MOCK_COMPANIES } from '@/sign-in-background-mock/constants/SignInBackgroundMockCompanies';
|
||||
import { useShowAuthModal } from '@/ui/layout/hooks/useShowAuthModal';
|
||||
@@ -88,8 +89,6 @@ export const useTriggerInitialRecordTableDataLoad = () => {
|
||||
const { scrollTableToPosition } = useScrollTableToPosition();
|
||||
|
||||
const { resetVirtualizedRowTreadmill } = useResetVirtualizedRowTreadmill();
|
||||
const { resetNumberOfRecordsToVirtualize } =
|
||||
useResetNumberOfRecordsToVirtualize();
|
||||
|
||||
const { resetTableFocuses } = useResetTableFocuses(recordTableId);
|
||||
const { upsertRecordsInStore } = useUpsertRecordsInStore();
|
||||
@@ -98,6 +97,11 @@ export const useTriggerInitialRecordTableDataLoad = () => {
|
||||
|
||||
const { reapplyRowSelection } = useReapplyRowSelection();
|
||||
|
||||
const totalNumberOfRecordsToVirtualizeCallbackState =
|
||||
useRecoilComponentCallbackState(
|
||||
totalNumberOfRecordsToVirtualizeComponentState,
|
||||
);
|
||||
|
||||
const triggerInitialRecordTableDataLoad = useRecoilCallback(
|
||||
({ snapshot, set }) =>
|
||||
async () => {
|
||||
@@ -153,18 +157,17 @@ export const useTriggerInitialRecordTableDataLoad = () => {
|
||||
null,
|
||||
);
|
||||
}
|
||||
|
||||
const { records: findManyRecords, totalCount: findManyTotalCount } =
|
||||
await findManyRecordsLazy();
|
||||
|
||||
records = findManyRecords;
|
||||
totalCount = findManyTotalCount;
|
||||
}
|
||||
|
||||
if (isDefined(records)) {
|
||||
resetNumberOfRecordsToVirtualize({
|
||||
records,
|
||||
totalCount,
|
||||
});
|
||||
set(totalNumberOfRecordsToVirtualizeCallbackState, totalCount);
|
||||
|
||||
if (isDefined(records)) {
|
||||
upsertRecordsInStore(records);
|
||||
|
||||
loadRecordsToVirtualRows({
|
||||
@@ -209,7 +212,7 @@ export const useTriggerInitialRecordTableDataLoad = () => {
|
||||
findManyRecordsLazy,
|
||||
dataLoadingStatusByRealIndexCallbackState,
|
||||
recordIdByRealIndexCallbackState,
|
||||
resetNumberOfRecordsToVirtualize,
|
||||
totalNumberOfRecordsToVirtualizeCallbackState,
|
||||
upsertRecordsInStore,
|
||||
loadRecordsToVirtualRows,
|
||||
reapplyRowSelection,
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import { type Decorator } from '@storybook/react';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import { useRecoilValue, useSetRecoilState } from 'recoil';
|
||||
|
||||
import { ActionMenuComponentInstanceContext } from '@/action-menu/states/contexts/ActionMenuComponentInstanceContext';
|
||||
import { getActionMenuIdFromRecordIndexId } from '@/action-menu/utils/getActionMenuIdFromRecordIndexId';
|
||||
import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState';
|
||||
import { labelIdentifierFieldMetadataItemSelector } from '@/object-metadata/states/labelIdentifierFieldMetadataItemSelector';
|
||||
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
||||
import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||
@@ -25,6 +26,8 @@ import { getObjectPermissionsFromMapByObjectMetadataId } from '@/settings/roles/
|
||||
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
|
||||
import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState';
|
||||
import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext';
|
||||
import { coreViewsState } from '@/views/states/coreViewState';
|
||||
import { type CoreViewWithRelations } from '@/views/types/CoreViewWithRelations';
|
||||
import { type View } from '@/views/types/View';
|
||||
import { mapViewFieldToRecordField } from '@/views/utils/mapViewFieldToRecordField';
|
||||
import { useEffect, useMemo } from 'react';
|
||||
@@ -44,6 +47,12 @@ const InternalTableStateLoaderEffect = ({
|
||||
currentRecordFieldsComponentState,
|
||||
);
|
||||
|
||||
const setContextStoreCurrentViewId = useSetRecoilComponentState(
|
||||
contextStoreCurrentViewIdComponentState,
|
||||
);
|
||||
|
||||
const setCoreViews = useSetRecoilState(coreViewsState);
|
||||
|
||||
const setRecordTableData = useSetRecordTableData({
|
||||
recordTableId,
|
||||
});
|
||||
@@ -67,12 +76,18 @@ const InternalTableStateLoaderEffect = ({
|
||||
.filter(isDefined);
|
||||
|
||||
setCurrentRecordFields(recordFields);
|
||||
|
||||
setCoreViews([view as unknown as CoreViewWithRelations]);
|
||||
|
||||
setContextStoreCurrentViewId(view.id);
|
||||
}, [
|
||||
loadRecordIndexStates,
|
||||
objectMetadataItem,
|
||||
setRecordTableData,
|
||||
view,
|
||||
setCurrentRecordFields,
|
||||
setContextStoreCurrentViewId,
|
||||
setCoreViews,
|
||||
]);
|
||||
|
||||
return null;
|
||||
|
||||
@@ -22,8 +22,10 @@ import { mockedViewsData } from '~/testing/mock-data/views';
|
||||
import { mockWorkspaceMembers } from '~/testing/mock-data/workspace-members';
|
||||
|
||||
import { GET_PUBLIC_WORKSPACE_DATA_BY_DOMAIN } from '@/auth/graphql/queries/getPublicWorkspaceDataByDomain';
|
||||
import { LIST_PLANS } from '@/billing/graphql/queries/listPlans';
|
||||
import { GET_ROLES } from '@/settings/roles/graphql/queries/getRolesQuery';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { mockBillingPlans } from '~/testing/mock-data/billing-plans';
|
||||
import { mockedStandardObjectMetadataQueryResult } from '~/testing/mock-data/generated/mock-metadata-query-result';
|
||||
import { getRolesMock } from '~/testing/mock-data/roles';
|
||||
import { mockedTasks } from '~/testing/mock-data/tasks';
|
||||
@@ -35,8 +37,6 @@ import {
|
||||
import { oneSucceededWorkflowRunQueryResult } from '~/testing/mock-data/workflow-run';
|
||||
import { mockedRemoteServers } from './mock-data/remote-servers';
|
||||
import { mockedViewFieldsData } from './mock-data/view-fields';
|
||||
import { LIST_PLANS } from '@/billing/graphql/queries/listPlans';
|
||||
import { mockBillingPlans } from '~/testing/mock-data/billing-plans';
|
||||
|
||||
const peopleMock = getPeopleRecordConnectionMock();
|
||||
const companiesMock = getCompaniesRecordConnectionMock();
|
||||
@@ -384,6 +384,7 @@ export const graphqlMocks = {
|
||||
startCursor: null,
|
||||
endCursor: null,
|
||||
},
|
||||
totalCount: mockedData.length,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user