fix(database): bound large cell previews and use dialog editing (#1040)

Limit grid and export-preview cell text to 1000 UTF-16 code units plus an ellipsis. Edit large values in a wrapped dialog while preserving complete clipboard, export and database values.

Reproduced STATUS_STACK_OVERFLOW (0xC00000FD) in Windows WebView2 against a real PostgreSQL table with nine rows and 8.83 MB of jsonb data. Verified the fix through display, selection, editing, full clipboard copy, JSON file export and PostgreSQL writeback. All PR CI checks passed, including 5625 frontend tests and Rust checks on Windows, macOS and Linux.

Fixes #825
Цей коміт міститься в:
l0ng-ai authored and GitHub committed 2026-11-03 21:49:26 +08:00
1 джерело dcd8ecc5ae
коміт e2e699dca9
7 files changed
+165 -6

No files matched your search

+37
Переглянути файл
@@ -0,0 +1,37 @@
import { fireEvent, render, screen, waitFor } from "@testing-library/react";
import { describe, expect, it, vi } from "vitest";
import { commands } from "@/platform/ipc";
import { ExportDialog } from "./ExportDialog";
import { cellPreview } from "./cellPreview";
vi.mock("./store", () => ({ closeDialog: vi.fn() }));
vi.mock("@/workbench/contributions", () => ({ notifications: () => ({ notify: vi.fn() }) }));
vi.mock("@tauri-apps/api/path", () => ({ homeDir: async () => "/home/test" }));
describe("large value export", () => {
it("bounds preview values while exporting every row in full", async () => {
const full = JSON.stringify({ text: "\u4e2d text ".repeat(200_000), tail: "complete" });
const dbExportFile = vi.spyOn(commands, "dbExportFile").mockResolvedValue({ status: "ok", data: null });
const rows = [[full], ["short"], [null]];
render(
<ExportDialog
data={{ columns: [{ name: "payload", type: "jsonb" }], rows, table: "big", driver: "postgres" }}
source="public.big"
initialFormat="json"
/>,
);
const preview = screen.getByLabelText("Export preview");
expect(JSON.parse(preview.textContent!)).toEqual([
{ payload: cellPreview(full) },
{ payload: "short" },
{ payload: null },
]);
await waitFor(() => expect(screen.getByLabelText("Output file")).toHaveValue("/home/test/big.json"));
fireEvent.click(screen.getByRole("button", { name: "Export to File" }));
await waitFor(() => expect(dbExportFile).toHaveBeenCalled());
const [path, contents] = dbExportFile.mock.calls[0]!;
expect(path).toBe("/home/test/big.json");
expect(JSON.parse(contents)).toEqual(rows.map(([payload]) => ({ payload })));
dbExportFile.mockRestore();
});
});