diff --git a/common/changes/@visactor/vtable/fix-issue-4607-filter-add-records_2026-09-20-17-20.json b/common/changes/@visactor/vtable/fix-issue-4607-filter-add-records_2026-09-20-17-20.json new file mode 100644 index 000000000..539b446c5 --- /dev/null +++ b/common/changes/@visactor/vtable/fix-issue-4607-filter-add-records_2026-09-20-17-20.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "test(vtable): cover preserving addRecords results after clearing filters", + "type": "patch", + "packageName": "@visactor/vtable" + } + ], + "packageName": "@visactor/vtable", + "email": "892739385@qq.com" +} diff --git a/packages/vtable/__tests__/data-update/listTable-data-events.test.ts b/packages/vtable/__tests__/data-update/listTable-data-events.test.ts index 4e580476f..4da58ac08 100644 --- a/packages/vtable/__tests__/data-update/listTable-data-events.test.ts +++ b/packages/vtable/__tests__/data-update/listTable-data-events.test.ts @@ -204,6 +204,48 @@ describe('listTable data events test', () => { expect(filterCalls).toBe(5); }); + test('addRecords under filter should preserve new records after clearing filter', () => { + table.release(); + const records = [ + { name: 'Alice', age: 25, group: 'A' }, + { name: 'Bob', age: 30, group: 'B' }, + { name: 'Charlie', age: 35, group: 'A' } + ]; + const newRecords = [ + { name: 'David', age: 40, group: 'A' }, + { name: 'Eve', age: 45, group: 'B' } + ]; + + table = new ListTable({ + container: containerDom, + columns: [ + { field: 'name', title: 'Name' }, + { field: 'age', title: 'Age' }, + { field: 'group', title: 'Group' } + ], + records, + syncRecordOperationsToSourceRecords: true + }); + + table.updateFilterRules([ + { + filterKey: 'group', + filteredValues: ['A'] + } + ]); + table.addRecords(newRecords); + table.updateFilterRules([]); + + expect((table.records as typeof records).map(record => record.name)).toEqual([ + 'Alice', + 'Bob', + 'Charlie', + 'David', + 'Eve' + ]); + expect(records).toEqual(table.records); + }); + test('addRecord under filter should keep relative position after clearing filter', () => { table.release(); const records = [ diff --git a/packages/vtable/examples/debug/issue-4607-filter-add-records.ts b/packages/vtable/examples/debug/issue-4607-filter-add-records.ts new file mode 100644 index 000000000..eaf09169d --- /dev/null +++ b/packages/vtable/examples/debug/issue-4607-filter-add-records.ts @@ -0,0 +1,74 @@ +import * as VTable from '../../src'; + +interface Issue4607Window extends Window { + tableInstance?: VTable.ListTable; + issue4607Run?: () => boolean; + BUGSERVER_SCREENSHOT?: () => void; +} + +const CONTAINER_ID = 'vTable'; + +export function createTable() { + const container = document.getElementById(CONTAINER_ID); + if (!container) { + throw new Error(`Missing #${CONTAINER_ID} container`); + } + container.style.width = '640px'; + container.style.height = '360px'; + + const sourceRecords = [ + { name: 'Alice', age: 25, group: 'A' }, + { name: 'Bob', age: 30, group: 'B' }, + { name: 'Charlie', age: 35, group: 'A' } + ]; + const addedRecords = [ + { name: 'David', age: 40, group: 'A' }, + { name: 'Eve', age: 45, group: 'B' } + ]; + + const status = document.createElement('div'); + status.id = 'issue4607Status'; + status.style.cssText = 'margin: 0 0 12px; font: 600 14px/1.5 sans-serif;'; + status.textContent = 'RUNNING'; + container.parentElement?.insertBefore(status, container); + + const tableInstance = new VTable.ListTable(container, { + columns: [ + { field: 'name', title: 'Name', width: 180 }, + { field: 'age', title: 'Age', width: 120 }, + { field: 'group', title: 'Group', width: 120 } + ], + records: sourceRecords, + syncRecordOperationsToSourceRecords: true + }); + + const runCheck = () => { + tableInstance.updateFilterRules([ + { + filterKey: 'group', + filteredValues: ['A'] + } + ]); + tableInstance.addRecords(addedRecords); + tableInstance.updateFilterRules([]); + + const names = (tableInstance.records as typeof sourceRecords).map(record => record.name); + const pass = + names.join(',') === 'Alice,Bob,Charlie,David,Eve' && + sourceRecords.length === 5 && + sourceRecords[3] === addedRecords[0] && + sourceRecords[4] === addedRecords[1]; + + status.textContent = `${pass ? 'PASS' : 'FAIL'} | ${names.join(', ')}`; + status.style.color = pass ? '#237804' : '#a8071a'; + status.style.borderLeft = `4px solid ${pass ? '#52c41a' : '#ff4d4f'}`; + status.style.paddingLeft = '8px'; + (window as Issue4607Window).BUGSERVER_SCREENSHOT?.(); + return pass; + }; + + const issueWindow = window as Issue4607Window; + issueWindow.tableInstance = tableInstance; + issueWindow.issue4607Run = runCheck; + requestAnimationFrame(runCheck); +} diff --git a/packages/vtable/examples/menu.ts b/packages/vtable/examples/menu.ts index 7bbfe9639..591cf72d8 100644 --- a/packages/vtable/examples/menu.ts +++ b/packages/vtable/examples/menu.ts @@ -78,6 +78,10 @@ export const menus = [ path: 'debug', name: 'issue-4656-fill-handle-hit-area' }, + { + path: 'debug', + name: 'issue-4607-filter-add-records' + }, { path: 'debug', name: 'issue-3752-large-merge-auto-height'