дзеркало
https://github.com/l0ng-ai/openidea.git
синхронізовано 2026-11-08 19:02:17 +02:00
fix(database): bound export previews after Windows WebView2 reproduction
Цей коміт міститься в:
1 джерело
560002e0c6
коміт
5fff9a1dec
5 files changed
+60
-13
No files matched your search
@@ -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();
|
||||
});
|
||||
});
|
||||
@@ -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,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", () => ({
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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";
|
||||
}
|
||||
Reference in new issue
Заблокувати користувача