From a07eea7815d845545452afce86afdfa6f77d16ff Mon Sep 17 00:00:00 2001 From: Syngnat Date: Tue, 28 Apr 2026 12:39:51 +0800 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20feat(data-grid):=20=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E8=A1=A8=E6=95=B0=E6=8D=AE=E9=A1=B5=20DDL=20=E6=9F=A5?= =?UTF-8?q?=E7=9C=8B=E4=B8=8E=E5=BD=93=E5=89=8D=E9=A1=B5=E6=9F=A5=E6=89=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 表数据页新增查看 DDL 入口,支持直接打开只读 SQL 预览弹窗 - 当前页查找支持大小写不敏感高亮,仅作用于已加载数据和显示列 - 查找结果新增上一个、下一个导航,并自动聚焦选中匹配单元格 - DDL 请求增加上下文过期保护,避免切表后展示旧表结构 - 补充 DataGrid 布局、DDL 交互和查找工具函数单元测试 Refs #417 --- frontend/src/components/DataGrid.ddl.test.tsx | 312 ++++++++++++++++++ .../src/components/DataGrid.layout.test.tsx | 47 +++ frontend/src/components/DataGrid.tsx | 299 ++++++++++++++++- frontend/src/utils/dataGridFind.test.ts | 107 ++++++ frontend/src/utils/dataGridFind.ts | 145 ++++++++ 5 files changed, 902 insertions(+), 8 deletions(-) create mode 100644 frontend/src/components/DataGrid.ddl.test.tsx create mode 100644 frontend/src/utils/dataGridFind.test.ts create mode 100644 frontend/src/utils/dataGridFind.ts diff --git a/frontend/src/components/DataGrid.ddl.test.tsx b/frontend/src/components/DataGrid.ddl.test.tsx new file mode 100644 index 0000000..c1f727b --- /dev/null +++ b/frontend/src/components/DataGrid.ddl.test.tsx @@ -0,0 +1,312 @@ +import React from 'react'; +import { act, create, type ReactTestRenderer } from 'react-test-renderer'; +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; + +import DataGrid from './DataGrid'; + +const storeState = vi.hoisted(() => ({ + connections: [ + { + id: 'conn-1', + name: 'local', + config: { + type: 'mysql', + host: '127.0.0.1', + port: 3306, + user: 'root', + password: '', + database: 'main', + }, + }, + ], + addSqlLog: vi.fn(), + theme: 'light', + appearance: { + enabled: true, + opacity: 1, + blur: 0, + showDataTableVerticalBorders: false, + dataTableColumnWidthMode: 'standard', + }, + queryOptions: { + showColumnComment: false, + showColumnType: false, + }, + setQueryOptions: vi.fn(), + tableColumnOrders: {}, + enableColumnOrderMemory: false, + setTableColumnOrder: vi.fn(), + setEnableColumnOrderMemory: vi.fn(), + clearTableColumnOrder: vi.fn(), + tableHiddenColumns: {}, + enableHiddenColumnMemory: false, + setTableHiddenColumns: vi.fn(), + setEnableHiddenColumnMemory: vi.fn(), + clearTableHiddenColumns: vi.fn(), + aiPanelVisible: false, + setAIPanelVisible: vi.fn(), +})); + +const backendApp = vi.hoisted(() => ({ + ImportData: vi.fn(), + ExportTable: vi.fn(), + ExportData: vi.fn(), + ExportQuery: vi.fn(), + ApplyChanges: vi.fn(), + DBGetColumns: vi.fn(), + DBGetIndexes: vi.fn(), + DBShowCreateTable: vi.fn(), +})); + +const messageApi = vi.hoisted(() => ({ + error: vi.fn(), + info: vi.fn(), + success: vi.fn(), + warning: vi.fn(), + loading: vi.fn(() => vi.fn()), +})); + +vi.mock('../store', () => ({ + useStore: (selector: (state: typeof storeState) => any) => selector(storeState), +})); + +vi.mock('../../wailsjs/go/app/App', () => backendApp); + +vi.mock('@monaco-editor/react', () => ({ + default: ({ value }: { value?: string }) =>
{value}
, +})); + +vi.mock('./ImportPreviewModal', () => ({ + default: () => null, +})); + +vi.mock('@ant-design/icons', () => { + const Icon = () => ; + return { + ReloadOutlined: Icon, + ImportOutlined: Icon, + ExportOutlined: Icon, + DownOutlined: Icon, + PlusOutlined: Icon, + DeleteOutlined: Icon, + SaveOutlined: Icon, + UndoOutlined: Icon, + FilterOutlined: Icon, + CloseOutlined: Icon, + ConsoleSqlOutlined: Icon, + FileTextOutlined: Icon, + CopyOutlined: Icon, + ClearOutlined: Icon, + EditOutlined: Icon, + VerticalAlignBottomOutlined: Icon, + LeftOutlined: Icon, + RightOutlined: Icon, + RobotOutlined: Icon, + SearchOutlined: Icon, + }; +}); + +vi.mock('@dnd-kit/core', () => ({ + DndContext: ({ children }: any) => <>{children}, + PointerSensor: vi.fn(), + MouseSensor: vi.fn(), + TouchSensor: vi.fn(), + useSensor: vi.fn(() => ({})), + useSensors: vi.fn(() => []), + closestCenter: vi.fn(), +})); + +vi.mock('@dnd-kit/sortable', () => ({ + SortableContext: ({ children }: any) => <>{children}, + useSortable: vi.fn(() => ({ + attributes: {}, + listeners: {}, + setNodeRef: vi.fn(), + transform: null, + transition: undefined, + isDragging: false, + })), + horizontalListSortingStrategy: vi.fn(), + arrayMove: (items: any[], from: number, to: number) => { + const next = [...items]; + const [item] = next.splice(from, 1); + next.splice(to, 0, item); + return next; + }, +})); + +vi.mock('@dnd-kit/utilities', () => ({ + CSS: { + Transform: { + toString: () => '', + }, + }, +})); + +vi.mock('antd', () => { + const Button = ({ children, disabled, loading, onClick, type, ...rest }: any) => ( + + ); + const Input: any = ({ value, onChange, placeholder, ...rest }: any) => ( + + ); + Input.TextArea = ({ value, onChange, placeholder }: any) => ( +