From 65f12dcf496f50246646f866d62143d691108ec0 Mon Sep 17 00:00:00 2001 From: fangsmile <892739385@qq.com> Date: Sun, 20 Sep 2026 19:47:45 +0800 Subject: [PATCH 1/2] test(vtable): cover filtered updateRecords persistence Preserve regression coverage for source-record updates after filters are cleared. Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com --- ...ilter-update-records_2026-09-20-19-30.json | 11 ++ .../data-update/listTable-data-events.test.ts | 43 ++++++++ .../debug/issue-4794-filter-update-records.ts | 104 ++++++++++++++++++ packages/vtable/examples/menu.ts | 4 + 4 files changed, 162 insertions(+) create mode 100644 common/changes/@visactor/vtable/fix-issue-4794-filter-update-records_2026-09-20-19-30.json create mode 100644 packages/vtable/examples/debug/issue-4794-filter-update-records.ts diff --git a/common/changes/@visactor/vtable/fix-issue-4794-filter-update-records_2026-09-20-19-30.json b/common/changes/@visactor/vtable/fix-issue-4794-filter-update-records_2026-09-20-19-30.json new file mode 100644 index 000000000..a8ee587d6 --- /dev/null +++ b/common/changes/@visactor/vtable/fix-issue-4794-filter-update-records_2026-09-20-19-30.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "test(vtable): cover preserving updateRecords 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 4da58ac08..ebfa613ef 100644 --- a/packages/vtable/__tests__/data-update/listTable-data-events.test.ts +++ b/packages/vtable/__tests__/data-update/listTable-data-events.test.ts @@ -246,6 +246,49 @@ describe('listTable data events test', () => { expect(records).toEqual(table.records); }); + test('updateRecords under filter should persist extra fields to source records', () => { + table.release(); + const records = [ + { id: 1, name: 'Employee 1' }, + { id: 2, name: 'Employee 2' }, + { id: 3, name: 'Employee 3' }, + { id: 4, name: 'Employee 4' }, + { id: 5, name: 'Employee 5' } + ]; + + table = new ListTable({ + container: containerDom, + columns: [ + { field: 'id', title: 'ID' }, + { field: 'name', title: 'Name' } + ], + records, + syncRecordOperationsToSourceRecords: true + }); + + table.updateFilterRules([ + { + filterKey: 'id', + filteredValues: [2, 3, 4] + } + ]); + + const updatedRecord = { + ...table.records[0], + name: 'Employee 2 updated', + modifiedCells: { name: true } + }; + table.updateRecords([updatedRecord], [0]); + + expect(records[1]).toBe(updatedRecord); + expect(records[1].modifiedCells).toEqual({ name: true }); + + table.updateFilterRules([]); + + expect(table.records[1]).toBe(updatedRecord); + expect(table.records[1].name).toBe('Employee 2 updated'); + }); + test('addRecord under filter should keep relative position after clearing filter', () => { table.release(); const records = [ diff --git a/packages/vtable/examples/debug/issue-4794-filter-update-records.ts b/packages/vtable/examples/debug/issue-4794-filter-update-records.ts new file mode 100644 index 000000000..8a0018791 --- /dev/null +++ b/packages/vtable/examples/debug/issue-4794-filter-update-records.ts @@ -0,0 +1,104 @@ +import * as VTable from '../../src'; + +interface Issue4794Window extends Window { + tableInstance?: VTable.ListTable; + issue4794Run?: () => boolean; + BUGSERVER_SCREENSHOT?: () => void; +} + +interface EmployeeRecord { + id: number; + name: string; + modifiedCells?: { + name?: boolean; + }; +} + +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: EmployeeRecord[] = [ + { id: 1, name: 'Employee 1' }, + { id: 2, name: 'Employee 2' }, + { id: 3, name: 'Employee 3' }, + { id: 4, name: 'Employee 4' }, + { id: 5, name: 'Employee 5' } + ]; + + const status = document.createElement('div'); + status.id = 'issue4794Status'; + 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: 'id', title: 'ID', width: 100 }, + { + field: 'name', + title: 'Name', + width: 260, + style: args => { + const record = args.table.records[args.row - 1] as EmployeeRecord | undefined; + return { + bgColor: record?.modifiedCells?.name ? '#ffccc7' : '#fff' + }; + } + }, + { + field: 'modifiedCells', + title: 'Source record updated', + width: 200, + fieldFormat: record => (record.modifiedCells?.name ? 'yes' : 'no') + } + ], + records: sourceRecords, + syncRecordOperationsToSourceRecords: true + }); + + const runCheck = () => { + tableInstance.updateFilterRules([ + { + filterKey: 'id', + filteredValues: [2, 3, 4] + } + ]); + + const updatedRecord: EmployeeRecord = { + ...(tableInstance.records[0] as EmployeeRecord), + name: 'Employee 2 updated', + modifiedCells: { name: true } + }; + tableInstance.updateRecords([updatedRecord], [0]); + tableInstance.updateFilterRules([]); + + const sourceRecord = sourceRecords[1]; + const displayedRecord = tableInstance.records[1] as EmployeeRecord; + const pass = + sourceRecord === updatedRecord && + displayedRecord === updatedRecord && + sourceRecord.name === 'Employee 2 updated' && + sourceRecord.modifiedCells?.name === true; + + status.textContent = `${pass ? 'PASS' : 'FAIL'} | source Employee 2: ${sourceRecord.name} | modified: ${ + sourceRecord.modifiedCells?.name === true ? 'yes' : 'no' + }`; + status.style.color = pass ? '#237804' : '#a8071a'; + status.style.borderLeft = `4px solid ${pass ? '#52c41a' : '#ff4d4f'}`; + status.style.paddingLeft = '8px'; + (window as Issue4794Window).BUGSERVER_SCREENSHOT?.(); + return pass; + }; + + const issueWindow = window as Issue4794Window; + issueWindow.tableInstance = tableInstance; + issueWindow.issue4794Run = runCheck; + requestAnimationFrame(runCheck); +} diff --git a/packages/vtable/examples/menu.ts b/packages/vtable/examples/menu.ts index 591cf72d8..a3b679f1e 100644 --- a/packages/vtable/examples/menu.ts +++ b/packages/vtable/examples/menu.ts @@ -82,6 +82,10 @@ export const menus = [ path: 'debug', name: 'issue-4607-filter-add-records' }, + { + path: 'debug', + name: 'issue-4794-filter-update-records' + }, { path: 'debug', name: 'issue-3752-large-merge-auto-height' From b60cbda32cc27c772e3bc2fd729937cf8c86865e Mon Sep 17 00:00:00 2001 From: fangsmile <892739385@qq.com> Date: Mon, 21 Sep 2026 09:37:16 +0800 Subject: [PATCH 2/2] chore(vtable): avoid release for test-only changes Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com --- .../fix-issue-4794-filter-update-records_2026-09-20-19-30.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/changes/@visactor/vtable/fix-issue-4794-filter-update-records_2026-09-20-19-30.json b/common/changes/@visactor/vtable/fix-issue-4794-filter-update-records_2026-09-20-19-30.json index a8ee587d6..70f6f0754 100644 --- a/common/changes/@visactor/vtable/fix-issue-4794-filter-update-records_2026-09-20-19-30.json +++ b/common/changes/@visactor/vtable/fix-issue-4794-filter-update-records_2026-09-20-19-30.json @@ -2,7 +2,7 @@ "changes": [ { "comment": "test(vtable): cover preserving updateRecords results after clearing filters", - "type": "patch", + "type": "none", "packageName": "@visactor/vtable" } ],