From 0c8bf24977eb7338521ea2774b42575a3cf75ba8 Mon Sep 17 00:00:00 2001 From: t8y2 <1156263951@qq.com> Date: Tue, 23 Jun 2026 20:33:51 +0800 Subject: [PATCH] fix(elasticsearch): save new document rows --- .../components/document/DocumentBrowser.vue | 48 +++++++++++++++++-- apps/desktop/src/components/grid/DataGrid.vue | 3 +- .../src/composables/useDataGridEditor.ts | 26 ++++++++++ 3 files changed, 71 insertions(+), 6 deletions(-) diff --git a/apps/desktop/src/components/document/DocumentBrowser.vue b/apps/desktop/src/components/document/DocumentBrowser.vue index a9149a553..b7f0c9e1c 100644 --- a/apps/desktop/src/components/document/DocumentBrowser.vue +++ b/apps/desktop/src/components/document/DocumentBrowser.vue @@ -88,6 +88,13 @@ type LocalFilterSummary = { values: string[]; hiddenValueCount: number; }; +type DocumentGridChanges = { + dirtyRows: Map>; + deletedRows: Set; + newRows: MongoInputValue[][]; + columns: string[]; + rows: MongoInputValue[][]; +}; const documentFilterBuilderOpen = ref(false); const documentFilterRules = ref([]); const appliedDocumentFilter = ref | null>(null); @@ -227,7 +234,15 @@ function clearDocumentFilters(clearLocalFilter?: (columnIndex?: number) => void) applyFilter(); } -async function gridSave(changes: { dirtyRows: Map>; deletedRows: Set; columns: string[]; rows: MongoInputValue[][] }) { +function documentIdFromGridValue(value: MongoInputValue | undefined): string | null { + if (value === null || value === undefined) return null; + const parsed = parseMongoDocumentInputValue(value); + if (parsed === null || parsed === undefined) return null; + const id = typeof parsed === "object" ? JSON.stringify(parsed) : String(parsed); + return id.trim() ? id : null; +} + +async function gridSave(changes: DocumentGridChanges) { const cols = changes.columns; const idColIdx = cols.indexOf("_id"); if (idColIdx < 0) throw new Error("No _id column"); @@ -267,6 +282,20 @@ async function gridSave(changes: { dirtyRows: Map>; deletedRows: Set; newRows: MongoInputValue[][]; columns: string[]; rows: MongoInputValue[][] }): Promise { +function elasticsearchPathIdPreview(id: string): string { + return encodeURIComponent(id); +} + +async function previewDocumentChanges(changes: DocumentGridChanges): Promise { const { dirtyRows, deletedRows, newRows, columns, rows } = changes; const idColIdx = columns.indexOf("_id"); const stmts: string[] = []; @@ -296,7 +329,7 @@ async function previewDocumentChanges(changes: { dirtyRows: Map= 0 ? documentIdFromGridValue(newRow[idColIdx]) : null; + if (id) { + stmts.push(`PUT /${coll}/_doc/${elasticsearchPathIdPreview(id)}\n${JSON.stringify(doc, null, 2)}`); + } else { + stmts.push(`POST /${coll}/_doc\n${JSON.stringify(doc, null, 2)}`); + } } else { stmts.push(`db.${coll}.insertOne(${formatMongoShellLiteral(doc)})`); } diff --git a/apps/desktop/src/components/grid/DataGrid.vue b/apps/desktop/src/components/grid/DataGrid.vue index ef2114364..7cc3729a5 100644 --- a/apps/desktop/src/components/grid/DataGrid.vue +++ b/apps/desktop/src/components/grid/DataGrid.vue @@ -2631,6 +2631,7 @@ const { dirtyRows, newRows, deletedRows, + pendingChangesVersion, pendingChangeCount, hasPendingChanges, transactionActive, @@ -2712,7 +2713,7 @@ function closeSqlPreview() { } // Watch for edits — auto-refresh preview when panel is open -watch([pendingChangeCount, dirtyRows, newRows, deletedRows], () => { +watch([pendingChangeCount, pendingChangesVersion], () => { schedulePreviewRefresh(); }); diff --git a/apps/desktop/src/composables/useDataGridEditor.ts b/apps/desktop/src/composables/useDataGridEditor.ts index 723da5529..fe2996506 100644 --- a/apps/desktop/src/composables/useDataGridEditor.ts +++ b/apps/desktop/src/composables/useDataGridEditor.ts @@ -142,6 +142,7 @@ export function useDataGridEditor(options: UseDataGridEditorOptions) { const dirtyRows = ref>>(new Map()); const newRows = ref([]); const deletedRows = ref>(new Set()); + const pendingChangesVersion = ref(0); let restoredEditingCell = false; let restoredTransactionActive = false; let suppressNextBlurCommit = false; @@ -218,6 +219,10 @@ export function useDataGridEditor(options: UseDataGridEditorOptions) { transactionActive.value = true; } + function touchPendingChanges() { + pendingChangesVersion.value++; + } + function exitTransaction() { transactionActive.value = false; } @@ -415,6 +420,8 @@ export function useDataGridEditor(options: UseDataGridEditorOptions) { if (newRows.value[item.newIndex]) { newRows.value[item.newIndex][col] = newVal; } + newRows.value = [...newRows.value]; + touchPendingChanges(); editingCell.value = null; isCommitting = false; return; @@ -445,6 +452,7 @@ export function useDataGridEditor(options: UseDataGridEditorOptions) { if (rowChanges?.size === 0) dirtyRows.value.delete(item.sourceIndex); } dirtyRows.value = new Map(dirtyRows.value); + touchPendingChanges(); editingCell.value = null; isCommitting = false; } @@ -466,6 +474,7 @@ export function useDataGridEditor(options: UseDataGridEditorOptions) { const oldVal = newRows.value[item.newIndex]?.[col]; newRows.value[item.newIndex][col] = value === null ? null : coerceCellValue(value, oldVal, col); newRows.value = [...newRows.value]; + touchPendingChanges(); return; } @@ -486,6 +495,7 @@ export function useDataGridEditor(options: UseDataGridEditorOptions) { if (rowChanges?.size === 0) dirtyRows.value.delete(item.sourceIndex); } dirtyRows.value = new Map(dirtyRows.value); + touchPendingChanges(); } function cancelEdit() { @@ -511,6 +521,8 @@ export function useDataGridEditor(options: UseDataGridEditorOptions) { function addRow() { rowStatusFilter.value = rowStatusFilterAfterAddingRow(rowStatusFilter.value); newRows.value.push(result.value.columns.map(() => null)); + newRows.value = [...newRows.value]; + touchPendingChanges(); if (useTransaction.value && !transactionActive.value) { enterTransaction(); } @@ -545,6 +557,8 @@ export function useDataGridEditor(options: UseDataGridEditorOptions) { const clonedData = clonedRowData(item); rowStatusFilter.value = rowStatusFilterAfterAddingRow(rowStatusFilter.value); newRows.value.push(clonedData); + newRows.value = [...newRows.value]; + touchPendingChanges(); if (useTransaction.value && !transactionActive.value) { enterTransaction(); } @@ -564,6 +578,8 @@ export function useDataGridEditor(options: UseDataGridEditorOptions) { const clonedData = clonedRowData(item); newRows.value.push(clonedData); } + newRows.value = [...newRows.value]; + touchPendingChanges(); if (useTransaction.value && !transactionActive.value) { enterTransaction(); } @@ -574,11 +590,15 @@ export function useDataGridEditor(options: UseDataGridEditorOptions) { if (!item) return; if (item.isNew && item.newIndex !== undefined) { newRows.value.splice(item.newIndex, 1); + newRows.value = [...newRows.value]; } else if (item.sourceIndex !== undefined) { if (!canEditExistingRows.value) return; dirtyRows.value.delete(item.sourceIndex); deletedRows.value.add(item.sourceIndex); + dirtyRows.value = new Map(dirtyRows.value); + deletedRows.value = new Set(deletedRows.value); } + touchPendingChanges(); if (editingCell.value?.rowId === rowId) editingCell.value = null; if (useTransaction.value && !transactionActive.value) { enterTransaction(); @@ -616,6 +636,8 @@ export function useDataGridEditor(options: UseDataGridEditorOptions) { const item = getRowItem(rowId); if (item?.sourceIndex !== undefined) { deletedRows.value.delete(item.sourceIndex); + deletedRows.value = new Set(deletedRows.value); + touchPendingChanges(); } } @@ -725,6 +747,7 @@ export function useDataGridEditor(options: UseDataGridEditorOptions) { dirtyRows.value.clear(); newRows.value = []; deletedRows.value.clear(); + touchPendingChanges(); exitTransaction(); isSaving.value = false; if (shouldReloadAfterSave) { @@ -808,6 +831,7 @@ export function useDataGridEditor(options: UseDataGridEditorOptions) { dirtyRows.value.clear(); newRows.value = []; deletedRows.value.clear(); + touchPendingChanges(); exitTransaction(); isSaving.value = false; if (shouldReloadAfterSave) { @@ -819,6 +843,7 @@ export function useDataGridEditor(options: UseDataGridEditorOptions) { dirtyRows.value.clear(); newRows.value = []; deletedRows.value.clear(); + touchPendingChanges(); editingCell.value = null; exitTransaction(); } @@ -939,6 +964,7 @@ export function useDataGridEditor(options: UseDataGridEditorOptions) { dirtyRows, newRows, deletedRows, + pendingChangesVersion, dirtyRowCount, newRowCount, deletedRowCount,