fix(database): bound export previews after Windows WebView2 reproduction

Цей коміт міститься в:
l0ng-ai committed 2026-11-03 21:24:45 +08:00
1 джерело 560002e0c6
коміт 5fff9a1dec
5 files changed
+60 -13

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();
});
});
+10 -1
Переглянути файл
@@ -17,6 +17,7 @@ import {
import { CodePreview } from "./CodePreview";
import { closeDialog } from "./store";
import styles from "./Database.module.css";
import { cellPreview } from "./cellPreview";
const PREVIEW_ROWS = 100;
/** Formats with a tabular layout (the options apply). */
@@ -59,7 +60,15 @@ export function ExportDialog({
const tabular = TABULAR.has(format);
const effective = tabular ? options : DEFAULT_EXPORT_OPTIONS;
const preview = useMemo(
() => exportData(format, { ...data, rows: data.rows.slice(0, PREVIEW_ROWS) }, effective),
() =>
exportData(
format,
{
...data,
rows: data.rows.slice(0, PREVIEW_ROWS).map((row) => row.map((v) => (v === null ? null : cellPreview(v)))),
},
effective,
),
[format, data, effective],
);
const text = () => exportData(format, data, effective);
+2 -1
Переглянути файл
@@ -2,7 +2,8 @@ import { installKeyboardDispatcher, useKeymap } from "@/platform/keymap";
import { registerActions } from "@/platform/actions";
import { fireEvent, render, screen } from "@testing-library/react";
import { afterEach, describe, expect, it, vi } from "vitest";
import { CELL_PREVIEW_LIMIT, cellPreview, Grid } from "./Grid";
import { Grid } from "./Grid";
import { CELL_PREVIEW_LIMIT, cellPreview } from "./cellPreview";
import { exportData } from "./export";
vi.mock("@tanstack/react-virtual", () => ({
+1 -11
Переглянути файл
@@ -10,6 +10,7 @@ import { Dialog, Icon, showContextMenu, type MenuItem } from "@/ui";
import { parseDelimited, toCsv, toTsv, type Cell } from "./model";
import styles from "./Database.module.css";
import { tx } from "@/platform/i18n";
import { CELL_PREVIEW_LIMIT, cellPreview } from "./cellPreview";
export interface GridColumn {
name: string;
@@ -69,17 +70,6 @@ interface Sel {
c1: number;
}
export const CELL_PREVIEW_LIMIT = 1000;
/** Bound text layout without changing the underlying value or splitting a surrogate pair. */
export function cellPreview(value: string): string {
if (value.length <= CELL_PREVIEW_LIMIT) return value;
let end = CELL_PREVIEW_LIMIT;
const last = value.charCodeAt(end - 1);
if (last >= 0xd800 && last <= 0xdbff) end--;
return value.slice(0, end) + "\u2026";
}
const ROW_H = 24;
const NUM_W = 48;
+10
Переглянути файл
@@ -0,0 +1,10 @@
export const CELL_PREVIEW_LIMIT = 1000;
/** Bound text layout without changing the underlying value or splitting a surrogate pair. */
export function cellPreview(value: string): string {
if (value.length <= CELL_PREVIEW_LIMIT) return value;
let end = CELL_PREVIEW_LIMIT;
const last = value.charCodeAt(end - 1);
if (last >= 0xd800 && last <= 0xdbff) end--;
return value.slice(0, end) + "\u2026";
}