diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 552cd732..04a6cb17 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -255,7 +255,9 @@ jobs: cp chat2db-client/versions/${{ steps.chat2db_version.outputs.substring }}/static/chat2db-server-start.jar ./oss_temp_file cp -r chat2db-client/release/*.dmg ./oss_temp_file cp -r chat2db-client/versions/${{ steps.chat2db_version.outputs.substring }}/dist ./oss_temp_file/dist - cd chat2db-client/versions/${{ steps.chat2db_version.outputs.substring }}/static/ && zip -r chat2db-server-start.zip ./ + cd chat2db-client/versions/${{ steps.chat2db_version.outputs.substring }}/ && zip -r ${{ steps.chat2db_version.outputs.substring }}.zip ./ + cp -r ${{ steps.chat2db_version.outputs.substring }}.zip ../../../oss_temp_file + cd static/ && zip -r chat2db-server-start.zip ./ cp -r chat2db-server-start.zip ../../../../oss_temp_file # 准备要需要的数据 MacOS arm64 diff --git a/CHANGELOG.md b/CHANGELOG.md index b92bd104..9135151d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,28 @@ +# 3.0.5 +`2023-10-23` +**Changelog** +- ⭐【New Features】Supports visual database creation +- ⭐【New Features】Support hot update +- ⭐【New Features】Double-click the table to open it directly +- ⚡️【Optimize】The search table supports size fuzzy matching +- ⚡️【Optimize】Sort Database and Schema at the top +- ⚡️【Optimize】The queried data supports editing and modification in the large popup window of the view +- ⚡️【Optimize】Example Query the page loading effect of data +- ⚡️【Optimize】Keep the top focused tab always in the viewable area +- ⚡️【Optimize】Query data cell does not have scroll bar problem + +**更新日志** +- ⭐【新功能】支持可视化创建数据库 +- ⭐【新功能】支持热更新 +- ⭐【新功能】双击表直接打开表 +- ⚡️【优化】搜索表支持大小模糊匹配 +- ⚡️【优化】Database 和 Schema 排序 +- ⚡️【优化】查询的数据支持在查看的大的弹窗中编辑修改 +- ⚡️【优化】查询数据翻页loading效果 +- ⚡️【优化】保持顶部聚焦的tab永远在可视区域内 +- ⚡️【优化】查询数据单元格没有滚动条问题 + + # 3.0.4 `2023-10-20` diff --git a/chat2db-client/.umirc.ts b/chat2db-client/.umirc.ts index 0ed67cc9..fe3b19ce 100644 --- a/chat2db-client/.umirc.ts +++ b/chat2db-client/.umirc.ts @@ -97,7 +97,7 @@ export default defineConfig({ define: { __ENV__: process.env.UMI_ENV, __BUILD_TIME__: transitionTimezoneTimestamp(new Date().getTime()), - __APP_VERSION__: yarn_config.app_version || '9.9.9', + __APP_VERSION__: yarn_config.app_version || '0.0.0', __APP_PORT__: yarn_config.app_port, }, esbuildMinifyIIFE: true diff --git a/chat2db-client/package.json b/chat2db-client/package.json index 0fb1844d..f2a9987c 100644 --- a/chat2db-client/package.json +++ b/chat2db-client/package.json @@ -129,7 +129,7 @@ } ], "publisherName": "Chat2DB", - "icon": "src/assets/logo/logo.png" + "icon": "src/assets/logo/logo.ico" }, "linux": { "maintainer": "Chat2DB, huanyueyaoqin@qq.com", diff --git a/chat2db-client/src/assets/logo/logo.ico b/chat2db-client/src/assets/logo/logo.ico index db0f083f..d8941bfc 100644 Binary files a/chat2db-client/src/assets/logo/logo.ico and b/chat2db-client/src/assets/logo/logo.ico differ diff --git a/chat2db-client/src/assets/logo/logo.png b/chat2db-client/src/assets/logo/logo.png index 286b969b..aa82a982 100644 Binary files a/chat2db-client/src/assets/logo/logo.png and b/chat2db-client/src/assets/logo/logo.png differ diff --git a/chat2db-client/src/blocks/SQLExecute/index.tsx b/chat2db-client/src/blocks/SQLExecute/index.tsx index b23547c9..34581d2b 100644 --- a/chat2db-client/src/blocks/SQLExecute/index.tsx +++ b/chat2db-client/src/blocks/SQLExecute/index.tsx @@ -4,7 +4,7 @@ import styles from './index.less'; import classnames from 'classnames'; import DraggableContainer from '@/components/DraggableContainer'; import Console, { IAppendValue } from '@/components/Console'; -import SearchResult from '@/components/SearchResult'; +import SearchResult, { ISearchResultRef } from '@/components/SearchResult'; import { DatabaseTypeCode, ConsoleStatus } from '@/constants'; import { IWorkspaceModelState, IWorkspaceModelType } from '@/models/workspace'; import { IAIState } from '@/models/ai'; @@ -31,7 +31,8 @@ const SQLExecute = memo((props) => { const draggableRef = useRef(); const [appendValue, setAppendValue] = useState(); const { curTableList, curWorkspaceParams } = workspaceModel; - const [sql, setSql] = useState(''); + // const [sql, setSql] = useState(''); + const searchResultRef = useRef(null); // useEffect(() => { // if (!doubleClickTreeNodeData) { @@ -67,7 +68,9 @@ const SQLExecute = memo((props) => { executeParams={{ ...data }} hasAiChat={true} hasAi2Lang={true} - onExecuteSQL={setSql} + onExecuteSQL={(sql) => { + searchResultRef.current?.handleExecuteSQL(sql); + }} onConsoleSave={() => { dispatch({ type: 'workspace/fetchGetSavedConsole', @@ -89,7 +92,7 @@ const SQLExecute = memo((props) => { />
- +
diff --git a/chat2db-client/src/blocks/Setting/About/index.tsx b/chat2db-client/src/blocks/Setting/About/index.tsx index 780356bb..11fea931 100644 --- a/chat2db-client/src/blocks/Setting/About/index.tsx +++ b/chat2db-client/src/blocks/Setting/About/index.tsx @@ -9,7 +9,6 @@ import { DownloadOutlined } from '@ant-design/icons'; import { IUpdateDetectionData } from '../index'; import { IUpdateDetectionRef, UpdatedStatusEnum } from '../UpdateDetection'; import Iconfont from '@/components/Iconfont'; - interface IProps { updateDetectionData: IUpdateDetectionData | null; updateDetectionRef: React.MutableRefObject | null; @@ -35,7 +34,6 @@ export default function AboutUs(props: IProps) { }; const restartApp = () => { - console.log(window.electronApi) window.electronApi?.quitApp(); } @@ -80,6 +78,12 @@ export default function AboutUs(props: IProps) { {i18n('setting.button.restart')} ); + // case UpdatedStatusEnum.UPDATED: + // return ( + // + // ); default: return false; } diff --git a/chat2db-client/src/blocks/Setting/UpdateDetection/index.tsx b/chat2db-client/src/blocks/Setting/UpdateDetection/index.tsx index eb31c04b..9d4be803 100644 --- a/chat2db-client/src/blocks/Setting/UpdateDetection/index.tsx +++ b/chat2db-client/src/blocks/Setting/UpdateDetection/index.tsx @@ -37,10 +37,9 @@ const MAX_TIMES = 200; const UpdateDetection = memo( forwardRef((props: IProps, ref: ForwardedRef) => { - const { openSettingModal, updateDetectionData, setUpdateDetectionData } = props; + const { openSettingModal, setUpdateDetectionData } = props; const [notificationApi, notificationDom] = notification.useNotification(); const timesRef = React.useRef(0); - console.log(updateDetectionData); useEffect(() => { checkUpdate(); diff --git a/chat2db-client/src/components/Console/MonacoEditor/index.tsx b/chat2db-client/src/components/Console/MonacoEditor/index.tsx index 296fc3c6..74cac02d 100644 --- a/chat2db-client/src/components/Console/MonacoEditor/index.tsx +++ b/chat2db-client/src/components/Console/MonacoEditor/index.tsx @@ -2,7 +2,8 @@ import React, { ForwardedRef, forwardRef, useEffect, useImperativeHandle, useRef import cs from 'classnames'; import { useTheme } from '@/hooks'; import * as monaco from 'monaco-editor/esm/vs/editor/editor.api'; -import { DatabaseTypeCode, editorDefaultOptions, EditorThemeType, ThemeType } from '@/constants'; +import { DatabaseTypeCode, EditorThemeType, ThemeType } from '@/constants'; +import { editorDefaultOptions } from './monacoEditorConfig'; import { IQuickInputService } from 'monaco-editor/esm/vs/platform/quickinput/common/quickInput'; import styles from './index.less'; @@ -88,6 +89,7 @@ function MonacoEditor(props: IProps, ref: ForwardedRef) { // 'editorLineNumber.foreground': colorPrimary, // 行号颜色 'editorLineNumber.activeForeground': colorPrimary, // 当前行号颜色 // 'editorCursor.foreground': colorPrimary, // 光标颜色 + 'editorRuler.foreground': colorPrimary + '15', }; monaco.editor.defineTheme(ThemeType.Light, { base: 'vs', diff --git a/chat2db-client/src/constants/monacoEditor.ts b/chat2db-client/src/components/Console/MonacoEditor/monacoEditorConfig.ts similarity index 100% rename from chat2db-client/src/constants/monacoEditor.ts rename to chat2db-client/src/components/Console/MonacoEditor/monacoEditorConfig.ts diff --git a/chat2db-client/src/components/Console/index.tsx b/chat2db-client/src/components/Console/index.tsx index 4f17a148..7cb2f238 100644 --- a/chat2db-client/src/components/Console/index.tsx +++ b/chat2db-client/src/components/Console/index.tsx @@ -30,13 +30,13 @@ enum IPromptType { ChatRobot = 'ChatRobot', } -enum IPromptTypeText { - NL_2_SQL = '自然语言转换', - SQL_EXPLAIN = '解释SQL', - SQL_OPTIMIZER = 'SQL优化', - SQL_2_SQL = 'SQL转换', - ChatRobot = 'Chat机器人', -} +// enum IPromptTypeText { +// NL_2_SQL = '自然语言转换', +// SQL_EXPLAIN = '解释SQL', +// SQL_OPTIMIZER = 'SQL优化', +// SQL_2_SQL = 'SQL转换', +// ChatRobot = 'Chat机器人', +// } export type IAppendValue = { text: any; @@ -65,11 +65,12 @@ interface IProps { consoleId?: number; schemaName?: string; consoleName?: string; + status?: ConsoleStatus; }; tableList?: ITreeNode[]; editorOptions?: IEditorOptions; aiModel: IAIState; - dispatch: Function; + dispatch: any; remainingBtnLoading: boolean; // remainingUse: IAIState['remainingUse']; // onSQLContentChange: (v: string) => void; @@ -108,8 +109,9 @@ function Console(props: IProps, ref: ForwardedRef) { const [isStream, setIsStream] = useState(false); const timerRef = useRef(); const aiFetchIntervalRef = useRef(); - const initializeSuccessful = useRef(false); const closeEventSource = useRef(); + // 上一次同步的console数据 + const lastSyncConsole = useRef(defaultValue); /** * 当前选择的AI类型是Chat2DBAI @@ -133,23 +135,19 @@ function Console(props: IProps, ref: ForwardedRef) { editorRef: editorRef?.current, })); - useEffect(() => {}, []); - useEffect(() => { if (source !== 'workspace') { return; } // 离开时保存 - if (!isActive) { + if (!isActive && timerRef.current) { // 离开时清除定时器 indexedDB.updateData('chat2db', 'workspaceConsoleDDL', { consoleId: executeParams.consoleId!, ddl: editorRef?.current?.getAllContent(), userId: getCookie('CHAT2DB.USER_ID'), }); - if (timerRef.current) { - clearInterval(timerRef.current); - } + clearInterval(timerRef.current); } else { // 活跃时自动保存 indexedDB @@ -158,12 +156,14 @@ function Console(props: IProps, ref: ForwardedRef) { userId: getCookie('CHAT2DB.USER_ID'), }) .then((res: any) => { - const value = res?.[0]?.ddl || ''; - if (value) { + const value = defaultValue || res?.[0]?.ddl || ''; + const oldValue = editorRef?.current?.getAllContent(); + if (value !== oldValue) { editorRef?.current?.setValue(value, 'reset'); - initializeSuccessful.current = true; - timingAutoSave(); } + setTimeout(() => { + timingAutoSave(); + }, 0); }); } return () => { @@ -173,14 +173,30 @@ function Console(props: IProps, ref: ForwardedRef) { }; }, [isActive]); - function timingAutoSave() { + function timingAutoSave(status?: ConsoleStatus) { + if (timerRef.current) { + clearInterval(timerRef.current); + } timerRef.current = setInterval(() => { - indexedDB.updateData('chat2db', 'workspaceConsoleDDL', { - consoleId: executeParams.consoleId!, - ddl: editorRef?.current?.getAllContent(), - userId: getCookie('CHAT2DB.USER_ID'), - }); - }, 3000); + const ddl = editorRef?.current?.getAllContent(); + if (ddl === lastSyncConsole.current) { + return; + } + lastSyncConsole.current = ddl; + if (executeParams.status === ConsoleStatus.RELEASE || status === ConsoleStatus.RELEASE) { + const p: any = { + id: executeParams.consoleId, + ddl, + }; + historyServer.updateSavedConsole(p); + } else { + indexedDB.updateData('chat2db', 'workspaceConsoleDDL', { + consoleId: executeParams.consoleId!, + ddl, + userId: getCookie('CHAT2DB.USER_ID'), + }); + } + }, 5000); } const tableListName = useMemo(() => { @@ -370,7 +386,7 @@ function Console(props: IProps, ref: ForwardedRef) { const saveConsole = (value?: string) => { // const a = editorRef.current?.getAllContent(); - let p: any = { + const p: any = { id: executeParams.consoleId, status: ConsoleStatus.RELEASE, ddl: value, @@ -380,6 +396,7 @@ function Console(props: IProps, ref: ForwardedRef) { indexedDB.deleteData('chat2db', 'workspaceConsoleDDL', executeParams.consoleId!); message.success(i18n('common.tips.saveSuccessfully')); props.onConsoleSave && props.onConsoleSave(); + timingAutoSave(ConsoleStatus.RELEASE); }); }; @@ -447,10 +464,10 @@ function Console(props: IProps, ref: ForwardedRef) { }; const handleSelectTableSyncModel = () => { - const syncModel: SyncModelType | null = Number(localStorage.getItem('syncTableModel')) ?? null; + const syncModel = localStorage.getItem('syncTableModel'); const hasAiAccess = aiModel.hasWhite; if (syncModel !== null) { - setSyncTableModel(syncModel); + setSyncTableModel(Number(syncModel)); return; } diff --git a/chat2db-client/src/components/CreateDatabase/index.less b/chat2db-client/src/components/CreateDatabase/index.less new file mode 100644 index 00000000..09e2e250 --- /dev/null +++ b/chat2db-client/src/components/CreateDatabase/index.less @@ -0,0 +1,39 @@ +@import '../../styles/var.less'; + +.monacoEditorBox { + height: 200px; + border: 1px solid var(--color-border); + border-radius: 4px; + overflow: hidden; +} + +.errorBox { + margin-top: 10px; +} + +.previewBox { + // 伪元素画一条剧中的线条 + position: relative; + display: flex; + margin-bottom: 4px; + .previewText { + background: var(--color-bg-base); + flex-shrink: 0; + margin-right: 10px; + } + .previewLine { + flex: 1; + position: relative; + &::after { + position: absolute; + left: 0; + right: 0px; + top: 50%; + content: ''; + width: 100%; + height: 1px; + background: var(--color-border); + transform: translateY(-50%); + } + } +} diff --git a/chat2db-client/src/components/CreateDatabase/index.tsx b/chat2db-client/src/components/CreateDatabase/index.tsx new file mode 100644 index 00000000..665d5b57 --- /dev/null +++ b/chat2db-client/src/components/CreateDatabase/index.tsx @@ -0,0 +1,177 @@ +import React, { useCallback, forwardRef, ForwardedRef, useImperativeHandle, useMemo, useState, useEffect } from 'react'; +import styles from './index.less'; +import classnames from 'classnames'; +import { Form, Input, Modal } from 'antd'; +import MonacoEditor, { IExportRefFunction } from '@/components/Console/MonacoEditor'; +import { v4 as uuid } from 'uuid'; +import sqlService from '@/service/sql'; +import i18n from '@/i18n'; +import { debounce } from 'lodash'; +import { DatabaseTypeCode } from '@/constants'; + +interface IProps { + className?: string; + curWorkspaceParams: any; + executedCallback?: () => void; +} + +export type CreateType = 'database' | 'schema'; + +export interface ICreateDatabaseRef { + setOpen: (open: boolean, type?: CreateType) => void; +} + +export interface ICreateDatabase { + databaseName?: string; + schemaName?: string; + comment?: string; +} + +// 创建database不支持注释的数据库 +const noCommentDatabase = [DatabaseTypeCode.MYSQL]; + +export default forwardRef((props: IProps, ref: ForwardedRef) => { + const { className, curWorkspaceParams, executedCallback } = props; + const [form] = Form.useForm(); + const monacoEditorUuid = useMemo(() => uuid(), []); + const monacoEditorRef = React.useRef(null); + const [open, setOpen] = useState(false); + const [errorMessage, setErrorMessage] = useState<{ success: boolean; message: string; originalSql: string } | null>( + null, + ); + const [confirmLoading, setConfirmLoading] = useState(false); + const [createType, setCreateType] = useState('database'); + + useEffect(() => { + if (!open) { + setErrorMessage(null); + form.resetFields(); + monacoEditorRef.current?.setValue('', 'cover'); + } + }, [open]); + + const config = useMemo(() => { + return createType === 'database' + ? { + title: `${i18n('common.title.create')} Database`, + api: sqlService.getCreateDatabaseSql, + formName: 'databaseName', + } + : { + title: `${i18n('common.title.create')} Schema`, + api: sqlService.getCreateSchemaSql, + formName: 'schemaName', + }; + }, [createType]); + + const exposedSetOpen = (_open: boolean, type?: CreateType) => { + setOpen(_open); + setCreateType(type || 'database'); + }; + + useImperativeHandle(ref, () => ({ + setOpen: exposedSetOpen, + })); + + const labelCol = { flex: '70px' }; + + const handleFieldsChange = useCallback( + debounce(() => { + const formData: ICreateDatabase = form.getFieldsValue(); + if (!formData.databaseName && createType === 'database') { + return; + } + if (!formData.schemaName && createType === 'schema') { + return; + } + const params = { + databaseType: curWorkspaceParams.databaseType, + dataSourceId: curWorkspaceParams.dataSourceId, + databaseName: curWorkspaceParams.databaseName, + ...formData, + }; + config.api(params).then((res) => { + const { sql } = res; + monacoEditorRef.current?.setValue(sql, 'cover'); + }); + }, 500), + [curWorkspaceParams, createType, monacoEditorRef, config], + ); + + const executeUpdateDataSql = (sql: string) => { + const params: any = { + dataSourceId: curWorkspaceParams.dataSourceId, + databaseType: curWorkspaceParams.databaseType, + databaseName: curWorkspaceParams.databaseName, + sql, + }; + setConfirmLoading(true); + setErrorMessage(null); + return sqlService + .executeDDL(params) + .then((res) => { + if (res.success) { + setOpen(false); + executedCallback?.(); + } else { + setErrorMessage(res); + } + }) + .finally(() => { + setConfirmLoading(false); + }); + }; + + const onOk = () => { + const sql = monacoEditorRef.current?.getAllContent() || ''; + executeUpdateDataSql(sql); + }; + + return ( + { + setOpen(false); + }} + title={config.title} + destroyOnClose + confirmLoading={confirmLoading} + open={open} + onOk={onOk} + > +
+
+ + + + {noCommentDatabase.includes(curWorkspaceParams.databaseType) ? null : ( + + + + )} +
+
+
{i18n('common.title.preview')}
+
+
+
+ +
+ {errorMessage && ( + <> +
+
{i18n('common.title.errorMessage')}
+
+
+
{errorMessage.message}
+ + )} +
+ + ); +}); diff --git a/chat2db-client/src/components/ExecuteSQL/index.less b/chat2db-client/src/components/ExecuteSQL/index.less index dbb6c170..8a513bba 100644 --- a/chat2db-client/src/components/ExecuteSQL/index.less +++ b/chat2db-client/src/components/ExecuteSQL/index.less @@ -85,6 +85,7 @@ padding: 4px 10px; background-color: var(--color-bg-subtle); border-radius: 8px; + .f-doc-en-break(); } } } diff --git a/chat2db-client/src/components/Modal/TriggeredModal/index.less b/chat2db-client/src/components/Modal/TriggeredModal/index.less new file mode 100644 index 00000000..b514cfb0 --- /dev/null +++ b/chat2db-client/src/components/Modal/TriggeredModal/index.less @@ -0,0 +1 @@ +@import '../../styles/var.less'; diff --git a/chat2db-client/src/components/Modal/TriggeredModal/index.tsx b/chat2db-client/src/components/Modal/TriggeredModal/index.tsx new file mode 100644 index 00000000..e41774c3 --- /dev/null +++ b/chat2db-client/src/components/Modal/TriggeredModal/index.tsx @@ -0,0 +1,31 @@ +import React, { memo, Fragment, ReactElement, cloneElement } from 'react'; +import { Modal } from 'antd'; + +interface ITriggeredModal extends React.ComponentProps { + children: ReactElement; + modalContent: React.ReactNode; + onOk?: any; +} + +const TriggeredModal = memo((props) => { + const { children, modalContent, ...orgs } = props; + const [open, setOpen] = React.useState(false); + const onClose = () => { + setOpen(false); + }; + + const onOk = () => { + orgs?.onOk?.(setOpen); + }; + + return ( + + {cloneElement(children, { onClick: () => setOpen(true) })} + + {modalContent} + + + ); +}); + +export default TriggeredModal; diff --git a/chat2db-client/src/components/SearchResult/TableBox/index.tsx b/chat2db-client/src/components/SearchResult/TableBox/index.tsx index 16c136e4..ba7194bc 100644 --- a/chat2db-client/src/components/SearchResult/TableBox/index.tsx +++ b/chat2db-client/src/components/SearchResult/TableBox/index.tsx @@ -234,7 +234,6 @@ export default function TableBox(props: ITableProps) { } }); setTableData(newTableData); - console.log(newTableData); // 添加更新记录 setUpdateData([ diff --git a/chat2db-client/src/components/SearchResult/index.tsx b/chat2db-client/src/components/SearchResult/index.tsx index 692429ba..36fb8246 100644 --- a/chat2db-client/src/components/SearchResult/index.tsx +++ b/chat2db-client/src/components/SearchResult/index.tsx @@ -1,4 +1,13 @@ -import React, { memo, useCallback, useEffect, useMemo, useState, useRef } from 'react'; +import React, { + useCallback, + useEffect, + useMemo, + useState, + useRef, + forwardRef, + ForwardedRef, + useImperativeHandle, +} from 'react'; import classnames from 'classnames'; import Tabs from '@/components/Tabs'; import Iconfont from '@/components/Iconfont'; @@ -27,7 +36,11 @@ const defaultResultConfig: IResultConfig = { hasNextPage: true, }; -export default memo((props) => { +export interface ISearchResultRef { + handleExecuteSQL: (sql: string) => void; +} + +export default forwardRef((props: IProps, ref: ForwardedRef) => { const { className, sql, executeSqlParams } = props; // const [currentTab, setCurrentTab] = useState(); const [resultDataList, setResultDataList] = useState(); @@ -40,6 +53,10 @@ export default memo((props) => { } }, [sql]); + useImperativeHandle(ref, () => ({ + handleExecuteSQL, + })); + /** * 执行SQL * @param sql diff --git a/chat2db-client/src/components/XXXX_FN/index.tsx b/chat2db-client/src/components/XXXX_FN/index.tsx index ff47777b..42d90570 100644 --- a/chat2db-client/src/components/XXXX_FN/index.tsx +++ b/chat2db-client/src/components/XXXX_FN/index.tsx @@ -6,9 +6,7 @@ interface IProps { className?: string; } -export default memo(function XXXX_FN(props) { - const { className } = props - return
- -
-}) +export default memo((props) => { + const { className } = props; + return
demo
; +}); diff --git a/chat2db-client/src/constants/index.ts b/chat2db-client/src/constants/index.ts index 2cae293d..9c4c0b0e 100644 --- a/chat2db-client/src/constants/index.ts +++ b/chat2db-client/src/constants/index.ts @@ -2,7 +2,6 @@ export * from './appConfig'; export * from './common'; export * from './database'; export * from './environment'; -export * from './monacoEditor'; export * from './table'; export * from './theme'; export * from './tree'; diff --git a/chat2db-client/src/i18n/en-us/common.ts b/chat2db-client/src/i18n/en-us/common.ts index fd138738..b7570ab7 100644 --- a/chat2db-client/src/i18n/en-us/common.ts +++ b/chat2db-client/src/i18n/en-us/common.ts @@ -93,5 +93,12 @@ export default { 'common.text.affectedRows': 'Affected rows: {1}', 'common.text.selectFile' : 'Select File', 'common.text.noTableFoundUp' : 'No tables in this database', - 'common.text.noTableFoundDown' : 'Switch databases at the top' + 'common.text.noTableFoundDown': 'Switch databases at the top', + 'common.title.preview': 'Preview', + 'common.title.errorMessage': 'Error message', + 'common.Button.addDatabase': 'Add database', + 'common.Button.addSchema': 'Add schema', + 'common.label.comment': 'Comment', + 'common.label.name': 'Name', + 'common.title.create': 'Create', }; diff --git a/chat2db-client/src/i18n/en-us/setting.ts b/chat2db-client/src/i18n/en-us/setting.ts index ac62d72f..c5497c7d 100644 --- a/chat2db-client/src/i18n/en-us/setting.ts +++ b/chat2db-client/src/i18n/en-us/setting.ts @@ -40,7 +40,7 @@ export default { 'setting.button.restart': 'Restart', 'setting.text.discoverNewVersion': 'Discover new version {1}', 'setting.text.isLatestVersion': 'This is the latest version', - 'setting.button.changeLog': 'ChangeLog', + 'setting.button.changeLog': 'Changelog', 'setting.title.updateRule': 'Update rule', 'setting.text.autoUpdate': 'The new version automatically downloads and installs updates', 'setting.text.manualUpdate': 'Only alert me when a new version is released', diff --git a/chat2db-client/src/i18n/zh-cn/common.ts b/chat2db-client/src/i18n/zh-cn/common.ts index fb519096..4c55168a 100644 --- a/chat2db-client/src/i18n/zh-cn/common.ts +++ b/chat2db-client/src/i18n/zh-cn/common.ts @@ -93,4 +93,11 @@ export default { 'common.text.noTableFoundUp' : '当前库没有查询到表', 'common.text.noTableFoundDown' : '你可以在顶部切换数据库', 'common.text.updateNow' : '立即更新', + 'common.title.preview' : '预览', + 'common.title.errorMessage': '错误信息', + 'common.Button.addDatabase': '添加数据库', + 'common.Button.addSchema': '添加Schema', + 'common.label.comment': '备注', + 'common.label.name': '名称', + 'common.title.create': '创建', }; diff --git a/chat2db-client/src/layouts/index.tsx b/chat2db-client/src/layouts/index.tsx index 98ebb67e..2c0c5295 100644 --- a/chat2db-client/src/layouts/index.tsx +++ b/chat2db-client/src/layouts/index.tsx @@ -6,7 +6,6 @@ import { v4 as uuidv4 } from 'uuid'; import { getAntdThemeConfig, injectThemeVar } from '@/theme'; import { IVersionResponse } from '@/typings'; import miscService from '@/service/misc'; -import configService from '@/service/config'; import antdEnUS from 'antd/locale/en_US'; import antdZhCN from 'antd/locale/zh_CN'; import { useTheme } from '@/hooks'; @@ -34,7 +33,7 @@ declare global { electronApi?: { startServerForSpawn: () => void; quitApp: () => void; - beforeQuitApp: (fn: () => void) => void; + setBaseURL: (baseUrl:string) => void; registerAppMenu: (data:any) => void; }; } @@ -111,10 +110,9 @@ function AppContainer() { window.electronApi?.registerAppMenu({ version: __APP_VERSION__, }) - - window.electronApi?.beforeQuitApp(()=>{ - configService.stopJavaService() - }) + // 把关闭java服务的的方法传给electron + window.electronApi?.setBaseURL?.(window._BaseURL) + // console.log(window.electronApi) } // 初始化indexedDB diff --git a/chat2db-client/src/main/index.js b/chat2db-client/src/main/index.js index 91fa470c..cebfbd40 100644 --- a/chat2db-client/src/main/index.js +++ b/chat2db-client/src/main/index.js @@ -10,6 +10,8 @@ const { loadMainResource } = require('./utils'); let mainWindow = null; +let baseUrl = null; + function createWindow() { mainWindow = new BrowserWindow({ minWidth: 1080, @@ -69,7 +71,18 @@ app.on('window-all-closed', () => { }); app.on('before-quit', () => { - mainWindow.webContents.send('before-quit-app'); + if(baseUrl){ + try { + const request = net.request({ + headers: { + 'Content-Type': 'application/json', + }, + method: 'POST', + url: `${baseUrl}/api/system/stop`, + }); + request.end(); + } catch (error) {} + } }); ipcMain.handle('get-product-name', () => { @@ -86,3 +99,9 @@ ipcMain.on('quit-app', () => { ipcMain.on('register-app-menu', (event, orgs) => { registerAppMenu(mainWindow, orgs); }); + +ipcMain.on('set-base-url',(event,_baseUrl)=>{ + baseUrl = _baseUrl; +}) + + diff --git a/chat2db-client/src/main/preload.js b/chat2db-client/src/main/preload.js index 09413359..5d2a0421 100644 --- a/chat2db-client/src/main/preload.js +++ b/chat2db-client/src/main/preload.js @@ -43,13 +43,10 @@ contextBridge.exposeInMainWorld('electronApi', { quitApp: () => { ipcRenderer.send('quit-app'); }, - beforeQuitApp: (callback)=>{ - ipcRenderer.on('before-quit-app', () => { - callback(); - }); + setBaseURL: (baseUrl) => { + ipcRenderer.send('set-base-url', baseUrl); }, - registerAppMenu: (menuProps)=>{ + registerAppMenu: (menuProps) => { ipcRenderer.send('register-app-menu', menuProps); - } + }, }); - diff --git a/chat2db-client/src/models/workspace.ts b/chat2db-client/src/models/workspace.ts index 9e151f6f..47d19436 100644 --- a/chat2db-client/src/models/workspace.ts +++ b/chat2db-client/src/models/workspace.ts @@ -58,7 +58,7 @@ const WorkspaceModel: IWorkspaceModelType = { state: { databaseAndSchema: undefined, - curWorkspaceParams: getCurrentWorkspaceDatabase(), + curWorkspaceParams: {} as any, doubleClickTreeNodeData: undefined, consoleList: [], openConsoleList: [], diff --git a/chat2db-client/src/pages/demo/index.tsx b/chat2db-client/src/pages/demo/index.tsx index b033dc5e..cb3bfce8 100644 --- a/chat2db-client/src/pages/demo/index.tsx +++ b/chat2db-client/src/pages/demo/index.tsx @@ -1,5 +1,4 @@ import React, { useEffect, useState } from 'react'; -import indexedDB from '@/indexedDB'; export enum CustomerTypeEnum { visitor = 'visitor', @@ -14,31 +13,10 @@ export enum CustomerTypeEnum2 { export type CustomerType1 = CustomerTypeEnum | CustomerTypeEnum2; const App: React.FC = () => { - const [db, setDb] = useState(); - useEffect(() => { - indexedDB.createDB('chat2db', 2).then((db) => { - setDb(db); - }); - }, []); - - const add = () => { - indexedDB.addData(db, 'workspaceConsoleDDL', { - userId: '1', - consoleId: '1', - ddl: 'select * from user', - }); - }; - - const deleteFn = () => { - indexedDB.deleteData(db, 'workspaceConsoleDDL', '1'); - }; return ( -
- - -
+
demo
); }; diff --git a/chat2db-client/src/pages/main/workspace/components/SaveList/index.tsx b/chat2db-client/src/pages/main/workspace/components/SaveList/index.tsx index f220af4b..834bc0bf 100644 --- a/chat2db-client/src/pages/main/workspace/components/SaveList/index.tsx +++ b/chat2db-client/src/pages/main/workspace/components/SaveList/index.tsx @@ -107,7 +107,7 @@ const SaveList = dvaModel((props: any) => { id: data.id, status: ConsoleStatus.DRAFT, }; - historyServer.updateSavedConsole(params).then((res) => { + historyServer.updateSavedConsole(params).then(() => { dispatch({ type: 'workspace/fetchGetSavedConsole', payload: { @@ -115,10 +115,10 @@ const SaveList = dvaModel((props: any) => { status: ConsoleStatus.RELEASE, ...curWorkspaceParams, }, - callback: (res: any) => { + callback: (_res: any) => { dispatch({ type: 'workspace/setConsoleList', - payload: res.data, + payload: _res.data, }); }, }); diff --git a/chat2db-client/src/pages/main/workspace/components/WorkspaceHeader/index.less b/chat2db-client/src/pages/main/workspace/components/WorkspaceHeader/index.less index 56d9b6fb..17071ec8 100644 --- a/chat2db-client/src/pages/main/workspace/components/WorkspaceHeader/index.less +++ b/chat2db-client/src/pages/main/workspace/components/WorkspaceHeader/index.less @@ -119,3 +119,18 @@ } } } + +.dropdownFooter { + display: flex; + align-items: center; + margin: 4px; + padding: 4px 8px; + line-height: 20px; + i { + margin-right: 4px; + } + &:hover { + background-color: var(--color-hover-bg); + cursor: pointer; + } +} diff --git a/chat2db-client/src/pages/main/workspace/components/WorkspaceHeader/index.tsx b/chat2db-client/src/pages/main/workspace/components/WorkspaceHeader/index.tsx index 93e016b6..1ad3d322 100644 --- a/chat2db-client/src/pages/main/workspace/components/WorkspaceHeader/index.tsx +++ b/chat2db-client/src/pages/main/workspace/components/WorkspaceHeader/index.tsx @@ -6,12 +6,14 @@ import Iconfont from '@/components/Iconfont'; import { IConnectionModelType } from '@/models/connection'; import { IWorkspaceModelType } from '@/models/workspace'; import { IMainPageType } from '@/models/mainPage'; -import { Cascader, Spin, Modal, Tag } from 'antd'; -import { databaseMap, TreeNodeType } from '@/constants'; +import { Cascader, Spin, Modal, Tag, Divider } from 'antd'; +import { databaseMap, TreeNodeType, DatabaseTypeCode } from '@/constants'; import { treeConfig } from '../Tree/treeConfig'; import { useUpdateEffect } from '@/hooks/useUpdateEffect'; import styles from './index.less'; import i18n from '@/i18n'; +import CreateDatabase, { ICreateDatabaseRef } from '@/components/CreateDatabase'; +import { getCurrentWorkspaceDatabase } from '@/utils/localStorage'; interface IProps { className?: string; @@ -26,6 +28,14 @@ interface IOption { value: number | string; } +// 不支持创建数据库的数据库类型 +const notSupportCreateDatabaseType = [DatabaseTypeCode.H2]; + +// 不支持创建schema的数据库类型 +const notSupportCreateSchemaType = [DatabaseTypeCode.ORACLE]; + +const localStorageWorkspaceDatabase = getCurrentWorkspaceDatabase(); + const WorkspaceHeader = memo((props) => { const { connectionModel, workspaceModel, mainPageModel, dispatch } = props; const { connectionList, curConnection } = connectionModel; @@ -37,6 +47,18 @@ const WorkspaceHeader = memo((props) => { const [curDBOptions, setCurDBOptions] = useState([]); const [curSchemaOptions, setCurSchemaOptions] = useState([]); const [isRefresh, setIsRefresh] = useState(false); + const [openDBCascaderDropdown, setOpenDBCascaderDropdown] = useState(undefined); + const [openSchemaCascaderDropdown, setOpenSchemaCascaderDropdown] = useState(undefined); + const createDatabaseRef = React.useRef(null); + + useEffect(() => { + if (openDBCascaderDropdown === false) { + setOpenDBCascaderDropdown(undefined); + } + if (openSchemaCascaderDropdown === false) { + setOpenSchemaCascaderDropdown(undefined); + } + }, [openDBCascaderDropdown, openSchemaCascaderDropdown]); useEffect(() => { if (curPage !== 'workspace') { @@ -44,7 +66,14 @@ const WorkspaceHeader = memo((props) => { } // 如果没有curConnection默认选第一个 if (!curConnection?.id && connectionList.length) { - connectionChange([connectionList[0].id], [connectionList[0]]); + if ( + localStorageWorkspaceDatabase.dataSourceId && + connectionList.find((t: any) => Number(t.id) === Number(localStorageWorkspaceDatabase.dataSourceId)) + ) { + connectionChange([localStorageWorkspaceDatabase.dataSourceId]); + return; + } + connectionChange([connectionList[0].id]); return; } // 如果都有的话 @@ -52,7 +81,12 @@ const WorkspaceHeader = memo((props) => { // 如果curConnection不再connectionList里,也是默认选第一个 const flag = connectionList.findIndex((t: any) => t.id === curConnection?.id); if (flag === -1) { - connectionChange([connectionList[0].id], [connectionList[0]]); + if (localStorageWorkspaceDatabase.dataSourceId && + connectionList.find((t: any) => Number(t.id) === Number(localStorageWorkspaceDatabase.dataSourceId))) { + connectionChange([localStorageWorkspaceDatabase.dataSourceId]); + return; + } + connectionChange([connectionList[0].id]); return; } @@ -71,10 +105,6 @@ const WorkspaceHeader = memo((props) => { getDatabaseList(isRefresh); setIsRefresh(false); } - // connectionList转换成可用的ConnectionOptions - // if (!connectionList.length) { - // setNoConnectionModal(true); - // } setConnectionOptions( connectionList?.map((t) => { return { @@ -118,7 +148,7 @@ const WorkspaceHeader = memo((props) => { dataSourceName: curConnection.name, }, }) - .then((res) => { + .then((res: any) => { const dbList = res?.map((t) => { return { @@ -127,14 +157,20 @@ const WorkspaceHeader = memo((props) => { }; }) || []; setCurDBOptions(dbList); - // 如果是切换那么就默认取列表的第一个database, 如果不是切换那么就取缓存的,如果缓存没有还是取列表第一个(这里是兜底,如果原先他并没有database,后来他加了database,如果还是取缓存的空就不对了) - const databaseName = - curWorkspaceParams.dataSourceId !== curConnection?.id - ? dbList[0]?.label - : curWorkspaceParams.databaseName || dbList[0]?.label; - getSchemaList(databaseName, refresh); + let databaseName = ''; + if(dbList.find((t: any) => t.value === localStorageWorkspaceDatabase.databaseName)){ + databaseName = localStorageWorkspaceDatabase.databaseName!; + }else{ + // 如果是切换那么就默认取列表的第一个database, 如果不是切换那么就取缓存的,如果缓存没有还是取列表第一个(这里是兜底,如果原先他并没有database,后来他加了database,如果还是取缓存的空就不对了) + databaseName = + curWorkspaceParams.dataSourceId !== curConnection?.id + ? dbList[0]?.label + : curWorkspaceParams.databaseName || dbList[0]?.label; + } + databaseChange([databaseName], [{ label: databaseName }],refresh); + // getSchemaList(databaseName, refresh); }) - .catch((error) => { + .catch(() => { setCascaderLoading(false); }); } @@ -155,7 +191,7 @@ const WorkspaceHeader = memo((props) => { dataSourceName: curConnection.name, }, }) - .then((res) => { + .then((res: any) => { const schemaList = res?.map((t) => { return { @@ -164,10 +200,17 @@ const WorkspaceHeader = memo((props) => { }; }) || []; setCurSchemaOptions(schemaList); - const schemaName = - curWorkspaceParams.dataSourceId !== curConnection?.id - ? schemaList[0]?.label - : curWorkspaceParams.schemaName || schemaList[0]?.label; + + let schemaName = ''; + if(schemaList.find((t: any) => t.value === localStorageWorkspaceDatabase.schemaName)){ + schemaName = localStorageWorkspaceDatabase.schemaName!; + }else{ + schemaName = + curWorkspaceParams.dataSourceId !== curConnection?.id + ? schemaList[0]?.label + : curWorkspaceParams.schemaName || schemaList[0]?.label; + } + // schemaChange([schemaName], [{ label: schemaName }]); const data: any = { dataSourceId: curConnection.id, dataSourceName: curConnection.alias, @@ -226,17 +269,17 @@ const WorkspaceHeader = memo((props) => { } // 数据库切换 - function databaseChange(valueArr: any, selectedOptions: any) { - if (selectedOptions[0].label !== curWorkspaceParams.databaseName) { - getSchemaList(selectedOptions[0].label); - } + function databaseChange(valueArr: any, selectedOptions: any,refresh) { + // if (selectedOptions[0].label !== curWorkspaceParams.databaseName) { + getSchemaList(selectedOptions[0].label,refresh); + // } } // schema切换 function schemaChange(valueArr: any, selectedOptions: any) { - if (selectedOptions[0].label !== curWorkspaceParams.schemaName) { + // if (selectedOptions[0].label !== curWorkspaceParams.schemaName) { setCurWorkspaceParams({ ...curWorkspaceParams, schemaName: selectedOptions[0].value }); - } + // } } function handleRefresh() { @@ -265,11 +308,34 @@ const WorkspaceHeader = memo((props) => { {!!curDBOptions?.length && } - {!!curDBOptions?.length && ( { + return ( +
+ {menu} + + { + // 不支持创建数据库的数据库类型 + !notSupportCreateDatabaseType.includes(curWorkspaceParams?.databaseType) && ( +
{ + setOpenDBCascaderDropdown(false); + createDatabaseRef.current?.setOpen(true, 'database'); + }} + > + + {i18n('common.Button.addDatabase')} +
+ ) + } +
+ ); + }} onChange={databaseChange} bordered={false} value={[curWorkspaceParams?.databaseName || '']} @@ -286,7 +352,31 @@ const WorkspaceHeader = memo((props) => { options={curSchemaOptions} onChange={schemaChange} bordered={false} + open={openSchemaCascaderDropdown} value={[curWorkspaceParams?.schemaName || '']} + dropdownRender={(menu) => { + return ( +
+ {menu} + + { + // 不支持创建schema的数据库类型 + !notSupportCreateSchemaType.includes(curWorkspaceParams?.databaseType) && ( +
{ + setOpenSchemaCascaderDropdown(false); + createDatabaseRef.current?.setOpen(true, 'schema'); + }} + > + + {i18n('common.Button.addSchema')} +
+ ) + } +
+ ); + }} >
{curWorkspaceParams.schemaName}
@@ -330,6 +420,11 @@ const WorkspaceHeader = memo((props) => {
+ ); }); diff --git a/chat2db-client/src/pages/main/workspace/components/WorkspaceRight/index.tsx b/chat2db-client/src/pages/main/workspace/components/WorkspaceRight/index.tsx index 617aaa05..8f4fdceb 100644 --- a/chat2db-client/src/pages/main/workspace/components/WorkspaceRight/index.tsx +++ b/chat2db-client/src/pages/main/workspace/components/WorkspaceRight/index.tsx @@ -64,7 +64,6 @@ const WorkspaceRight = memo((props: IProps) => { uniqueData: t, }; }); - console.log(workspaceTabList, newTabList); if (workspaceTabList.length) { const newWorkspaceTabList = lodash.cloneDeep(workspaceTabList); const newAddList: any = []; @@ -312,11 +311,23 @@ const WorkspaceRight = memo((props: IProps) => { } if (doubleClickTreeNodeData.treeNodeType === TreeNodeType.TABLE) { + const { extraParams } = doubleClickTreeNodeData; const { tableName } = extraParams || {}; const sql = `SELECT * FROM ${compatibleDataBaseName(tableName!, curWorkspaceParams.databaseType)};\n`; const title = tableName!; const id = uuidV4(); + let flag = false; + workspaceTabList.forEach((t) => { + if (t.uniqueData?.sql === sql) { + setActiveConsoleId(t.id); + flag = true + return; + } + }) + if(flag){ + return + } setWorkspaceTabList([ ...(workspaceTabList || []), { @@ -355,6 +366,9 @@ const WorkspaceRight = memo((props: IProps) => { // 更新表名提示 useUpdateEffect(() => { const { dataSourceId, databaseName, schemaName, databaseType } = curWorkspaceParams; + if (dataSourceId === null || dataSourceId === undefined) { + return; + } sqlService .getAllTableList({ dataSourceId, @@ -571,6 +585,7 @@ const WorkspaceRight = memo((props: IProps) => { schemaName: curWorkspaceParams?.schemaName, consoleId: t.id as number, consoleName: uniqueData.name, + status: uniqueData.status, }} /> )} diff --git a/chat2db-client/src/service/config.ts b/chat2db-client/src/service/config.ts index 2ddc6b68..d78c99d2 100644 --- a/chat2db-client/src/service/config.ts +++ b/chat2db-client/src/service/config.ts @@ -78,11 +78,6 @@ const setAppUpdateType = createRequest('/api/sy method: 'post', }); -// 退出electron时关闭后端服务 -const stopJavaService = createRequest('/api/system/stop', { - method: 'post', -}); - export default { getSystemConfig, setSystemConfig, @@ -92,6 +87,5 @@ export default { getLatestVersion, isUpdateSuccess, updateDesktopVersion, - setAppUpdateType, - stopJavaService + setAppUpdateType }; diff --git a/chat2db-client/src/service/outside.ts b/chat2db-client/src/service/outside.ts index b22973f4..b5d41465 100644 --- a/chat2db-client/src/service/outside.ts +++ b/chat2db-client/src/service/outside.ts @@ -1,10 +1,4 @@ import createRequest from './base'; -import { IVersionResponse } from '@/typings'; - -const checkVersion = createRequest('/api/client/version/check/v2', { - errorLevel: false, - outside: true, -}); const dynamicUrl = createRequest('', { dynamicUrl: true, @@ -12,5 +6,4 @@ const dynamicUrl = createRequest('', { export default { dynamicUrl, - checkVersion, }; diff --git a/chat2db-client/src/service/sql.ts b/chat2db-client/src/service/sql.ts index 7a930ef0..8754246f 100644 --- a/chat2db-client/src/service/sql.ts +++ b/chat2db-client/src/service/sql.ts @@ -288,7 +288,22 @@ const executeUpdateDataSql = createRequest('/api/rdb/dml/get_update_sql', { method: 'post' }); +/** 创建数据库 */ +const getCreateDatabaseSql = createRequest<{ + dataSourceId: number; + databaseName: string; +}, { sql: string }>('/api/rdb/database/create_database_sql', { method: 'post' }); + +/** 创建schema */ +const getCreateSchemaSql = createRequest<{ + dataSourceId: number; + databaseName?: string; + schemaName?: string; +}, {sql:string}>('/api/rdb/schema/create_schema_sql', { method: 'post' }); + export default { + getCreateSchemaSql, + getCreateDatabaseSql, executeUpdateDataSql, executeDDL, getExecuteUpdateSql, diff --git a/chat2db-client/src/styles/var.less b/chat2db-client/src/styles/var.less index 3efe4d69..db46dd54 100644 --- a/chat2db-client/src/styles/var.less +++ b/chat2db-client/src/styles/var.less @@ -51,6 +51,11 @@ } } +// 文档英文强制换行 +.f-doc-en-break { + word-break: break-all; +} + @keyframes loading-animation { 0% { transform: rotate(0deg); diff --git a/chat2db-client/src/utils/index.ts b/chat2db-client/src/utils/index.ts index e9d3ab9b..9ae085c2 100644 --- a/chat2db-client/src/utils/index.ts +++ b/chat2db-client/src/utils/index.ts @@ -244,9 +244,9 @@ export function formatSql(sql: string, dbType: DatabaseTypeCode) { // 桌面端用hash模式,web端用history模式,路由跳转 export function navigate(path: string) { if (__ENV__ === 'desktop') { - window.location.href = `#${path}`; + window.location.replace(`#${path}`) } else { - window.location.href = path; + window.location.replace(path) } } diff --git a/chat2db-server/chat2db-plugins/chat2db-h2/src/main/java/ai/chat2db/plugin/h2/H2DBManage.java b/chat2db-server/chat2db-plugins/chat2db-h2/src/main/java/ai/chat2db/plugin/h2/H2DBManage.java index 0e02f8dd..c22b795a 100644 --- a/chat2db-server/chat2db-plugins/chat2db-h2/src/main/java/ai/chat2db/plugin/h2/H2DBManage.java +++ b/chat2db-server/chat2db-plugins/chat2db-h2/src/main/java/ai/chat2db/plugin/h2/H2DBManage.java @@ -1,13 +1,32 @@ package ai.chat2db.plugin.h2; import java.sql.Connection; +import java.sql.SQLException; import ai.chat2db.spi.DBManage; import ai.chat2db.spi.jdbc.DefaultDBManage; +import ai.chat2db.spi.sql.Chat2DBContext; +import ai.chat2db.spi.sql.ConnectInfo; import ai.chat2db.spi.sql.SQLExecutor; +import org.apache.commons.lang3.ObjectUtils; +import org.apache.commons.lang3.StringUtils; public class H2DBManage extends DefaultDBManage implements DBManage { + @Override + public void connectDatabase(Connection connection, String database) { + ConnectInfo connectInfo = Chat2DBContext.getConnectInfo(); + if (ObjectUtils.anyNull(connectInfo) || StringUtils.isEmpty(connectInfo.getSchemaName())) { + return; + } + String schemaName = connectInfo.getSchemaName(); + try { + SQLExecutor.getInstance().execute(connection, "SET SCHEMA \"" + schemaName + "\""); + } catch (SQLException e) { + + } + } + @Override public void dropTable(Connection connection, String databaseName, String schemaName, String tableName) { diff --git a/chat2db-server/chat2db-plugins/chat2db-mysql/src/main/java/ai/chat2db/plugin/mysql/builder/MysqlSqlBuilder.java b/chat2db-server/chat2db-plugins/chat2db-mysql/src/main/java/ai/chat2db/plugin/mysql/builder/MysqlSqlBuilder.java index bc1e2d51..c2cc32c0 100644 --- a/chat2db-server/chat2db-plugins/chat2db-mysql/src/main/java/ai/chat2db/plugin/mysql/builder/MysqlSqlBuilder.java +++ b/chat2db-server/chat2db-plugins/chat2db-mysql/src/main/java/ai/chat2db/plugin/mysql/builder/MysqlSqlBuilder.java @@ -129,7 +129,7 @@ public class MysqlSqlBuilder extends DefaultSqlBuilder implements SqlBuilder { @Override public String buildCreateDatabaseSql(Database database) { StringBuilder sqlBuilder = new StringBuilder(); - sqlBuilder.append("CREATE DATABASE "+database.getName()); + sqlBuilder.append("CREATE DATABASE `"+database.getName()+"`"); if (StringUtils.isNotBlank(database.getCharset())) { sqlBuilder.append(" DEFAULT CHARACTER SET=").append(database.getCharset()); } diff --git a/chat2db-server/chat2db-plugins/chat2db-postgresql/src/main/java/ai/chat2db/plugin/postgresql/PostgreSQLDBManage.java b/chat2db-server/chat2db-plugins/chat2db-postgresql/src/main/java/ai/chat2db/plugin/postgresql/PostgreSQLDBManage.java index ff3ffdcb..c2f4b91b 100644 --- a/chat2db-server/chat2db-plugins/chat2db-postgresql/src/main/java/ai/chat2db/plugin/postgresql/PostgreSQLDBManage.java +++ b/chat2db-server/chat2db-plugins/chat2db-postgresql/src/main/java/ai/chat2db/plugin/postgresql/PostgreSQLDBManage.java @@ -4,17 +4,22 @@ import java.sql.Connection; import ai.chat2db.spi.DBManage; import ai.chat2db.spi.jdbc.DefaultDBManage; +import ai.chat2db.spi.sql.Chat2DBContext; import ai.chat2db.spi.sql.ConnectInfo; import ai.chat2db.spi.sql.SQLExecutor; +import org.apache.commons.lang3.StringUtils; public class PostgreSQLDBManage extends DefaultDBManage implements DBManage { @Override public void connectDatabase(Connection connection, String database) { - //try { - // SQLExecutor.getInstance().execute(connection,"SELECT pg_database_size('"+database+"');"); - //} catch (SQLException e) { - // throw new RuntimeException(e); - //} + try { + ConnectInfo connectInfo = Chat2DBContext.getConnectInfo(); + if (!StringUtils.isEmpty(connectInfo.getSchemaName())) { + SQLExecutor.getInstance().execute(connection, "SET search_path TO \"" + connectInfo.getSchemaName() + "\""); + } + } catch (Exception e) { + + } } @Override @@ -26,7 +31,7 @@ public class PostgreSQLDBManage extends DefaultDBManage implements DBManage { } connectInfo.setUrl(url); - return super.getConnection(connectInfo); + return super.getConnection(connectInfo); } @@ -53,8 +58,8 @@ public class PostgreSQLDBManage extends DefaultDBManage implements DBManage { @Override public void dropTable(Connection connection, String databaseName, String schemaName, String tableName) { - String sql = "DROP TABLE "+ tableName; - SQLExecutor.getInstance().executeSql(connection,sql, resultSet -> null); + String sql = "DROP TABLE " + tableName; + SQLExecutor.getInstance().executeSql(connection, sql, resultSet -> null); } } diff --git a/chat2db-server/chat2db-plugins/chat2db-sqlserver/src/main/java/ai/chat2db/plugin/sqlserver/SqlServerDBManage.java b/chat2db-server/chat2db-plugins/chat2db-sqlserver/src/main/java/ai/chat2db/plugin/sqlserver/SqlServerDBManage.java index 2b1d7325..ded0abf1 100644 --- a/chat2db-server/chat2db-plugins/chat2db-sqlserver/src/main/java/ai/chat2db/plugin/sqlserver/SqlServerDBManage.java +++ b/chat2db-server/chat2db-plugins/chat2db-sqlserver/src/main/java/ai/chat2db/plugin/sqlserver/SqlServerDBManage.java @@ -11,7 +11,7 @@ public class SqlServerDBManage extends DefaultDBManage implements DBManage { @Override public void connectDatabase(Connection connection, String database) { try { - SQLExecutor.getInstance().execute(connection,"use [" + database + "];"); + SQLExecutor.getInstance().execute(connection, "use [" + database + "];"); } catch (SQLException e) { throw new RuntimeException(e); } diff --git a/chat2db-server/chat2db-plugins/chat2db-sqlserver/src/main/java/ai/chat2db/plugin/sqlserver/builder/SqlServerSqlBuilder.java b/chat2db-server/chat2db-plugins/chat2db-sqlserver/src/main/java/ai/chat2db/plugin/sqlserver/builder/SqlServerSqlBuilder.java index ccf671c4..54978d45 100644 --- a/chat2db-server/chat2db-plugins/chat2db-sqlserver/src/main/java/ai/chat2db/plugin/sqlserver/builder/SqlServerSqlBuilder.java +++ b/chat2db-server/chat2db-plugins/chat2db-sqlserver/src/main/java/ai/chat2db/plugin/sqlserver/builder/SqlServerSqlBuilder.java @@ -153,7 +153,7 @@ public class SqlServerSqlBuilder extends DefaultSqlBuilder implements SqlBuilder sqlBuilder.append("\ngo\n"); if (StringUtils.isNotBlank(database.getComment())) { sqlBuilder.append("exec [" + database.getName() + "].sys. sp_addextendedproperty 'MS_Description','") - .append(database.getComment()).append("'").append("'\ngo\n"); + .append(database.getComment()).append("'").append("\ngo\n"); } return sqlBuilder.toString(); } @@ -166,7 +166,7 @@ public class SqlServerSqlBuilder extends DefaultSqlBuilder implements SqlBuilder if (StringUtils.isNotBlank(schema.getComment())) { sqlBuilder.append("exec sp_addextendedproperty 'MS_Description','") .append(schema.getComment()).append("'").append(",'SCHEMA'") - .append(",'").append(schema.getName()).append("'").append("'\ngo\n"); + .append(",'").append(schema.getName()).append("'").append("\ngo\n"); } return sqlBuilder.toString(); } diff --git a/chat2db-server/chat2db-server-start/src/main/java/ai/chat2db/server/start/config/config/Chat2dbWebMvcConfigurer.java b/chat2db-server/chat2db-server-start/src/main/java/ai/chat2db/server/start/config/config/Chat2dbWebMvcConfigurer.java index 2f3a68a4..08ad4a1a 100644 --- a/chat2db-server/chat2db-server-start/src/main/java/ai/chat2db/server/start/config/config/Chat2dbWebMvcConfigurer.java +++ b/chat2db-server/chat2db-server-start/src/main/java/ai/chat2db/server/start/config/config/Chat2dbWebMvcConfigurer.java @@ -56,7 +56,7 @@ public class Chat2dbWebMvcConfigurer implements WebMvcConfigurer { * 全局放行的url */ private static final String[] FRONT_PERMIT_ALL = new String[] {"/favicon.ico", "/error", "/static/**", - "/api/system", "/login"}; + "/api/system", "/login", "/api/system/get_latest_version"}; @Resource private UserService userService; diff --git a/chat2db-server/chat2db-server-web/chat2db-server-web-api/src/main/java/ai/chat2db/server/web/api/controller/rdb/RdbDmlController.java b/chat2db-server/chat2db-server-web/chat2db-server-web-api/src/main/java/ai/chat2db/server/web/api/controller/rdb/RdbDmlController.java index 626663fe..1df806b2 100644 --- a/chat2db-server/chat2db-server-web/chat2db-server-web-api/src/main/java/ai/chat2db/server/web/api/controller/rdb/RdbDmlController.java +++ b/chat2db-server/chat2db-server-web/chat2db-server-web-api/src/main/java/ai/chat2db/server/web/api/controller/rdb/RdbDmlController.java @@ -93,7 +93,7 @@ public class RdbDmlController { try { boolean flag = true; ExecuteResultVO executeResult = null; - connection.setAutoCommit(false); + //connection.setAutoCommit(false); ListResult resultDTOListResult = dlTemplateService.execute(param); List resultVOS = rdbWebConverter.dto2vo(resultDTOListResult.getData()); if (!CollectionUtils.isEmpty(resultVOS)) { @@ -107,7 +107,7 @@ public class RdbDmlController { } } if (flag) { - connection.commit(); + //connection.commit(); return DataResult.of(resultVOS.get(0)); }else { connection.rollback(); diff --git a/chat2db-server/chat2db-server-web/chat2db-server-web-api/src/main/java/ai/chat2db/server/web/api/controller/rdb/doc/DatabaseExportService.java b/chat2db-server/chat2db-server-web/chat2db-server-web-api/src/main/java/ai/chat2db/server/web/api/controller/rdb/doc/DatabaseExportService.java index a33a4d65..4e5bc409 100644 --- a/chat2db-server/chat2db-server-web/chat2db-server-web-api/src/main/java/ai/chat2db/server/web/api/controller/rdb/doc/DatabaseExportService.java +++ b/chat2db-server/chat2db-server-web/chat2db-server-web-api/src/main/java/ai/chat2db/server/web/api/controller/rdb/doc/DatabaseExportService.java @@ -108,7 +108,7 @@ public class DatabaseExportService { try { export(outputStream, exportOptions); } catch (Exception e) { - throw new RuntimeException("导出失败!请联系开发者,邮箱:963565242@qq.com" + e); + throw new RuntimeException("导出失败!请联系开发者" + e); } init(); }