fix(grid): preserve pending value editor draft on refresh
This commit is contained in:
1 parent
1c972b80c0
commit
b00821d2c5
1 file changed
+39
-6
@@ -599,6 +599,7 @@ let preservedSelectionOnNextResult: {
|
||||
} | null = null;
|
||||
let preservedDetailsOnNextResult: {
|
||||
sideCell?: PersistedDataGridSelection;
|
||||
sideCellHasPendingDraft?: boolean;
|
||||
cellDialog?: PersistedDataGridSelection;
|
||||
rowDialog?: PersistedDataGridSelection;
|
||||
columnDialog?: PersistedDataGridSelection;
|
||||
@@ -5942,6 +5943,10 @@ function captureColumnTargetForRefresh(columnIndex: number | null): PersistedDat
|
||||
function captureDetailsForRefresh() {
|
||||
const details = {
|
||||
sideCell: showCellDetail.value ? captureCellTargetForRefresh(detailCell.value) : undefined,
|
||||
// A refresh must not silently discard an unsaved value-editor draft: closing
|
||||
// and reopening the panel (even at the "same" cell) would re-derive its text
|
||||
// from the freshly fetched row, wiping whatever the user was typing.
|
||||
sideCellHasPendingDraft: showCellDetail.value && hasPendingDetailEditorDraft.value,
|
||||
cellDialog: cellDetailDialogOpen.value ? captureCellTargetForRefresh(cellDetailDialogTarget.value) : undefined,
|
||||
rowDialog: rowDetailDialogOpen.value ? captureRowTargetForRefresh(rowDetailDialogRowId.value) : undefined,
|
||||
columnDialog: columnDetailDialogOpen.value ? captureColumnTargetForRefresh(columnDetailDialogColumnIndex.value) : undefined,
|
||||
@@ -5965,11 +5970,17 @@ function restoreDetailCellAfterRefresh(snapshot: PersistedDataGridSelection | un
|
||||
}
|
||||
|
||||
function restoreDetailsAfterRefresh(details: NonNullable<typeof preservedDetailsOnNextResult>) {
|
||||
const sideCell = restoreDetailCellAfterRefresh(details.sideCell);
|
||||
if (sideCell) {
|
||||
detailCell.value = sideCell;
|
||||
showCellDetail.value = true;
|
||||
hydrateCellDetailTarget(sideCell);
|
||||
// When the side panel was left open with an unsaved value-editor draft, it was
|
||||
// deliberately kept open (not closed) across this refresh, so there is nothing
|
||||
// to restore here - reassigning detailCell would re-derive the editor text from
|
||||
// the freshly fetched row and clobber the draft the user is still editing.
|
||||
if (!details.sideCellHasPendingDraft) {
|
||||
const sideCell = restoreDetailCellAfterRefresh(details.sideCell);
|
||||
if (sideCell) {
|
||||
detailCell.value = sideCell;
|
||||
showCellDetail.value = true;
|
||||
hydrateCellDetailTarget(sideCell);
|
||||
}
|
||||
}
|
||||
|
||||
const cellDialog = restoreDetailCellAfterRefresh(details.cellDialog);
|
||||
@@ -6461,6 +6472,12 @@ watch(activeCellDetailTab, (tab) => {
|
||||
const detailEditValue = ref("");
|
||||
const detailEditOriginalValue = ref("");
|
||||
const isEditingDetail = ref(false);
|
||||
// commitDetailEdit() intentionally re-triggers the activeCellDetail watch below to
|
||||
// re-sync the editor with the canonical committed value. Any other change to the
|
||||
// same cell's underlying data while still editing (e.g. a result refresh, or a
|
||||
// large-value hydration resolving) must not clobber the user's in-progress draft.
|
||||
let allowActiveCellDetailResync = false;
|
||||
let lastSyncedDetailCellKey: string | null = null;
|
||||
const detailValueDiffOpen = ref(false);
|
||||
const detailValueDiffSnapshot = ref<Readonly<JsonValueDiffSnapshot> | null>(null);
|
||||
const hasPendingDetailEditorDraft = computed(() => isEditingDetail.value && detailEditValue.value !== detailEditOriginalValue.value);
|
||||
@@ -6591,6 +6608,15 @@ watch(activeCellDetail, (detail) => {
|
||||
resetDetailEdit();
|
||||
return;
|
||||
}
|
||||
const cellKey = `${detail.rowId}:${detail.colIndex}`;
|
||||
const isSameCellStillEditing = isEditingDetail.value && cellKey === lastSyncedDetailCellKey;
|
||||
lastSyncedDetailCellKey = cellKey;
|
||||
if (isSameCellStillEditing && !allowActiveCellDetailResync) {
|
||||
// The row's underlying data changed (e.g. a result refresh or a large-value
|
||||
// hydration) while the user is still editing this same cell. Keep their draft.
|
||||
return;
|
||||
}
|
||||
allowActiveCellDetailResync = false;
|
||||
const value = dataGridCellEditorText({
|
||||
value: detail.value,
|
||||
databaseType: resolvedDatabaseType.value,
|
||||
@@ -6668,6 +6694,7 @@ function resetDetailEdit() {
|
||||
isEditingDetail.value = false;
|
||||
detailEditValue.value = "";
|
||||
detailEditOriginalValue.value = "";
|
||||
lastSyncedDetailCellKey = null;
|
||||
}
|
||||
|
||||
function closeCellDetails() {
|
||||
@@ -6741,6 +6768,9 @@ function commitDetailEdit() {
|
||||
if (!item || item.isDeleted) return;
|
||||
applyCellValue(detail.rowId, detail.colIndex, detailEditValue.value);
|
||||
detailEditOriginalValue.value = detailEditValue.value;
|
||||
// Force the activeCellDetail watch to re-run so the editor picks up the
|
||||
// canonical (possibly coerced) committed value.
|
||||
allowActiveCellDetailResync = true;
|
||||
detailCell.value = detailCell.value ? { ...detailCell.value } : null;
|
||||
}
|
||||
|
||||
@@ -10529,7 +10559,10 @@ watch(
|
||||
clearCellSelection();
|
||||
clearRowSelection();
|
||||
invalidateContextMenuTarget();
|
||||
closeCellDetails();
|
||||
// Don't discard an unsaved value-editor draft just because the result set
|
||||
// refreshed underneath it; leave the panel/editor state as-is and let
|
||||
// restoreDetailsAfterRefresh() below skip re-opening it from fresh data.
|
||||
if (!detailsSnapshot?.sideCellHasPendingDraft) closeCellDetails();
|
||||
closeDetailDialogs();
|
||||
if (shouldPreserveTranspose) {
|
||||
applyTransposeState(nextTransposeStateForRecordCount(showTranspose.value, transposeRowIndex.value, displayRowCount.value));
|
||||
|
||||
Reference in new issue
Block a user