perf(grid): optimize bulk edit performance
This commit is contained in:
1 parent
e6da0a6298
commit
1e21a5ad52
3 files changed
+151
-39
No files matched your search
@@ -1,4 +1,4 @@
|
||||
import { ref, computed, nextTick, watch, getCurrentInstance, onActivated, onBeforeUnmount, onDeactivated, onMounted, toRaw, type ComputedRef, type Ref } from "vue";
|
||||
import { ref, shallowRef, computed, nextTick, watch, getCurrentInstance, onActivated, onBeforeUnmount, onDeactivated, onMounted, toRaw, type ComputedRef, type Ref } from "vue";
|
||||
import * as api from "@/lib/backend/api";
|
||||
import type { CellValue } from "@/lib/dataGrid/cellValue";
|
||||
import { coerceDataGridCellValue, dataGridCellEditorText } from "@/lib/dataGrid/dataGridCellCoercion";
|
||||
@@ -206,7 +206,7 @@ export function useDataGridEditor(options: UseDataGridEditorOptions) {
|
||||
const editingCell = ref<{ rowId: number; col: number } | null>(null);
|
||||
const editValue = ref("");
|
||||
const scrollerRef = ref<GridScrollerRef | null>(null);
|
||||
const dirtyRows = ref<Map<number, Map<number, CellValue>>>(new Map());
|
||||
const dirtyRows = shallowRef<Map<number, Map<number, CellValue>>>(new Map());
|
||||
const newRows = ref<CellValue[][]>([]);
|
||||
const deletedRows = ref<Set<number>>(new Set());
|
||||
const quickEntryDraftRow = ref<CellValue[]>([]);
|
||||
@@ -500,10 +500,45 @@ export function useDataGridEditor(options: UseDataGridEditorOptions) {
|
||||
}) as CellValue;
|
||||
}
|
||||
|
||||
let isBatching = false;
|
||||
let batchUndoSnapshotPushed = false;
|
||||
let batchMutated = false;
|
||||
let batchColumnInfoCache: Map<number, ColumnInfo | undefined> | null = null;
|
||||
|
||||
function beginBatch() {
|
||||
if (isBatching) return;
|
||||
isBatching = true;
|
||||
batchUndoSnapshotPushed = false;
|
||||
batchMutated = false;
|
||||
batchColumnInfoCache = new Map();
|
||||
}
|
||||
|
||||
function commitBatch() {
|
||||
if (!isBatching) return;
|
||||
isBatching = false;
|
||||
batchColumnInfoCache = null;
|
||||
if (!batchMutated) return;
|
||||
dirtyRows.value = new Map(dirtyRows.value);
|
||||
newRows.value = [...newRows.value];
|
||||
touchPendingChanges();
|
||||
}
|
||||
|
||||
function markBatchMutated() {
|
||||
if (isBatching) batchMutated = true;
|
||||
}
|
||||
|
||||
function tableColumnForGridColumn(columnIndex: number): ColumnInfo | undefined {
|
||||
if (isBatching && batchColumnInfoCache) {
|
||||
if (batchColumnInfoCache.has(columnIndex)) {
|
||||
return batchColumnInfoCache.get(columnIndex);
|
||||
}
|
||||
}
|
||||
const columnName = sourceColumns.value?.[columnIndex] ?? result.value.columns[columnIndex];
|
||||
if (!columnName) return undefined;
|
||||
return tableMeta.value?.columns.find((column) => column.name.toLowerCase() === columnName.toLowerCase());
|
||||
const info = columnName ? tableMeta.value?.columns.find((column) => column.name.toLowerCase() === columnName.toLowerCase()) : undefined;
|
||||
if (isBatching && batchColumnInfoCache) {
|
||||
batchColumnInfoCache.set(columnIndex, info);
|
||||
}
|
||||
return info;
|
||||
}
|
||||
|
||||
function canEditColumn(columnIndex: number): boolean {
|
||||
@@ -747,9 +782,19 @@ export function useDataGridEditor(options: UseDataGridEditorOptions) {
|
||||
const nextDraftRow = [...quickEntryDraftRow.value];
|
||||
nextDraftRow[col] = value === null ? null : coerceCellValue(value, oldVal, col, options);
|
||||
if (nextDraftRow[col] === oldVal) return;
|
||||
pushUndoSnapshot();
|
||||
if (isBatching) {
|
||||
if (!batchUndoSnapshotPushed) {
|
||||
pushUndoSnapshot();
|
||||
batchUndoSnapshotPushed = true;
|
||||
}
|
||||
} else {
|
||||
pushUndoSnapshot();
|
||||
}
|
||||
quickEntryDraftRow.value = draftRowHasValue(nextDraftRow) ? nextDraftRow : emptyDraftRow();
|
||||
touchPendingChanges();
|
||||
markBatchMutated();
|
||||
if (!isBatching) {
|
||||
touchPendingChanges();
|
||||
}
|
||||
scheduleQuickEntryDraftPromotion();
|
||||
return;
|
||||
}
|
||||
@@ -761,10 +806,20 @@ export function useDataGridEditor(options: UseDataGridEditorOptions) {
|
||||
const oldVal = row[col];
|
||||
const newVal = value === null ? null : coerceCellValue(value, oldVal, col, options);
|
||||
if (newVal === oldVal) return;
|
||||
pushUndoSnapshot();
|
||||
if (isBatching) {
|
||||
if (!batchUndoSnapshotPushed) {
|
||||
pushUndoSnapshot();
|
||||
batchUndoSnapshotPushed = true;
|
||||
}
|
||||
} else {
|
||||
pushUndoSnapshot();
|
||||
}
|
||||
row[col] = newVal;
|
||||
newRows.value = [...newRows.value];
|
||||
touchPendingChanges();
|
||||
markBatchMutated();
|
||||
if (!isBatching) {
|
||||
newRows.value = [...newRows.value];
|
||||
touchPendingChanges();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -778,19 +833,39 @@ export function useDataGridEditor(options: UseDataGridEditorOptions) {
|
||||
const newVal = value === null ? null : coerceCellValue(value, oldVal, col, options);
|
||||
if (newVal === currentVal) return;
|
||||
if (newVal !== oldVal) {
|
||||
pushUndoSnapshot();
|
||||
if (isBatching) {
|
||||
if (!batchUndoSnapshotPushed) {
|
||||
pushUndoSnapshot();
|
||||
batchUndoSnapshotPushed = true;
|
||||
}
|
||||
} else {
|
||||
pushUndoSnapshot();
|
||||
}
|
||||
if (!dirtyRows.value.has(item.sourceIndex)) dirtyRows.value.set(item.sourceIndex, new Map());
|
||||
dirtyRows.value.get(item.sourceIndex)!.set(col, newVal);
|
||||
markBatchMutated();
|
||||
if (useTransaction.value && !transactionActive.value) {
|
||||
enterTransaction();
|
||||
}
|
||||
} else {
|
||||
if (hasPendingCellChange) pushUndoSnapshot();
|
||||
if (hasPendingCellChange) {
|
||||
if (isBatching) {
|
||||
if (!batchUndoSnapshotPushed) {
|
||||
pushUndoSnapshot();
|
||||
batchUndoSnapshotPushed = true;
|
||||
}
|
||||
} else {
|
||||
pushUndoSnapshot();
|
||||
}
|
||||
}
|
||||
rowChanges?.delete(col);
|
||||
if (rowChanges?.size === 0) dirtyRows.value.delete(item.sourceIndex);
|
||||
if (hasPendingCellChange) markBatchMutated();
|
||||
}
|
||||
if (!isBatching) {
|
||||
dirtyRows.value = new Map(dirtyRows.value);
|
||||
touchPendingChanges();
|
||||
}
|
||||
dirtyRows.value = new Map(dirtyRows.value);
|
||||
touchPendingChanges();
|
||||
}
|
||||
|
||||
function restoreCellValue(rowId: number, col: number) {
|
||||
@@ -1330,9 +1405,9 @@ export function useDataGridEditor(options: UseDataGridEditorOptions) {
|
||||
}
|
||||
|
||||
function discardChanges() {
|
||||
dirtyRows.value.clear();
|
||||
dirtyRows.value = new Map();
|
||||
newRows.value = [];
|
||||
deletedRows.value.clear();
|
||||
deletedRows.value = new Set();
|
||||
quickEntryDraftRow.value = emptyDraftRow();
|
||||
queuedAutoSaveChanges.clear();
|
||||
editingCell.value = null;
|
||||
@@ -1477,6 +1552,8 @@ export function useDataGridEditor(options: UseDataGridEditorOptions) {
|
||||
isSaving,
|
||||
saveError,
|
||||
useTransaction,
|
||||
beginBatch,
|
||||
commitBatch,
|
||||
enterTransaction,
|
||||
exitTransaction,
|
||||
startEdit,
|
||||
|
||||
Reference in new issue
Block a user