diff --git a/src/d.ts/index.ts b/src/d.ts/index.ts index dd635a1bc..0bddf2bdf 100644 --- a/src/d.ts/index.ts +++ b/src/d.ts/index.ts @@ -120,6 +120,7 @@ export interface IUserConfig { // 系统配置 export interface ISystemConfig { 'odc.data.export.enabled': string; + 'odc.data.result-set.copy.enabled': string; [key: string]: string; } diff --git a/src/page/Workspace/components/DDLResultSet/ColumnModeModal.tsx b/src/page/Workspace/components/DDLResultSet/ColumnModeModal.tsx index a012000f6..6f8811c81 100644 --- a/src/page/Workspace/components/DDLResultSet/ColumnModeModal.tsx +++ b/src/page/Workspace/components/DDLResultSet/ColumnModeModal.tsx @@ -23,8 +23,10 @@ import React, { useMemo, useRef } from 'react'; +import { inject, observer } from 'mobx-react'; import type { ResultSetColumn } from '@/d.ts'; +import type { SettingStore } from '@/store/setting'; import { LeftSquareOutlined, RightSquareOutlined } from '@ant-design/icons'; import type { DataGridRef, @@ -47,6 +49,7 @@ interface IProps { total: number; onClose: () => void; setSelectedRowIndex: (rowIdx: number) => void; + settingStore?: SettingStore; } interface DataInColumnMode extends RowType { @@ -80,7 +83,8 @@ const ColumnModeModal: React.FC = function (props) { total, currentIdx, setSelectedRowIndex, - onClose + onClose, + settingStore } = props; const resultContext = useContext(ResultContext); @@ -190,7 +194,9 @@ const ColumnModeModal: React.FC = function (props) { enableColumnRecord={false} enableRowRecord={false} readonly={true} - onCopy={handleForbidCopy} + onCopy={ + settingStore?.enableResultSetCopy ? undefined : handleForbidCopy + } contextMenuRender={ResultSetContextMenu} /> @@ -246,4 +252,4 @@ const ColumnModeModal: React.FC = function (props) { ); }; -export default ColumnModeModal; +export default inject('settingStore')(observer(ColumnModeModal)); diff --git a/src/page/Workspace/components/DDLResultSet/ResultSetContextMenu.tsx b/src/page/Workspace/components/DDLResultSet/ResultSetContextMenu.tsx index 239650ce3..e3078828c 100644 --- a/src/page/Workspace/components/DDLResultSet/ResultSetContextMenu.tsx +++ b/src/page/Workspace/components/DDLResultSet/ResultSetContextMenu.tsx @@ -18,6 +18,7 @@ import type { ContextMenuConfig, ContextMenuRenderProps } from '@oceanbase-odc/ob-react-data-grid/lib/types'; +import settingStore from '@/store/setting'; import { Menu } from 'antd'; import React, { useContext, useEffect, useMemo } from 'react'; import ResultContext from './ResultContext'; @@ -79,15 +80,25 @@ function ResultSetContextMenu(props: ContextMenuRenderProps) { setContextMenuVisible(false); }; + // 与格子复制共用 enableResultSetCopy:开态允许行选中/多行渲染 isShowRowSelected(clipMenu) + const enableResultSetCopy = settingStore.enableResultSetCopy; + const menuItems = useMemo(() => { - if (isSelectMultiRow) { - return []; - } - if (isRowSelected && !isEditing) { + if ( + !enableResultSetCopy && + (isSelectMultiRow || (isRowSelected && !isEditing)) + ) { return []; } return renderConfigMenuItems(visibleConfig, row, closeMenu); - }, [isSelectMultiRow, isRowSelected, isEditing, visibleConfig, row]); + }, [ + enableResultSetCopy, + isSelectMultiRow, + isRowSelected, + isEditing, + visibleConfig, + row + ]); useEffect(() => { if (!menuItems.length) { diff --git a/src/page/Workspace/components/DDLResultSet/index.tsx b/src/page/Workspace/components/DDLResultSet/index.tsx index b05380eea..198ae9175 100644 --- a/src/page/Workspace/components/DDLResultSet/index.tsx +++ b/src/page/Workspace/components/DDLResultSet/index.tsx @@ -68,6 +68,10 @@ import Icon, { VerticalRightOutlined } from '@ant-design/icons'; import type { DataGridRef } from '@oceanbase-odc/ob-react-data-grid'; +import { + defaultOnCopy, + defaultOnCopyCsv +} from '@oceanbase-odc/ob-react-data-grid'; import type { CalculatedColumn } from '@oceanbase-odc/ob-react-data-grid/lib/types'; import { useControllableValue, useUpdate } from 'ahooks'; import { @@ -105,6 +109,7 @@ import styles from './index.less'; import ResultContext from './ResultContext'; import ResultSetContextMenu from './ResultSetContextMenu'; import StatusBar from './StatusBar'; +import { copyToSQL, getColumnNameByColumnKey } from './util'; import Sync from './Sync'; import { BasicInputNumber, @@ -512,16 +517,80 @@ const DDLResultSet: React.FC = function (props) { selectedRange?.columnIdx === selectedRange?.endColumnIdx && selectedRange?.rowIdx === selectedRange?.endRowIdx; const tableColumns: Partial[] = table?.columns; + const columnName = getColumnNameByColumnKey(columnKey, columns); const column: Partial = columns?.find((column) => { return column?.key === columnKey; }); const isMasked = column?.masked; const isSelectedRow = !!gridRef.current?.selectedRows?.size; + const enableCopy = settingStore.enableResultSetCopy; + const clipMenu = enableCopy + ? { + key: 'clip', + text: formatMessage({ + id: 'odc.components.DDLResultSet.OutputToShearPlate', + defaultMessage: '输出到剪切板' + }), + isShowRowSelected: true, + // 输出到剪切板 + children: [ + { + key: 'clip-sql', + text: 'SQL', + // SQL 文件 + onClick: clipSQL + }, + { + key: 'clip-csv', + text: 'CSV', + // CSV 文件 + onClick: clipCsv + } + ] + } + : null; + function copy() { + defaultOnCopy(gridRef.current); + } + function clipSQL() { + if (!tableColumns || (!columnName && !isSelectedRow)) { + copyToSQL( + gridRef.current, + columns, + undefined, + session?.connection?.dialectType, + rows + ); + } else { + copyToSQL( + gridRef.current, + columns, + table?.tableName, + session?.connection?.dialectType, + rows + ); + } + } + function clipCsv() { + defaultOnCopyCsv(gridRef.current); + } if (isSelectedRow) { - return []; + return [clipMenu].filter(Boolean); } if (!tableColumns) { - return []; + return enableCopy + ? [ + { + key: 'copy', + text: formatMessage({ + id: 'odc.components.ConnectionCardList.Copy', + defaultMessage: '复制' + }), + onClick: copy + }, + clipMenu + ].filter(Boolean) + : []; } if (!column) { return []; @@ -534,6 +603,15 @@ const DDLResultSet: React.FC = function (props) { settingStore.enableDataExport && !isMasked; return [ + enableCopy && { + key: 'copy', + text: formatMessage({ + id: 'odc.components.ConnectionCardList.Copy', + defaultMessage: '复制' + }), + onClick: copy + }, + clipMenu, isEditing && isSingleSelected && { key: 'setnull', @@ -642,7 +720,7 @@ const DDLResultSet: React.FC = function (props) { } ].filter(Boolean); }, - [table, columns, isEditing, gridRef, downloadObjectData, rows, sessionId] + [table, columns, isEditing, gridRef, downloadObjectData, rows, sessionId, session, settingStore] ); const getContextMenuConfig = useCallback( function (row: any, column: CalculatedColumn) { @@ -1425,7 +1503,9 @@ const DDLResultSet: React.FC = function (props) { contextMenuRender={ResultSetContextMenu} enableFrozenRow={true} pasteFormatter={pasteFormatter} - onCopy={handleForbidCopy} + onCopy={ + settingStore.enableResultSetCopy ? undefined : handleForbidCopy + } />