Skip to content

Commit

Permalink
T1205597: Scheduler - Timetable becomes empty when scrolling to the f…
Browse files Browse the repository at this point in the history
…ar right in virtual scrolling mode (DevExpress#26743) (DevExpress#26894)
  • Loading branch information
timbset authored Mar 12, 2024
1 parent e124db3 commit 963f449
Show file tree
Hide file tree
Showing 13 changed files with 136 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ const MIN_CELL_WIDTH = 1;
const MIN_SCROLL_OFFSET = 10;
const VIRTUAL_APPOINTMENTS_RENDER_TIMEOUT = 15;
const DOCUMENT_SCROLL_EVENT_NAMESPACE = addNamespace('scroll', 'dxSchedulerVirtualScrolling');
const MAX_CELLS_PER_VIRTUAL_CELL_COUNT = 1000;

const scrollingOrientations = {
vertical: 'vertical',
Expand Down Expand Up @@ -102,9 +103,7 @@ export class VirtualScrollingDispatcher {
? this.cellCountInsideLeftVirtualCell
: this.cellCountInsideRightVirtualCell;

return virtualItemsCount > 0
? 1
: 0;
return Math.ceil(virtualItemsCount / MAX_CELLS_PER_VIRTUAL_CELL_COUNT);
}

get virtualRowOffset() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ import {
Component, ComponentBindings, JSXComponent, Slot, OneWay, CSSAttributes,
} from '@devextreme-generator/declarations';
import { VirtualCell } from './virtual_cell';
import { splitNumber } from './utils';

const MAX_COL_SPAN = 1000;

export const viewFunction = ({
props: {
Expand All @@ -21,23 +24,29 @@ export const viewFunction = ({
className={className}
style={styles}
>
{hasLeftVirtualCell && (
<VirtualCell
width={leftVirtualCellWidth}
colSpan={leftVirtualCellCount}
isHeaderCell={isHeaderRow}
/>
)}
{hasLeftVirtualCell
&& leftVirtualCellCount != null
&& splitNumber(leftVirtualCellCount, MAX_COL_SPAN).map((colSpan, index) => (
<VirtualCell
key={`left-virtual-cell-${index}`}
width={leftVirtualCellWidth * (colSpan / leftVirtualCellCount)}
colSpan={colSpan}
isHeaderCell={isHeaderRow}
/>
))}

{children}

{hasRightVirtualCell && (
<VirtualCell
width={rightVirtualCellWidth}
colSpan={rightVirtualCellCount}
isHeaderCell={isHeaderRow}
/>
)}
{hasRightVirtualCell
&& rightVirtualCellCount != null
&& splitNumber(rightVirtualCellCount, MAX_COL_SPAN).map((colSpan, index) => (
<VirtualCell
key={`right-virtual-cell-${index}`}
width={rightVirtualCellWidth * (colSpan / rightVirtualCellCount)}
colSpan={colSpan}
isHeaderCell={isHeaderRow}
/>
))}
</tr>
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -211,3 +211,8 @@ export const compareCellsByDateAndIndex = (daysAndIndexes: {

export const isCellAllDay = (cell: HTMLElement): boolean => cell.className
.includes(ALL_DAY_PANEL_CELL_CLASS);

export const splitNumber = (value: number, splitValue: number): number[] => Array.from(
{ length: Math.ceil(value / splitValue) },
(_, index) => Math.min(value - (splitValue * index), splitValue),
);
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
import { createScreenshotsComparer } from 'devextreme-screenshot-comparer';

import { createWidget } from '../../../helpers/createWidget';
import url from '../../../helpers/getPageUrl';
import Scheduler from '../../../model/scheduler';
import { generateOptionMatrix } from '../../../helpers/generateOptionMatrix';
import type { ViewType } from '../../../../../js/ui/scheduler';

fixture.disablePageReloads`Scheduler: Virtual scrolling (many cells)`
.page(url(__dirname, '../../container.html'));

const buildScreenshotName = (viewType: ViewType, step: string) => `virtual-scrolling-many-cells-${viewType}-horizontal-${step}.png`;

const testCases = generateOptionMatrix({
views: [
[
{
type: 'month' as ViewType,
groupOrientation: 'horizontal',
},
],
[
{
type: 'week' as ViewType,
groupOrientation: 'horizontal',
},
],
[
{
type: 'workWeek' as ViewType,
groupOrientation: 'horizontal',
},
],
],
});

testCases.forEach(({ views }) => {
const viewType = views[0].type;
const resourceCount = 400;

test(`it should correctly render virtual table if more than 1000 cells are virtualized for ${viewType} view (T1205597)`, async (t) => {
const scheduler = new Scheduler('#container');

const { takeScreenshot, compareResults } = createScreenshotsComparer(t);

await t
.expect(await takeScreenshot(buildScreenshotName(viewType, 'start'), scheduler.element))
.ok();

await scheduler.scrollTo(new Date(2024, 1, 1, 1), { groupId: resourceCount / 2 });

await t
.expect(await takeScreenshot(buildScreenshotName(viewType, 'middle'), scheduler.element))
.ok();

await scheduler.scrollTo(new Date(2024, 1, 1, 1), { groupId: resourceCount - 1 });

await t
.expect(await takeScreenshot(buildScreenshotName(viewType, 'end'), scheduler.element))
.ok();

await t
.expect(compareResults.isValid())
.ok(compareResults.errorMessages());
}).before(async () => {
const resources = Array.from({ length: resourceCount }, (_, i) => ({
id: i,
text: `Resource ${i}`,
}));

const appointmentDateInfo = Array.from({ length: 29 })
.map((_, i) => ({
startDate: new Date(2024, 1, i + 1, 1),
endDate: new Date(2024, 1, i + 1, 4),
}));

const appointments = Array.from({ length: resourceCount })
.map((_, resourceIndex) => appointmentDateInfo.map(({ startDate, endDate }) => ({
text: `Appointment for Resource ${resourceIndex}`,
startDate,
endDate,
groupId: resourceIndex,
})))
.flat();

await createWidget(
'dxScheduler',
{
height: 600,
currentDate: new Date(2024, 1, 1),
dataSource: appointments,
views,
currentView: viewType,
scrolling: {
mode: 'virtual',
},
groups: ['groupId'],
resources: [{
fieldExpr: 'groupId',
dataSource: resources,
label: 'Group',
}],
},
);
});
});

0 comments on commit 963f449

Please sign in to comment.