diff --git a/apps/desktop/src/composables/__tests__/useDataGridCellDetailEdit.spec.ts b/apps/desktop/src/composables/__tests__/useDataGridCellDetailEdit.spec.ts index 65fbc499b9..7761bf9cf8 100644 --- a/apps/desktop/src/composables/__tests__/useDataGridCellDetailEdit.spec.ts +++ b/apps/desktop/src/composables/__tests__/useDataGridCellDetailEdit.spec.ts @@ -179,10 +179,10 @@ describe("useDataGridCellDetailEdit", () => { await editor.startDetailEdit(); syncEditor.mockClear(); warnFormattedJsonEdit.mockClear(); + editor.detailEditValue.value = compact; editor.formatDetailJsonDraft(); expect(editor.detailEditValue.value).toBe('{\n "owner": "zipg",\n "tags": [\n "a"\n ]\n}'); - expect(editor.detailEditOriginalValue.value).toBe(compact); expect(syncEditor).toHaveBeenLastCalledWith('{\n "owner": "zipg",\n "tags": [\n "a"\n ]\n}', ""); expect(warnFormattedJsonEdit).not.toHaveBeenCalled(); @@ -192,4 +192,62 @@ describe("useDataGridCellDetailEdit", () => { expect(editor.detailEditValue.value).toBe("not json"); expect(syncEditor).not.toHaveBeenCalled(); }); + + // issue #12416:点「编辑」进入值编辑器时,结构化值直接以格式化草稿打开, + // 不需要用户再点一次「格式化 JSON」。 + it("opens the value editor with a pretty-printed JSON draft", async () => { + const compact = '{"owner":"zipg","tags":["a"]}'; + const pretty = '{\n "owner": "zipg",\n "tags": [\n "a"\n ]\n}'; + const activeDetail = ref(detail(compact, { type: "object" })); + const applyCellValue = vi.fn(); + const warnFormattedJsonEdit = vi.fn(); + const editor = useDataGridCellDetailEdit({ + activeDetail: computed(() => activeDetail.value), + activeTab: ref("valueEditor"), + jsonFormatted: computed(() => false), + databaseType: computed(() => "mongodb"), + resultRows: computed(() => [["id", compact]]), + getColumnInfo: () => undefined, + getRowItem: () => ({ sourceIndex: 0, isNew: false, isDeleted: false }), + hydrateLargeValueCell: async () => true, + applyCellValue, + restoreCellValue: vi.fn(), + syncEditor: vi.fn(), + refreshDetail: vi.fn(), + warnFormattedJsonEdit, + }); + + await editor.startDetailEdit(); + + expect(editor.detailEditValue.value).toBe(pretty); + expect(editor.detailEditOriginalValue.value).toBe(pretty); + expect(editor.hasPendingDetailEditorDraft.value).toBe(false); + + // 未改动的提交仍然写回原始(压缩)文本,不会把格式化后的空白静默落库。 + editor.commitDetailEdit(); + expect(applyCellValue).toHaveBeenLastCalledWith(3, 1, compact); + }); + + it("keeps plain text values unchanged when the value editor opens", async () => { + const activeDetail = ref(detail("plain text")); + const editor = useDataGridCellDetailEdit({ + activeDetail: computed(() => activeDetail.value), + activeTab: ref("valueEditor"), + jsonFormatted: computed(() => false), + databaseType: computed(() => "mongodb"), + resultRows: computed(() => [["id", "plain text"]]), + getColumnInfo: () => undefined, + getRowItem: () => ({ sourceIndex: 0, isNew: false, isDeleted: false }), + hydrateLargeValueCell: async () => true, + applyCellValue: vi.fn(), + restoreCellValue: vi.fn(), + syncEditor: vi.fn(), + refreshDetail: vi.fn(), + warnFormattedJsonEdit: vi.fn(), + }); + + await editor.startDetailEdit(); + + expect(editor.detailEditValue.value).toBe("plain text"); + }); }); diff --git a/apps/desktop/src/composables/useDataGridCellDetailEdit.ts b/apps/desktop/src/composables/useDataGridCellDetailEdit.ts index 63ec01f9ad..936370ed77 100644 --- a/apps/desktop/src/composables/useDataGridCellDetailEdit.ts +++ b/apps/desktop/src/composables/useDataGridCellDetailEdit.ts @@ -80,6 +80,17 @@ export function useDataGridCellDetailEdit(options: UseDataGridCellDetailEditOpti return editorText(detail.value, detail.colIndex); } + /** + * Structured values open in the value editor as a pretty-printed draft + * (issue #12416). The baseline is formatted too, so an untouched draft still + * commits the stored raw text — `commitDetailEdit` falls back to + * `detail.value` while the draft matches its baseline. + */ + function autoFormattedEditorText(value: string, columnType?: string): string { + if (!canFormatCellDetailJson(value, columnType)) return value; + return formatJsonText(value) ?? value; + } + function resetDetailEdit() { detailEditGeneration += 1; isEditingDetail.value = false; @@ -111,7 +122,7 @@ export function useDataGridCellDetailEdit(options: UseDataGridCellDetailEditOpti lastSyncedDetailCellKey = cellKey; if (isSameCellStillEditing && !allowActiveCellDetailResync) return; allowActiveCellDetailResync = false; - const value = editorText(detail.value, detail.colIndex); + const value = autoFormattedEditorText(editorText(detail.value, detail.colIndex), detail.type); detailEditValue.value = value; detailEditOriginalValue.value = value; syncEditorFromDetailEdit(); @@ -127,7 +138,7 @@ export function useDataGridCellDetailEdit(options: UseDataGridCellDetailEditOpti const detail = options.activeDetail.value; if (!detail || !detail.isEditable || `${detail.rowId}:${detail.colIndex}` !== initialCellKey) return; options.warnFormattedJsonEdit(detail); - const value = activeDetailEditorText(detail); + const value = autoFormattedEditorText(activeDetailEditorText(detail), detail.type); detailEditValue.value = value; detailEditOriginalValue.value = value; syncEditorFromDetailEdit();