Repository navigation
fix(vtable): map sorted view index to source record in deleteRecords/updateRecords - #5330
william-xue wants to merge 3 commits into
Conversation
…updateRecords deleteRecords/updateRecords receive body display indices, but the sync branches of DataSource used them directly as indices into this.records (_source, source order). Sorting keeps _source in source order and stores the view -> source mapping in currentIndexedData, so on a sorted table the wrong record was deleted/updated in the user's records array.
|
有 2 处阻塞性问题需要修正后再合并:
|
- resolve every body view index to its source record first, then delete the raw indexes in descending order, so a batch delete on a sorted table no longer misses records when rawRecords and this.records are the same array - map the body view index through _currentPagerIndexedData (same as getRecordIndexPaths) so deleteRecords/updateRecords on currentPage > 0 operate on the records shown on the current page - add tests for sorted batch delete, sorted update and paginated delete/update
|
已按这两点提交 df4a503:
新增 4 个用例:排序表单条/批量删除、排序表更新、分页排序表(perPageCount: 2, currentPage: 1)下的删除与更新。本地仓库没有 node_modules 跑不了 jest-electron,单测交由 CI(unit-test)执行。 |
There was a problem hiding this comment.
Latest reviewed commit: cdab8fe
No confirmed new issues found.
| if (rawIndex >= 0) { | ||
| rawRecords.splice(rawIndex, 1); | ||
| rawDeletedIndexs.push(rawIndex); | ||
| pendingDeletes.push(rawIndex); |
There was a problem hiding this comment.
[P2] 批量删除重复引用记录时避免重复删除同一原始下标
当 syncRecordOperationsToSourceRecords: true 且源数组中复用同一记录对象时,不同显示行经 rawRecords.indexOf(deletedRecord) 会解析到同一原始下标;这里将它多次加入 pendingDeletes,后面连续 splice 会误删其他行。例如无排序、无筛选时源数组为 [A, B, A, B](两个 A 引用同一对象,两个 B 亦然),调用 deleteRecords([1, 2, 3]) 应留下 A,但待删下标变成 [1, 1, 0],实际留下 B;改动前逐次删除在此输入会留下 A。这与既有讨论中的排序后映射失效不同,是预收集下标带来的新回归。建议直接使用已映射的源下标(筛选态则建立按出现次数匹配的原始位置映射),确保每个显示行对应不同原始槽位。上述结果来自按源码删除循环构造的 Node 最小复现,未运行工程测试。
Confirmed fixed (cdab8fe): For the original [A, B, A, B] input deleting view rows [1, 2, 3], the reservedRawIndexs loop now skips already-reserved source positions, then splices distinct positions in descending order. The ListTable sync path still invokes this branch for non-tree, non-grouped tables (record-helper.ts:1004-1009). A source-matched Node reproduction leaves A, so the original incorrect result is gone; this is not a full integration test.
deleteRecords 的同步分支先把显示行映射成「待删记录」,再用 rawRecords.indexOf 得到原始下标并按降序 splice。当同一个记录对象在源数组中被引用多次时(例如多张 表共用同一条记录),indexOf 会对多条显示行返回同一个原始下标,这个下标被重复 加入待删列表后连续 splice,会连带删掉别的行:源数组 [A, B, A, B] 删除显示行 [1, 2, 3] 时留下的是 B 而不是 A。 改为在解析阶段为每条显示行预留一个尚未占用的原始槽位(命中已占用的下标时, indexOf 从该位置继续向后查找),保证显示行与原始槽位一一对应。记录互不重复时 行为不变。 新增 1 条回归用例:源数组引用同一对象两次,批量删除 [1, 2, 3] 后只保留第 0 行 引用的记录。
[中文版模板 / Chinese template]
🤔 This is a ...
🔗 Related issue link
No tracking issue. Found while checking
syncRecordOperationsToSourceRecordson a sorted table.💡 Background and solution
syncRecordOperationsToSourceRecords: truepromises thatdeleteRecords/updateRecordswrite back to the array passed inoptions.records. Both APIs receive body display indices, and the sync branches inDataSourceused that display index directly as an index intothis.records:this.recordsis_source, i.e. the data source array in source order. Sorting does not reorder_source:DataSource.sort()only stores the view → source mapping incurrentIndexedData, which is exactly what the non-sync paths already use (deleteRecordsForSorted/updateRecordsForSortedboth readthis.currentIndexedData[recordIndex]). Filtering keeps the same contract, because the view index then maps identically onto the filtered_source.So on a sorted table the sync path touched the wrong record. Reproduced with the published 1.26.8 UMD bundle (desc-sorted
id, 5 records, headless Chrome):[5,4,3,2,1])deleteRecords([0])[2,3,4,5], view[5,4,3,2]— id 5 still visible, id 1 silently dropped[1,2,3,4], view[4,3,2,1]updateRecords([{id:5,name:'FIVE-UPDATED'}], [0])[0](id 1) replaced, view[5,5,4,3,2]— duplicate id 5[5,4,3,2,1]Fix: map the display index back to the data source index through
currentIndexedDatabefore readingthis.records(_getRecordIndexFromViewIndex, identity when the table is neither sorted nor filtered, so the existing behavior is unchanged). Tree / grouped data are untouched — those entries are arrays and keep the previous fallback.📝 Changelog
☑️ Self-Check before Merge
🚀 Summary
copilot:summary
🔍 Walkthrough
copilot:walkthrough