Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
494f4f3
fix: handle right frozen column count update
biubiukam Jun 16, 2026
c2ee2a3
docs: update changlog of rush
biubiukam Jun 16, 2026
0674116
fix: sync gantt task bars after sorted updates
fangsmile Jun 17, 2026
2deda5e
docs: update changlog of rush
fangsmile Jun 17, 2026
a51508f
chore: fix changefile metadata
fangsmile Jun 17, 2026
38882a5
fix: refresh gantt bars after sorted record updates
fangsmile Jun 17, 2026
f4d85d4
fix: stabilize package pre-push tests
fangsmile Jun 17, 2026
eec8688
Merge branch 'pr-5179-external' into verify/pr-5179-issue-3672
fangsmile Jun 17, 2026
4f0e584
fix: preserve quad style values
fangsmile Jun 17, 2026
2247567
docs: update changlog of rush
fangsmile Jun 17, 2026
f9b9522
chore: fix changefile metadata
fangsmile Jun 17, 2026
36d68b7
fix: keep sheet multi-header record fields
fangsmile Jun 23, 2026
aec26e0
fix: guard formula editor input sync
fangsmile Jun 23, 2026
1c7deb5
Merge pull request #5182 from VisActor/verify/pr-5179-issue-3672
fangsmile Jun 23, 2026
3caa924
fix: keep fractional row scroll target
biubiukam Jun 23, 2026
d94ff50
docs: update changlog of rush
biubiukam Jun 23, 2026
cb2bee2
fix: keep pivot row tree scroll position
fangsmile Jun 24, 2026
50dc7ad
merge: issue 5088 carousel fractional row fix
fangsmile Jun 24, 2026
3d7f75b
Merge pull request #5192 from VisActor/fix/issue-5088-carousel-fracti…
fangsmile Jun 24, 2026
45fc6cb
Merge pull request #5188 from VisActor/codex/fix-issue-5184-vtable-sh…
fangsmile Jun 24, 2026
1cec072
Merge pull request #5191 from VisActor/codex/fix-pivot-expand-scroll-…
fangsmile Jun 24, 2026
93dcf58
Merge pull request #5181 from VisActor/fix/issue-5162-gantt-sort-drag
fangsmile Jun 24, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ jspm_packages/

# Optional eslint cache
.eslintcache
.jest-cache/
**/.jest-cache/

# Optional REPL history
.node_repl_history
Expand Down Expand Up @@ -109,4 +111,4 @@ tsconfig.tsbuildinfo

.history
.trae/
.agents/
.agents/
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"changes": [
{
"comment": "fix: keep pivot row tree scroll position on toggle",
"type": "patch",
"packageName": "@visactor/vtable"
}
],
"packageName": "@visactor/vtable",
"email": "892739385@qq.com"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"changes": [
{
"comment": "fix: handle right frozen column count update",
"type": "none",
"packageName": "@visactor/vtable"
}
],
"packageName": "@visactor/vtable",
"email": "biukam.w@gmail.com"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"changes": [
{
"comment": "fix: keep fractional row scroll target",
"type": "none",
"packageName": "@visactor/vtable"
}
],
"packageName": "@visactor/vtable",
"email": "biukam.w@gmail.com"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"changes": [
{
"comment": "fix: sync gantt task bars after sorted updates\n\n",
"type": "none",
"packageName": "@visactor/vtable"
}
],
"packageName": "@visactor/vtable",
"email": "liufangfang.jane@bytedance.com"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"changes": [
{
"comment": "fix: preserve quad style values",
"type": "none",
"packageName": "@visactor/vtable"
}
],
"packageName": "@visactor/vtable",
"email": "liufangfang.jane@bytedance.com"
}
113 changes: 113 additions & 0 deletions packages/vtable-gantt/__tests__/gantt-sort-sync.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
// @ts-nocheck

global.__VERSION__ = 'none';

import { Gantt } from '../src';
import { createDiv, removeDom } from './dom';

describe('gantt sort sync', () => {
test('task bar nodes should bind sorted records after table sort', async () => {
const container = createDiv();
container.style.width = '900px';
container.style.height = '400px';

const records = [
{ id: 1, title: 'Task 1', startDate: '2024-07-01', endDate: '2024-07-03', progress: 10 },
{ id: 2, title: 'Task 2', startDate: '2024-07-05', endDate: '2024-07-07', progress: 20 },
{ id: 3, title: 'Task 3', startDate: '2024-07-09', endDate: '2024-07-11', progress: 30 }
];

const gantt = new Gantt(container, {
records,
taskListTable: {
columns: [
{ field: 'title', title: 'title', width: 160, sort: true },
{ field: 'startDate', title: 'startDate', width: 120, sort: true }
],
tableWidth: 320
},
taskBar: {
startDateField: 'startDate',
endDateField: 'endDate',
progressField: 'progress'
},
timelineHeader: {
colWidth: 40,
scales: [{ unit: 'day', step: 1 }]
},
minDate: '2024-06-25',
maxDate: '2024-07-20'
});

try {
gantt.taskListTableInstance.updateSortState({ field: 'startDate', order: 'desc' });
await new Promise(resolve => setTimeout(resolve, 250));

const firstVisibleRecord = gantt.getRecordByIndex(0);
const firstTaskBarNode = gantt.scenegraph.taskBar.getTaskBarNodeByIndex(0);

expect(firstVisibleRecord.id).toBe(3);
expect(firstTaskBarNode.record.id).toBe(firstVisibleRecord.id);
expect(firstTaskBarNode.record.startDate).toBe(firstVisibleRecord.startDate);
} finally {
gantt.release?.();
removeDom(container);
}
});

test('task bar nodes should refresh when date update changes sorted row order', async () => {
const container = createDiv();
container.style.width = '900px';
container.style.height = '400px';

const records = [
{ id: 101, title: '需求评审', startDate: '2024-02-05', endDate: '2024-02-12', progress: 20 },
{ id: 102, title: '交互设计', startDate: '2024-03-10', endDate: '2024-03-18', progress: 35 },
{ id: 103, title: '接口联调', startDate: '2024-05-28', endDate: '2024-06-05', progress: 50 },
{ id: 104, title: '灰度验证', startDate: '2024-10-05', endDate: '2024-10-20', progress: 65 },
{ id: 105, title: '正式上线', startDate: '2024-11-10', endDate: '2024-11-25', progress: 80 }
];

const gantt = new Gantt(container, {
records,
taskKeyField: 'id',
taskListTable: {
columns: [
{ field: 'title', title: 'title', width: 160, sort: true },
{ field: 'startDate', title: 'startDate', width: 120, sort: true }
],
tableWidth: 320
},
taskBar: {
startDateField: 'startDate',
endDateField: 'endDate',
progressField: 'progress'
},
timelineHeader: {
colWidth: 40,
scales: [{ unit: 'day', step: 1 }]
},
minDate: '2024-01-01',
maxDate: '2024-12-31'
});

try {
gantt.taskListTableInstance.updateSortState({ field: 'startDate', order: 'desc' });
await new Promise(resolve => setTimeout(resolve, 250));

expect(gantt.getRecordByIndex(0).id).toBe(105);
expect(gantt.scenegraph.taskBar.getTaskBarNodeByIndex(0).record.id).toBe(105);

gantt._updateStartEndDateToTaskRecord(new Date('2024-09-19'), new Date('2024-10-04'), 0);
await new Promise(resolve => setTimeout(resolve, 250));

expect(gantt.getRecordByIndex(0).id).toBe(104);
expect(gantt.scenegraph.taskBar.getTaskBarNodeByIndex(0).record.id).toBe(104);
expect(gantt.getRecordByIndex(1).id).toBe(105);
expect(gantt.scenegraph.taskBar.getTaskBarNodeByIndex(1).record.id).toBe(105);
} finally {
gantt.release?.();
removeDom(container);
}
});
});
132 changes: 132 additions & 0 deletions packages/vtable-gantt/examples/gantt/gantt-issue-5162-sort-drag.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
import type { ColumnsDefine } from '@visactor/vtable';
import type { GanttConstructorOptions } from '../../src/index';
import { Gantt } from '../../src/index';

const CONTAINER_ID = 'vTable';

function createTips(container: HTMLElement) {
const tips = document.createElement('div');
tips.style.cssText = [
'margin: 12px 0',
'padding: 12px 16px',
'border: 1px solid #d9e2f2',
'border-radius: 6px',
'background: #f7faff',
'font-family: Arial, sans-serif',
'font-size: 13px',
'line-height: 20px',
'color: #1f2329'
].join(';');
tips.innerHTML = [
'<strong>Issue #5162 Repro</strong><br>',
'1. 点击左侧 start 列排序,切到 desc。<br>',
'2. 拖动排序后的第一行或第二行任务条,观察控制台输出。<br>',
'3. 再次排序或调用 <code>window.ganttIssue5162.logMapping()</code> 查看可见行与任务条绑定是否一致。'
].join('');
container.appendChild(tips);
}

export function createTable() {
const container = document.getElementById(CONTAINER_ID)!;
container.innerHTML = '';
createTips(container);

const records = [
{ id: 101, title: '需求评审', owner: 'Alice', start: '2024-02-05', end: '2024-02-12', progress: 20 },
{ id: 102, title: '交互设计', owner: 'Bob', start: '2024-03-10', end: '2024-03-18', progress: 35 },
{ id: 103, title: '接口联调', owner: 'Carol', start: '2024-05-28', end: '2024-06-05', progress: 50 },
{ id: 104, title: '灰度验证', owner: 'David', start: '2024-10-05', end: '2024-10-20', progress: 65 },
{ id: 105, title: '正式上线', owner: 'Eve', start: '2024-11-10', end: '2024-11-25', progress: 80 }
];

const columns: ColumnsDefine = [
{ field: 'title', title: 'title', width: 160, sort: true },
{ field: 'owner', title: 'owner', width: 120, sort: true },
{ field: 'start', title: 'start', width: 120, sort: true },
{ field: 'end', title: 'end', width: 120, sort: true },
{ field: 'progress', title: 'progress', width: 100, sort: true }
];

const option: GanttConstructorOptions = {
records,
taskListTable: {
columns,
tableWidth: 360,
minTableWidth: 280,
maxTableWidth: 640
},
taskKeyField: 'id',
taskBar: {
startDateField: 'start',
endDateField: 'end',
progressField: 'progress',
moveable: true,
labelText: '{title}'
},
minDate: '2024-01-01',
maxDate: '2024-12-31',
timelineHeader: {
colWidth: 30,
scales: [{ unit: 'day', step: 1 }]
},
scrollStyle: {
visible: 'scrolling'
},
grid: {
verticalLine: {
lineWidth: 1,
lineColor: '#e1e4e8'
},
horizontalLine: {
lineWidth: 1,
lineColor: '#e1e4e8'
}
}
};

const ganttInstance = new Gantt(container, option);
(window as any).ganttInstance = ganttInstance;

const logMapping = () => {
const rows = records.map((_, index) => {
const visibleRecord = ganttInstance.getRecordByIndex(index);
const taskBarNode = ganttInstance.scenegraph.taskBar.getTaskBarNodeByIndex(index);
return {
row: index,
visibleId: visibleRecord?.id,
visibleTitle: visibleRecord?.title,
taskBarRecordId: taskBarNode?.record?.id,
taskBarRecordTitle: taskBarNode?.record?.title
};
});
console.table(rows);
return rows;
};

(window as any).ganttIssue5162 = {
gantt: ganttInstance,
sortByStartDesc: () => ganttInstance.taskListTableInstance?.updateSortState({ field: 'start', order: 'desc' }),
sortByStartAsc: () => ganttInstance.taskListTableInstance?.updateSortState({ field: 'start', order: 'asc' }),
logMapping,
logRecords: () => {
console.table(ganttInstance.records);
return ganttInstance.records;
}
};

ganttInstance.taskListTableInstance?.on('after_sort', () => {
console.log('[issue-5162] after_sort');
logMapping();
});

ganttInstance.on('move_end_task_bar', e => {
console.log('[issue-5162] move_end_task_bar', e);
logMapping();
console.table(ganttInstance.records);
});

setTimeout(() => {
const x = ganttInstance.getXByTime(new Date('2024-06-01 00:00:00').getTime());
ganttInstance.scrollLeft = x;
}, 0);
}
4 changes: 4 additions & 0 deletions packages/vtable-gantt/examples/menu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,10 @@ export const menus = [
{
path: 'gantt',
name: 'gantt-locate-taskbar'
},
{
path: 'gantt',
name: 'gantt-issue-5162-sort-drag'
}
// ]
// }
Expand Down
1 change: 1 addition & 0 deletions packages/vtable-gantt/jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ module.exports = {
statements: 60
}
},
cacheDirectory: '<rootDir>/.jest-cache',
moduleNameMapper: {
'd3-color': path.resolve(__dirname, './node_modules/d3-color/dist/d3-color.min.js'),
'd3-array': path.resolve(process.cwd(), './node_modules/d3-array/dist/d3-array.min.js'),
Expand Down
Loading
Loading