mirror of
https://github.com/CodePhiliaX/Chat2DB.git
synced 2025-07-31 03:32:43 +08:00
Merge remote-tracking branch 'origin/dev' into dev
This commit is contained in:
4
.github/workflows/release.yml
vendored
4
.github/workflows/release.yml
vendored
@ -255,7 +255,9 @@ jobs:
|
|||||||
cp chat2db-client/versions/${{ steps.chat2db_version.outputs.substring }}/static/chat2db-server-start.jar ./oss_temp_file
|
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/release/*.dmg ./oss_temp_file
|
||||||
cp -r chat2db-client/versions/${{ steps.chat2db_version.outputs.substring }}/dist ./oss_temp_file/dist
|
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
|
cp -r chat2db-server-start.zip ../../../../oss_temp_file
|
||||||
|
|
||||||
# 准备要需要的数据 MacOS arm64
|
# 准备要需要的数据 MacOS arm64
|
||||||
|
25
CHANGELOG.md
25
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
|
# 3.0.4
|
||||||
`2023-10-20`
|
`2023-10-20`
|
||||||
|
|
||||||
|
@ -97,7 +97,7 @@ export default defineConfig({
|
|||||||
define: {
|
define: {
|
||||||
__ENV__: process.env.UMI_ENV,
|
__ENV__: process.env.UMI_ENV,
|
||||||
__BUILD_TIME__: transitionTimezoneTimestamp(new Date().getTime()),
|
__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,
|
__APP_PORT__: yarn_config.app_port,
|
||||||
},
|
},
|
||||||
esbuildMinifyIIFE: true
|
esbuildMinifyIIFE: true
|
||||||
|
@ -129,7 +129,7 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"publisherName": "Chat2DB",
|
"publisherName": "Chat2DB",
|
||||||
"icon": "src/assets/logo/logo.png"
|
"icon": "src/assets/logo/logo.ico"
|
||||||
},
|
},
|
||||||
"linux": {
|
"linux": {
|
||||||
"maintainer": "Chat2DB, huanyueyaoqin@qq.com",
|
"maintainer": "Chat2DB, huanyueyaoqin@qq.com",
|
||||||
|
Binary file not shown.
Before Width: | Height: | Size: 4.3 KiB After Width: | Height: | Size: 27 KiB |
Binary file not shown.
Before Width: | Height: | Size: 372 KiB After Width: | Height: | Size: 17 KiB |
@ -4,7 +4,7 @@ import styles from './index.less';
|
|||||||
import classnames from 'classnames';
|
import classnames from 'classnames';
|
||||||
import DraggableContainer from '@/components/DraggableContainer';
|
import DraggableContainer from '@/components/DraggableContainer';
|
||||||
import Console, { IAppendValue } from '@/components/Console';
|
import Console, { IAppendValue } from '@/components/Console';
|
||||||
import SearchResult from '@/components/SearchResult';
|
import SearchResult, { ISearchResultRef } from '@/components/SearchResult';
|
||||||
import { DatabaseTypeCode, ConsoleStatus } from '@/constants';
|
import { DatabaseTypeCode, ConsoleStatus } from '@/constants';
|
||||||
import { IWorkspaceModelState, IWorkspaceModelType } from '@/models/workspace';
|
import { IWorkspaceModelState, IWorkspaceModelType } from '@/models/workspace';
|
||||||
import { IAIState } from '@/models/ai';
|
import { IAIState } from '@/models/ai';
|
||||||
@ -31,7 +31,8 @@ const SQLExecute = memo<IProps>((props) => {
|
|||||||
const draggableRef = useRef<any>();
|
const draggableRef = useRef<any>();
|
||||||
const [appendValue, setAppendValue] = useState<IAppendValue>();
|
const [appendValue, setAppendValue] = useState<IAppendValue>();
|
||||||
const { curTableList, curWorkspaceParams } = workspaceModel;
|
const { curTableList, curWorkspaceParams } = workspaceModel;
|
||||||
const [sql, setSql] = useState<string>('');
|
// const [sql, setSql] = useState<string>('');
|
||||||
|
const searchResultRef = useRef<ISearchResultRef>(null);
|
||||||
|
|
||||||
// useEffect(() => {
|
// useEffect(() => {
|
||||||
// if (!doubleClickTreeNodeData) {
|
// if (!doubleClickTreeNodeData) {
|
||||||
@ -67,7 +68,9 @@ const SQLExecute = memo<IProps>((props) => {
|
|||||||
executeParams={{ ...data }}
|
executeParams={{ ...data }}
|
||||||
hasAiChat={true}
|
hasAiChat={true}
|
||||||
hasAi2Lang={true}
|
hasAi2Lang={true}
|
||||||
onExecuteSQL={setSql}
|
onExecuteSQL={(sql) => {
|
||||||
|
searchResultRef.current?.handleExecuteSQL(sql);
|
||||||
|
}}
|
||||||
onConsoleSave={() => {
|
onConsoleSave={() => {
|
||||||
dispatch({
|
dispatch({
|
||||||
type: 'workspace/fetchGetSavedConsole',
|
type: 'workspace/fetchGetSavedConsole',
|
||||||
@ -89,7 +92,7 @@ const SQLExecute = memo<IProps>((props) => {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className={styles.boxRightResult}>
|
<div className={styles.boxRightResult}>
|
||||||
<SearchResult executeSqlParams={data} sql={sql} />
|
<SearchResult ref={searchResultRef} executeSqlParams={data} />
|
||||||
</div>
|
</div>
|
||||||
</DraggableContainer>
|
</DraggableContainer>
|
||||||
</div>
|
</div>
|
||||||
|
@ -9,7 +9,6 @@ import { DownloadOutlined } from '@ant-design/icons';
|
|||||||
import { IUpdateDetectionData } from '../index';
|
import { IUpdateDetectionData } from '../index';
|
||||||
import { IUpdateDetectionRef, UpdatedStatusEnum } from '../UpdateDetection';
|
import { IUpdateDetectionRef, UpdatedStatusEnum } from '../UpdateDetection';
|
||||||
import Iconfont from '@/components/Iconfont';
|
import Iconfont from '@/components/Iconfont';
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
updateDetectionData: IUpdateDetectionData | null;
|
updateDetectionData: IUpdateDetectionData | null;
|
||||||
updateDetectionRef: React.MutableRefObject<IUpdateDetectionRef> | null;
|
updateDetectionRef: React.MutableRefObject<IUpdateDetectionRef> | null;
|
||||||
@ -35,7 +34,6 @@ export default function AboutUs(props: IProps) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const restartApp = () => {
|
const restartApp = () => {
|
||||||
console.log(window.electronApi)
|
|
||||||
window.electronApi?.quitApp();
|
window.electronApi?.quitApp();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -80,6 +78,12 @@ export default function AboutUs(props: IProps) {
|
|||||||
{i18n('setting.button.restart')}
|
{i18n('setting.button.restart')}
|
||||||
</Button>
|
</Button>
|
||||||
);
|
);
|
||||||
|
// case UpdatedStatusEnum.UPDATED:
|
||||||
|
// return (
|
||||||
|
// <Button icon={<RedoOutlined />} type="primary">
|
||||||
|
// {i18n('setting.button.restart')}
|
||||||
|
// </Button>
|
||||||
|
// );
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -37,10 +37,9 @@ const MAX_TIMES = 200;
|
|||||||
|
|
||||||
const UpdateDetection = memo(
|
const UpdateDetection = memo(
|
||||||
forwardRef((props: IProps, ref: ForwardedRef<IUpdateDetectionRef>) => {
|
forwardRef((props: IProps, ref: ForwardedRef<IUpdateDetectionRef>) => {
|
||||||
const { openSettingModal, updateDetectionData, setUpdateDetectionData } = props;
|
const { openSettingModal, setUpdateDetectionData } = props;
|
||||||
const [notificationApi, notificationDom] = notification.useNotification();
|
const [notificationApi, notificationDom] = notification.useNotification();
|
||||||
const timesRef = React.useRef(0);
|
const timesRef = React.useRef(0);
|
||||||
console.log(updateDetectionData);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
checkUpdate();
|
checkUpdate();
|
||||||
|
@ -2,7 +2,8 @@ import React, { ForwardedRef, forwardRef, useEffect, useImperativeHandle, useRef
|
|||||||
import cs from 'classnames';
|
import cs from 'classnames';
|
||||||
import { useTheme } from '@/hooks';
|
import { useTheme } from '@/hooks';
|
||||||
import * as monaco from 'monaco-editor/esm/vs/editor/editor.api';
|
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 { IQuickInputService } from 'monaco-editor/esm/vs/platform/quickinput/common/quickInput';
|
||||||
|
|
||||||
import styles from './index.less';
|
import styles from './index.less';
|
||||||
@ -88,6 +89,7 @@ function MonacoEditor(props: IProps, ref: ForwardedRef<IExportRefFunction>) {
|
|||||||
// 'editorLineNumber.foreground': colorPrimary, // 行号颜色
|
// 'editorLineNumber.foreground': colorPrimary, // 行号颜色
|
||||||
'editorLineNumber.activeForeground': colorPrimary, // 当前行号颜色
|
'editorLineNumber.activeForeground': colorPrimary, // 当前行号颜色
|
||||||
// 'editorCursor.foreground': colorPrimary, // 光标颜色
|
// 'editorCursor.foreground': colorPrimary, // 光标颜色
|
||||||
|
'editorRuler.foreground': colorPrimary + '15',
|
||||||
};
|
};
|
||||||
monaco.editor.defineTheme(ThemeType.Light, {
|
monaco.editor.defineTheme(ThemeType.Light, {
|
||||||
base: 'vs',
|
base: 'vs',
|
||||||
|
@ -30,13 +30,13 @@ enum IPromptType {
|
|||||||
ChatRobot = 'ChatRobot',
|
ChatRobot = 'ChatRobot',
|
||||||
}
|
}
|
||||||
|
|
||||||
enum IPromptTypeText {
|
// enum IPromptTypeText {
|
||||||
NL_2_SQL = '自然语言转换',
|
// NL_2_SQL = '自然语言转换',
|
||||||
SQL_EXPLAIN = '解释SQL',
|
// SQL_EXPLAIN = '解释SQL',
|
||||||
SQL_OPTIMIZER = 'SQL优化',
|
// SQL_OPTIMIZER = 'SQL优化',
|
||||||
SQL_2_SQL = 'SQL转换',
|
// SQL_2_SQL = 'SQL转换',
|
||||||
ChatRobot = 'Chat机器人',
|
// ChatRobot = 'Chat机器人',
|
||||||
}
|
// }
|
||||||
|
|
||||||
export type IAppendValue = {
|
export type IAppendValue = {
|
||||||
text: any;
|
text: any;
|
||||||
@ -65,11 +65,12 @@ interface IProps {
|
|||||||
consoleId?: number;
|
consoleId?: number;
|
||||||
schemaName?: string;
|
schemaName?: string;
|
||||||
consoleName?: string;
|
consoleName?: string;
|
||||||
|
status?: ConsoleStatus;
|
||||||
};
|
};
|
||||||
tableList?: ITreeNode[];
|
tableList?: ITreeNode[];
|
||||||
editorOptions?: IEditorOptions;
|
editorOptions?: IEditorOptions;
|
||||||
aiModel: IAIState;
|
aiModel: IAIState;
|
||||||
dispatch: Function;
|
dispatch: any;
|
||||||
remainingBtnLoading: boolean;
|
remainingBtnLoading: boolean;
|
||||||
// remainingUse: IAIState['remainingUse'];
|
// remainingUse: IAIState['remainingUse'];
|
||||||
// onSQLContentChange: (v: string) => void;
|
// onSQLContentChange: (v: string) => void;
|
||||||
@ -108,8 +109,9 @@ function Console(props: IProps, ref: ForwardedRef<IConsoleRef>) {
|
|||||||
const [isStream, setIsStream] = useState(false);
|
const [isStream, setIsStream] = useState(false);
|
||||||
const timerRef = useRef<any>();
|
const timerRef = useRef<any>();
|
||||||
const aiFetchIntervalRef = useRef<any>();
|
const aiFetchIntervalRef = useRef<any>();
|
||||||
const initializeSuccessful = useRef(false);
|
|
||||||
const closeEventSource = useRef<any>();
|
const closeEventSource = useRef<any>();
|
||||||
|
// 上一次同步的console数据
|
||||||
|
const lastSyncConsole = useRef<any>(defaultValue);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 当前选择的AI类型是Chat2DBAI
|
* 当前选择的AI类型是Chat2DBAI
|
||||||
@ -133,23 +135,19 @@ function Console(props: IProps, ref: ForwardedRef<IConsoleRef>) {
|
|||||||
editorRef: editorRef?.current,
|
editorRef: editorRef?.current,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
useEffect(() => {}, []);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (source !== 'workspace') {
|
if (source !== 'workspace') {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// 离开时保存
|
// 离开时保存
|
||||||
if (!isActive) {
|
if (!isActive && timerRef.current) {
|
||||||
// 离开时清除定时器
|
// 离开时清除定时器
|
||||||
indexedDB.updateData('chat2db', 'workspaceConsoleDDL', {
|
indexedDB.updateData('chat2db', 'workspaceConsoleDDL', {
|
||||||
consoleId: executeParams.consoleId!,
|
consoleId: executeParams.consoleId!,
|
||||||
ddl: editorRef?.current?.getAllContent(),
|
ddl: editorRef?.current?.getAllContent(),
|
||||||
userId: getCookie('CHAT2DB.USER_ID'),
|
userId: getCookie('CHAT2DB.USER_ID'),
|
||||||
});
|
});
|
||||||
if (timerRef.current) {
|
clearInterval(timerRef.current);
|
||||||
clearInterval(timerRef.current);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// 活跃时自动保存
|
// 活跃时自动保存
|
||||||
indexedDB
|
indexedDB
|
||||||
@ -158,12 +156,14 @@ function Console(props: IProps, ref: ForwardedRef<IConsoleRef>) {
|
|||||||
userId: getCookie('CHAT2DB.USER_ID'),
|
userId: getCookie('CHAT2DB.USER_ID'),
|
||||||
})
|
})
|
||||||
.then((res: any) => {
|
.then((res: any) => {
|
||||||
const value = res?.[0]?.ddl || '';
|
const value = defaultValue || res?.[0]?.ddl || '';
|
||||||
if (value) {
|
const oldValue = editorRef?.current?.getAllContent();
|
||||||
|
if (value !== oldValue) {
|
||||||
editorRef?.current?.setValue(value, 'reset');
|
editorRef?.current?.setValue(value, 'reset');
|
||||||
initializeSuccessful.current = true;
|
|
||||||
timingAutoSave();
|
|
||||||
}
|
}
|
||||||
|
setTimeout(() => {
|
||||||
|
timingAutoSave();
|
||||||
|
}, 0);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return () => {
|
return () => {
|
||||||
@ -173,14 +173,30 @@ function Console(props: IProps, ref: ForwardedRef<IConsoleRef>) {
|
|||||||
};
|
};
|
||||||
}, [isActive]);
|
}, [isActive]);
|
||||||
|
|
||||||
function timingAutoSave() {
|
function timingAutoSave(status?: ConsoleStatus) {
|
||||||
|
if (timerRef.current) {
|
||||||
|
clearInterval(timerRef.current);
|
||||||
|
}
|
||||||
timerRef.current = setInterval(() => {
|
timerRef.current = setInterval(() => {
|
||||||
indexedDB.updateData('chat2db', 'workspaceConsoleDDL', {
|
const ddl = editorRef?.current?.getAllContent();
|
||||||
consoleId: executeParams.consoleId!,
|
if (ddl === lastSyncConsole.current) {
|
||||||
ddl: editorRef?.current?.getAllContent(),
|
return;
|
||||||
userId: getCookie('CHAT2DB.USER_ID'),
|
}
|
||||||
});
|
lastSyncConsole.current = ddl;
|
||||||
}, 3000);
|
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(() => {
|
const tableListName = useMemo(() => {
|
||||||
@ -370,7 +386,7 @@ function Console(props: IProps, ref: ForwardedRef<IConsoleRef>) {
|
|||||||
|
|
||||||
const saveConsole = (value?: string) => {
|
const saveConsole = (value?: string) => {
|
||||||
// const a = editorRef.current?.getAllContent();
|
// const a = editorRef.current?.getAllContent();
|
||||||
let p: any = {
|
const p: any = {
|
||||||
id: executeParams.consoleId,
|
id: executeParams.consoleId,
|
||||||
status: ConsoleStatus.RELEASE,
|
status: ConsoleStatus.RELEASE,
|
||||||
ddl: value,
|
ddl: value,
|
||||||
@ -380,6 +396,7 @@ function Console(props: IProps, ref: ForwardedRef<IConsoleRef>) {
|
|||||||
indexedDB.deleteData('chat2db', 'workspaceConsoleDDL', executeParams.consoleId!);
|
indexedDB.deleteData('chat2db', 'workspaceConsoleDDL', executeParams.consoleId!);
|
||||||
message.success(i18n('common.tips.saveSuccessfully'));
|
message.success(i18n('common.tips.saveSuccessfully'));
|
||||||
props.onConsoleSave && props.onConsoleSave();
|
props.onConsoleSave && props.onConsoleSave();
|
||||||
|
timingAutoSave(ConsoleStatus.RELEASE);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -447,10 +464,10 @@ function Console(props: IProps, ref: ForwardedRef<IConsoleRef>) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleSelectTableSyncModel = () => {
|
const handleSelectTableSyncModel = () => {
|
||||||
const syncModel: SyncModelType | null = Number(localStorage.getItem('syncTableModel')) ?? null;
|
const syncModel = localStorage.getItem('syncTableModel');
|
||||||
const hasAiAccess = aiModel.hasWhite;
|
const hasAiAccess = aiModel.hasWhite;
|
||||||
if (syncModel !== null) {
|
if (syncModel !== null) {
|
||||||
setSyncTableModel(syncModel);
|
setSyncTableModel(Number(syncModel));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
39
chat2db-client/src/components/CreateDatabase/index.less
Normal file
39
chat2db-client/src/components/CreateDatabase/index.less
Normal file
@ -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%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
177
chat2db-client/src/components/CreateDatabase/index.tsx
Normal file
177
chat2db-client/src/components/CreateDatabase/index.tsx
Normal file
@ -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<ICreateDatabaseRef>) => {
|
||||||
|
const { className, curWorkspaceParams, executedCallback } = props;
|
||||||
|
const [form] = Form.useForm<ICreateDatabase>();
|
||||||
|
const monacoEditorUuid = useMemo(() => uuid(), []);
|
||||||
|
const monacoEditorRef = React.useRef<IExportRefFunction>(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<CreateType>('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 (
|
||||||
|
<Modal
|
||||||
|
onCancel={() => {
|
||||||
|
setOpen(false);
|
||||||
|
}}
|
||||||
|
title={config.title}
|
||||||
|
destroyOnClose
|
||||||
|
confirmLoading={confirmLoading}
|
||||||
|
open={open}
|
||||||
|
onOk={onOk}
|
||||||
|
>
|
||||||
|
<div className={classnames(styles.box, className)}>
|
||||||
|
<Form labelAlign="left" form={form} labelCol={labelCol} onFieldsChange={handleFieldsChange} name="create">
|
||||||
|
<Form.Item label={i18n('common.label.name')} name={config.formName}>
|
||||||
|
<Input autoComplete="off" />
|
||||||
|
</Form.Item>
|
||||||
|
{noCommentDatabase.includes(curWorkspaceParams.databaseType) ? null : (
|
||||||
|
<Form.Item label={i18n('common.label.comment')} name="comment">
|
||||||
|
<Input autoComplete="off" />
|
||||||
|
</Form.Item>
|
||||||
|
)}
|
||||||
|
</Form>
|
||||||
|
<div className={styles.previewBox}>
|
||||||
|
<div className={styles.previewText}>{i18n('common.title.preview')}</div>
|
||||||
|
<div className={styles.previewLine} />
|
||||||
|
</div>
|
||||||
|
<div className={styles.monacoEditorBox}>
|
||||||
|
<MonacoEditor
|
||||||
|
ref={monacoEditorRef}
|
||||||
|
options={{
|
||||||
|
lineNumbers: 'off',
|
||||||
|
}}
|
||||||
|
id={monacoEditorUuid}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
{errorMessage && (
|
||||||
|
<>
|
||||||
|
<div className={classnames(styles.previewBox, styles.errorBox)}>
|
||||||
|
<div className={styles.previewText}>{i18n('common.title.errorMessage')}</div>
|
||||||
|
<div className={styles.previewLine} />
|
||||||
|
</div>
|
||||||
|
<div>{errorMessage.message}</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
});
|
@ -85,6 +85,7 @@
|
|||||||
padding: 4px 10px;
|
padding: 4px 10px;
|
||||||
background-color: var(--color-bg-subtle);
|
background-color: var(--color-bg-subtle);
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
|
.f-doc-en-break();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1 @@
|
|||||||
|
@import '../../styles/var.less';
|
31
chat2db-client/src/components/Modal/TriggeredModal/index.tsx
Normal file
31
chat2db-client/src/components/Modal/TriggeredModal/index.tsx
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
import React, { memo, Fragment, ReactElement, cloneElement } from 'react';
|
||||||
|
import { Modal } from 'antd';
|
||||||
|
|
||||||
|
interface ITriggeredModal extends React.ComponentProps<typeof Modal> {
|
||||||
|
children: ReactElement;
|
||||||
|
modalContent: React.ReactNode;
|
||||||
|
onOk?: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
const TriggeredModal = memo<ITriggeredModal>((props) => {
|
||||||
|
const { children, modalContent, ...orgs } = props;
|
||||||
|
const [open, setOpen] = React.useState(false);
|
||||||
|
const onClose = () => {
|
||||||
|
setOpen(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
const onOk = () => {
|
||||||
|
orgs?.onOk?.(setOpen);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Fragment>
|
||||||
|
{cloneElement(children, { onClick: () => setOpen(true) })}
|
||||||
|
<Modal {...orgs} open={open} onCancel={onClose} onOk={onOk}>
|
||||||
|
{modalContent}
|
||||||
|
</Modal>
|
||||||
|
</Fragment>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
export default TriggeredModal;
|
@ -234,7 +234,6 @@ export default function TableBox(props: ITableProps) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
setTableData(newTableData);
|
setTableData(newTableData);
|
||||||
console.log(newTableData);
|
|
||||||
|
|
||||||
// 添加更新记录
|
// 添加更新记录
|
||||||
setUpdateData([
|
setUpdateData([
|
||||||
|
@ -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 classnames from 'classnames';
|
||||||
import Tabs from '@/components/Tabs';
|
import Tabs from '@/components/Tabs';
|
||||||
import Iconfont from '@/components/Iconfont';
|
import Iconfont from '@/components/Iconfont';
|
||||||
@ -27,7 +36,11 @@ const defaultResultConfig: IResultConfig = {
|
|||||||
hasNextPage: true,
|
hasNextPage: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default memo<IProps>((props) => {
|
export interface ISearchResultRef {
|
||||||
|
handleExecuteSQL: (sql: string) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default forwardRef((props: IProps, ref: ForwardedRef<ISearchResultRef>) => {
|
||||||
const { className, sql, executeSqlParams } = props;
|
const { className, sql, executeSqlParams } = props;
|
||||||
// const [currentTab, setCurrentTab] = useState<string | number | undefined>();
|
// const [currentTab, setCurrentTab] = useState<string | number | undefined>();
|
||||||
const [resultDataList, setResultDataList] = useState<IManageResultData[]>();
|
const [resultDataList, setResultDataList] = useState<IManageResultData[]>();
|
||||||
@ -40,6 +53,10 @@ export default memo<IProps>((props) => {
|
|||||||
}
|
}
|
||||||
}, [sql]);
|
}, [sql]);
|
||||||
|
|
||||||
|
useImperativeHandle(ref, () => ({
|
||||||
|
handleExecuteSQL,
|
||||||
|
}));
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 执行SQL
|
* 执行SQL
|
||||||
* @param sql
|
* @param sql
|
||||||
|
@ -6,9 +6,7 @@ interface IProps {
|
|||||||
className?: string;
|
className?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default memo<IProps>(function XXXX_FN(props) {
|
export default memo<IProps>((props) => {
|
||||||
const { className } = props
|
const { className } = props;
|
||||||
return <div className={classnames(styles.box, className)}>
|
return <div className={classnames(styles.box, className)}>demo</div>;
|
||||||
|
});
|
||||||
</div>
|
|
||||||
})
|
|
||||||
|
@ -2,7 +2,6 @@ export * from './appConfig';
|
|||||||
export * from './common';
|
export * from './common';
|
||||||
export * from './database';
|
export * from './database';
|
||||||
export * from './environment';
|
export * from './environment';
|
||||||
export * from './monacoEditor';
|
|
||||||
export * from './table';
|
export * from './table';
|
||||||
export * from './theme';
|
export * from './theme';
|
||||||
export * from './tree';
|
export * from './tree';
|
||||||
|
@ -93,5 +93,12 @@ export default {
|
|||||||
'common.text.affectedRows': 'Affected rows: {1}',
|
'common.text.affectedRows': 'Affected rows: {1}',
|
||||||
'common.text.selectFile' : 'Select File',
|
'common.text.selectFile' : 'Select File',
|
||||||
'common.text.noTableFoundUp' : 'No tables in this database',
|
'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',
|
||||||
};
|
};
|
||||||
|
@ -40,7 +40,7 @@ export default {
|
|||||||
'setting.button.restart': 'Restart',
|
'setting.button.restart': 'Restart',
|
||||||
'setting.text.discoverNewVersion': 'Discover new version {1}',
|
'setting.text.discoverNewVersion': 'Discover new version {1}',
|
||||||
'setting.text.isLatestVersion': 'This is the latest version',
|
'setting.text.isLatestVersion': 'This is the latest version',
|
||||||
'setting.button.changeLog': 'ChangeLog',
|
'setting.button.changeLog': 'Changelog',
|
||||||
'setting.title.updateRule': 'Update rule',
|
'setting.title.updateRule': 'Update rule',
|
||||||
'setting.text.autoUpdate': 'The new version automatically downloads and installs updates',
|
'setting.text.autoUpdate': 'The new version automatically downloads and installs updates',
|
||||||
'setting.text.manualUpdate': 'Only alert me when a new version is released',
|
'setting.text.manualUpdate': 'Only alert me when a new version is released',
|
||||||
|
@ -93,4 +93,11 @@ export default {
|
|||||||
'common.text.noTableFoundUp' : '当前库没有查询到表',
|
'common.text.noTableFoundUp' : '当前库没有查询到表',
|
||||||
'common.text.noTableFoundDown' : '你可以在顶部切换数据库',
|
'common.text.noTableFoundDown' : '你可以在顶部切换数据库',
|
||||||
'common.text.updateNow' : '立即更新',
|
'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': '创建',
|
||||||
};
|
};
|
||||||
|
@ -6,7 +6,6 @@ import { v4 as uuidv4 } from 'uuid';
|
|||||||
import { getAntdThemeConfig, injectThemeVar } from '@/theme';
|
import { getAntdThemeConfig, injectThemeVar } from '@/theme';
|
||||||
import { IVersionResponse } from '@/typings';
|
import { IVersionResponse } from '@/typings';
|
||||||
import miscService from '@/service/misc';
|
import miscService from '@/service/misc';
|
||||||
import configService from '@/service/config';
|
|
||||||
import antdEnUS from 'antd/locale/en_US';
|
import antdEnUS from 'antd/locale/en_US';
|
||||||
import antdZhCN from 'antd/locale/zh_CN';
|
import antdZhCN from 'antd/locale/zh_CN';
|
||||||
import { useTheme } from '@/hooks';
|
import { useTheme } from '@/hooks';
|
||||||
@ -34,7 +33,7 @@ declare global {
|
|||||||
electronApi?: {
|
electronApi?: {
|
||||||
startServerForSpawn: () => void;
|
startServerForSpawn: () => void;
|
||||||
quitApp: () => void;
|
quitApp: () => void;
|
||||||
beforeQuitApp: (fn: () => void) => void;
|
setBaseURL: (baseUrl:string) => void;
|
||||||
registerAppMenu: (data:any) => void;
|
registerAppMenu: (data:any) => void;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -111,10 +110,9 @@ function AppContainer() {
|
|||||||
window.electronApi?.registerAppMenu({
|
window.electronApi?.registerAppMenu({
|
||||||
version: __APP_VERSION__,
|
version: __APP_VERSION__,
|
||||||
})
|
})
|
||||||
|
// 把关闭java服务的的方法传给electron
|
||||||
window.electronApi?.beforeQuitApp(()=>{
|
window.electronApi?.setBaseURL?.(window._BaseURL)
|
||||||
configService.stopJavaService()
|
// console.log(window.electronApi)
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 初始化indexedDB
|
// 初始化indexedDB
|
||||||
|
@ -10,6 +10,8 @@ const { loadMainResource } = require('./utils');
|
|||||||
|
|
||||||
let mainWindow = null;
|
let mainWindow = null;
|
||||||
|
|
||||||
|
let baseUrl = null;
|
||||||
|
|
||||||
function createWindow() {
|
function createWindow() {
|
||||||
mainWindow = new BrowserWindow({
|
mainWindow = new BrowserWindow({
|
||||||
minWidth: 1080,
|
minWidth: 1080,
|
||||||
@ -69,7 +71,18 @@ app.on('window-all-closed', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
app.on('before-quit', () => {
|
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', () => {
|
ipcMain.handle('get-product-name', () => {
|
||||||
@ -86,3 +99,9 @@ ipcMain.on('quit-app', () => {
|
|||||||
ipcMain.on('register-app-menu', (event, orgs) => {
|
ipcMain.on('register-app-menu', (event, orgs) => {
|
||||||
registerAppMenu(mainWindow, orgs);
|
registerAppMenu(mainWindow, orgs);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
ipcMain.on('set-base-url',(event,_baseUrl)=>{
|
||||||
|
baseUrl = _baseUrl;
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
@ -43,13 +43,10 @@ contextBridge.exposeInMainWorld('electronApi', {
|
|||||||
quitApp: () => {
|
quitApp: () => {
|
||||||
ipcRenderer.send('quit-app');
|
ipcRenderer.send('quit-app');
|
||||||
},
|
},
|
||||||
beforeQuitApp: (callback)=>{
|
setBaseURL: (baseUrl) => {
|
||||||
ipcRenderer.on('before-quit-app', () => {
|
ipcRenderer.send('set-base-url', baseUrl);
|
||||||
callback();
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
registerAppMenu: (menuProps)=>{
|
registerAppMenu: (menuProps) => {
|
||||||
ipcRenderer.send('register-app-menu', menuProps);
|
ipcRenderer.send('register-app-menu', menuProps);
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -58,7 +58,7 @@ const WorkspaceModel: IWorkspaceModelType = {
|
|||||||
|
|
||||||
state: {
|
state: {
|
||||||
databaseAndSchema: undefined,
|
databaseAndSchema: undefined,
|
||||||
curWorkspaceParams: getCurrentWorkspaceDatabase(),
|
curWorkspaceParams: {} as any,
|
||||||
doubleClickTreeNodeData: undefined,
|
doubleClickTreeNodeData: undefined,
|
||||||
consoleList: [],
|
consoleList: [],
|
||||||
openConsoleList: [],
|
openConsoleList: [],
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import indexedDB from '@/indexedDB';
|
|
||||||
|
|
||||||
export enum CustomerTypeEnum {
|
export enum CustomerTypeEnum {
|
||||||
visitor = 'visitor',
|
visitor = 'visitor',
|
||||||
@ -14,31 +13,10 @@ export enum CustomerTypeEnum2 {
|
|||||||
export type CustomerType1 = CustomerTypeEnum | CustomerTypeEnum2;
|
export type CustomerType1 = CustomerTypeEnum | CustomerTypeEnum2;
|
||||||
|
|
||||||
const App: React.FC = () => {
|
const App: React.FC = () => {
|
||||||
const [db, setDb] = useState<any>();
|
|
||||||
|
|
||||||
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 (
|
return (
|
||||||
<div>
|
<div>demo</div>
|
||||||
<button onClick={add}>add</button>
|
|
||||||
<button onClick={deleteFn}>deleteFn</button>
|
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -107,7 +107,7 @@ const SaveList = dvaModel((props: any) => {
|
|||||||
id: data.id,
|
id: data.id,
|
||||||
status: ConsoleStatus.DRAFT,
|
status: ConsoleStatus.DRAFT,
|
||||||
};
|
};
|
||||||
historyServer.updateSavedConsole(params).then((res) => {
|
historyServer.updateSavedConsole(params).then(() => {
|
||||||
dispatch({
|
dispatch({
|
||||||
type: 'workspace/fetchGetSavedConsole',
|
type: 'workspace/fetchGetSavedConsole',
|
||||||
payload: {
|
payload: {
|
||||||
@ -115,10 +115,10 @@ const SaveList = dvaModel((props: any) => {
|
|||||||
status: ConsoleStatus.RELEASE,
|
status: ConsoleStatus.RELEASE,
|
||||||
...curWorkspaceParams,
|
...curWorkspaceParams,
|
||||||
},
|
},
|
||||||
callback: (res: any) => {
|
callback: (_res: any) => {
|
||||||
dispatch({
|
dispatch({
|
||||||
type: 'workspace/setConsoleList',
|
type: 'workspace/setConsoleList',
|
||||||
payload: res.data,
|
payload: _res.data,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -6,12 +6,14 @@ import Iconfont from '@/components/Iconfont';
|
|||||||
import { IConnectionModelType } from '@/models/connection';
|
import { IConnectionModelType } from '@/models/connection';
|
||||||
import { IWorkspaceModelType } from '@/models/workspace';
|
import { IWorkspaceModelType } from '@/models/workspace';
|
||||||
import { IMainPageType } from '@/models/mainPage';
|
import { IMainPageType } from '@/models/mainPage';
|
||||||
import { Cascader, Spin, Modal, Tag } from 'antd';
|
import { Cascader, Spin, Modal, Tag, Divider } from 'antd';
|
||||||
import { databaseMap, TreeNodeType } from '@/constants';
|
import { databaseMap, TreeNodeType, DatabaseTypeCode } from '@/constants';
|
||||||
import { treeConfig } from '../Tree/treeConfig';
|
import { treeConfig } from '../Tree/treeConfig';
|
||||||
import { useUpdateEffect } from '@/hooks/useUpdateEffect';
|
import { useUpdateEffect } from '@/hooks/useUpdateEffect';
|
||||||
import styles from './index.less';
|
import styles from './index.less';
|
||||||
import i18n from '@/i18n';
|
import i18n from '@/i18n';
|
||||||
|
import CreateDatabase, { ICreateDatabaseRef } from '@/components/CreateDatabase';
|
||||||
|
import { getCurrentWorkspaceDatabase } from '@/utils/localStorage';
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
className?: string;
|
className?: string;
|
||||||
@ -26,6 +28,14 @@ interface IOption {
|
|||||||
value: number | string;
|
value: number | string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 不支持创建数据库的数据库类型
|
||||||
|
const notSupportCreateDatabaseType = [DatabaseTypeCode.H2];
|
||||||
|
|
||||||
|
// 不支持创建schema的数据库类型
|
||||||
|
const notSupportCreateSchemaType = [DatabaseTypeCode.ORACLE];
|
||||||
|
|
||||||
|
const localStorageWorkspaceDatabase = getCurrentWorkspaceDatabase();
|
||||||
|
|
||||||
const WorkspaceHeader = memo<IProps>((props) => {
|
const WorkspaceHeader = memo<IProps>((props) => {
|
||||||
const { connectionModel, workspaceModel, mainPageModel, dispatch } = props;
|
const { connectionModel, workspaceModel, mainPageModel, dispatch } = props;
|
||||||
const { connectionList, curConnection } = connectionModel;
|
const { connectionList, curConnection } = connectionModel;
|
||||||
@ -37,6 +47,18 @@ const WorkspaceHeader = memo<IProps>((props) => {
|
|||||||
const [curDBOptions, setCurDBOptions] = useState<IOption[]>([]);
|
const [curDBOptions, setCurDBOptions] = useState<IOption[]>([]);
|
||||||
const [curSchemaOptions, setCurSchemaOptions] = useState<IOption[]>([]);
|
const [curSchemaOptions, setCurSchemaOptions] = useState<IOption[]>([]);
|
||||||
const [isRefresh, setIsRefresh] = useState(false);
|
const [isRefresh, setIsRefresh] = useState(false);
|
||||||
|
const [openDBCascaderDropdown, setOpenDBCascaderDropdown] = useState<false | undefined>(undefined);
|
||||||
|
const [openSchemaCascaderDropdown, setOpenSchemaCascaderDropdown] = useState<false | undefined>(undefined);
|
||||||
|
const createDatabaseRef = React.useRef<ICreateDatabaseRef>(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (openDBCascaderDropdown === false) {
|
||||||
|
setOpenDBCascaderDropdown(undefined);
|
||||||
|
}
|
||||||
|
if (openSchemaCascaderDropdown === false) {
|
||||||
|
setOpenSchemaCascaderDropdown(undefined);
|
||||||
|
}
|
||||||
|
}, [openDBCascaderDropdown, openSchemaCascaderDropdown]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (curPage !== 'workspace') {
|
if (curPage !== 'workspace') {
|
||||||
@ -44,7 +66,14 @@ const WorkspaceHeader = memo<IProps>((props) => {
|
|||||||
}
|
}
|
||||||
// 如果没有curConnection默认选第一个
|
// 如果没有curConnection默认选第一个
|
||||||
if (!curConnection?.id && connectionList.length) {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
// 如果都有的话
|
// 如果都有的话
|
||||||
@ -52,7 +81,12 @@ const WorkspaceHeader = memo<IProps>((props) => {
|
|||||||
// 如果curConnection不再connectionList里,也是默认选第一个
|
// 如果curConnection不再connectionList里,也是默认选第一个
|
||||||
const flag = connectionList.findIndex((t: any) => t.id === curConnection?.id);
|
const flag = connectionList.findIndex((t: any) => t.id === curConnection?.id);
|
||||||
if (flag === -1) {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -71,10 +105,6 @@ const WorkspaceHeader = memo<IProps>((props) => {
|
|||||||
getDatabaseList(isRefresh);
|
getDatabaseList(isRefresh);
|
||||||
setIsRefresh(false);
|
setIsRefresh(false);
|
||||||
}
|
}
|
||||||
// connectionList转换成可用的ConnectionOptions
|
|
||||||
// if (!connectionList.length) {
|
|
||||||
// setNoConnectionModal(true);
|
|
||||||
// }
|
|
||||||
setConnectionOptions(
|
setConnectionOptions(
|
||||||
connectionList?.map((t) => {
|
connectionList?.map((t) => {
|
||||||
return {
|
return {
|
||||||
@ -118,7 +148,7 @@ const WorkspaceHeader = memo<IProps>((props) => {
|
|||||||
dataSourceName: curConnection.name,
|
dataSourceName: curConnection.name,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.then((res) => {
|
.then((res: any) => {
|
||||||
const dbList =
|
const dbList =
|
||||||
res?.map((t) => {
|
res?.map((t) => {
|
||||||
return {
|
return {
|
||||||
@ -127,14 +157,20 @@ const WorkspaceHeader = memo<IProps>((props) => {
|
|||||||
};
|
};
|
||||||
}) || [];
|
}) || [];
|
||||||
setCurDBOptions(dbList);
|
setCurDBOptions(dbList);
|
||||||
// 如果是切换那么就默认取列表的第一个database, 如果不是切换那么就取缓存的,如果缓存没有还是取列表第一个(这里是兜底,如果原先他并没有database,后来他加了database,如果还是取缓存的空就不对了)
|
let databaseName = '';
|
||||||
const databaseName =
|
if(dbList.find((t: any) => t.value === localStorageWorkspaceDatabase.databaseName)){
|
||||||
curWorkspaceParams.dataSourceId !== curConnection?.id
|
databaseName = localStorageWorkspaceDatabase.databaseName!;
|
||||||
? dbList[0]?.label
|
}else{
|
||||||
: curWorkspaceParams.databaseName || dbList[0]?.label;
|
// 如果是切换那么就默认取列表的第一个database, 如果不是切换那么就取缓存的,如果缓存没有还是取列表第一个(这里是兜底,如果原先他并没有database,后来他加了database,如果还是取缓存的空就不对了)
|
||||||
getSchemaList(databaseName, refresh);
|
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);
|
setCascaderLoading(false);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -155,7 +191,7 @@ const WorkspaceHeader = memo<IProps>((props) => {
|
|||||||
dataSourceName: curConnection.name,
|
dataSourceName: curConnection.name,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.then((res) => {
|
.then((res: any) => {
|
||||||
const schemaList =
|
const schemaList =
|
||||||
res?.map((t) => {
|
res?.map((t) => {
|
||||||
return {
|
return {
|
||||||
@ -164,10 +200,17 @@ const WorkspaceHeader = memo<IProps>((props) => {
|
|||||||
};
|
};
|
||||||
}) || [];
|
}) || [];
|
||||||
setCurSchemaOptions(schemaList);
|
setCurSchemaOptions(schemaList);
|
||||||
const schemaName =
|
|
||||||
curWorkspaceParams.dataSourceId !== curConnection?.id
|
let schemaName = '';
|
||||||
? schemaList[0]?.label
|
if(schemaList.find((t: any) => t.value === localStorageWorkspaceDatabase.schemaName)){
|
||||||
: curWorkspaceParams.schemaName || schemaList[0]?.label;
|
schemaName = localStorageWorkspaceDatabase.schemaName!;
|
||||||
|
}else{
|
||||||
|
schemaName =
|
||||||
|
curWorkspaceParams.dataSourceId !== curConnection?.id
|
||||||
|
? schemaList[0]?.label
|
||||||
|
: curWorkspaceParams.schemaName || schemaList[0]?.label;
|
||||||
|
}
|
||||||
|
// schemaChange([schemaName], [{ label: schemaName }]);
|
||||||
const data: any = {
|
const data: any = {
|
||||||
dataSourceId: curConnection.id,
|
dataSourceId: curConnection.id,
|
||||||
dataSourceName: curConnection.alias,
|
dataSourceName: curConnection.alias,
|
||||||
@ -226,17 +269,17 @@ const WorkspaceHeader = memo<IProps>((props) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 数据库切换
|
// 数据库切换
|
||||||
function databaseChange(valueArr: any, selectedOptions: any) {
|
function databaseChange(valueArr: any, selectedOptions: any,refresh) {
|
||||||
if (selectedOptions[0].label !== curWorkspaceParams.databaseName) {
|
// if (selectedOptions[0].label !== curWorkspaceParams.databaseName) {
|
||||||
getSchemaList(selectedOptions[0].label);
|
getSchemaList(selectedOptions[0].label,refresh);
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
// schema切换
|
// schema切换
|
||||||
function schemaChange(valueArr: any, selectedOptions: any) {
|
function schemaChange(valueArr: any, selectedOptions: any) {
|
||||||
if (selectedOptions[0].label !== curWorkspaceParams.schemaName) {
|
// if (selectedOptions[0].label !== curWorkspaceParams.schemaName) {
|
||||||
setCurWorkspaceParams({ ...curWorkspaceParams, schemaName: selectedOptions[0].value });
|
setCurWorkspaceParams({ ...curWorkspaceParams, schemaName: selectedOptions[0].value });
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleRefresh() {
|
function handleRefresh() {
|
||||||
@ -265,11 +308,34 @@ const WorkspaceHeader = memo<IProps>((props) => {
|
|||||||
</Cascader>
|
</Cascader>
|
||||||
|
|
||||||
{!!curDBOptions?.length && <Iconfont className={styles.arrow} code="" />}
|
{!!curDBOptions?.length && <Iconfont className={styles.arrow} code="" />}
|
||||||
|
|
||||||
{!!curDBOptions?.length && (
|
{!!curDBOptions?.length && (
|
||||||
<Cascader
|
<Cascader
|
||||||
popupClassName={styles.cascaderPopup}
|
popupClassName={styles.cascaderPopup}
|
||||||
options={curDBOptions}
|
options={curDBOptions}
|
||||||
|
open={openDBCascaderDropdown}
|
||||||
|
dropdownRender={(menu) => {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
{menu}
|
||||||
|
<Divider style={{ margin: 0 }} />
|
||||||
|
{
|
||||||
|
// 不支持创建数据库的数据库类型
|
||||||
|
!notSupportCreateDatabaseType.includes(curWorkspaceParams?.databaseType) && (
|
||||||
|
<div
|
||||||
|
className={styles.dropdownFooter}
|
||||||
|
onClick={() => {
|
||||||
|
setOpenDBCascaderDropdown(false);
|
||||||
|
createDatabaseRef.current?.setOpen(true, 'database');
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Iconfont code="" />
|
||||||
|
{i18n('common.Button.addDatabase')}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}}
|
||||||
onChange={databaseChange}
|
onChange={databaseChange}
|
||||||
bordered={false}
|
bordered={false}
|
||||||
value={[curWorkspaceParams?.databaseName || '']}
|
value={[curWorkspaceParams?.databaseName || '']}
|
||||||
@ -286,7 +352,31 @@ const WorkspaceHeader = memo<IProps>((props) => {
|
|||||||
options={curSchemaOptions}
|
options={curSchemaOptions}
|
||||||
onChange={schemaChange}
|
onChange={schemaChange}
|
||||||
bordered={false}
|
bordered={false}
|
||||||
|
open={openSchemaCascaderDropdown}
|
||||||
value={[curWorkspaceParams?.schemaName || '']}
|
value={[curWorkspaceParams?.schemaName || '']}
|
||||||
|
dropdownRender={(menu) => {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
{menu}
|
||||||
|
<Divider style={{ margin: 0 }} />
|
||||||
|
{
|
||||||
|
// 不支持创建schema的数据库类型
|
||||||
|
!notSupportCreateSchemaType.includes(curWorkspaceParams?.databaseType) && (
|
||||||
|
<div
|
||||||
|
className={styles.dropdownFooter}
|
||||||
|
onClick={() => {
|
||||||
|
setOpenSchemaCascaderDropdown(false);
|
||||||
|
createDatabaseRef.current?.setOpen(true, 'schema');
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Iconfont code="" />
|
||||||
|
{i18n('common.Button.addSchema')}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<div className={styles.crumbsItem}>
|
<div className={styles.crumbsItem}>
|
||||||
<div className={styles.text}>{curWorkspaceParams.schemaName}</div>
|
<div className={styles.text}>{curWorkspaceParams.schemaName}</div>
|
||||||
@ -330,6 +420,11 @@ const WorkspaceHeader = memo<IProps>((props) => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Modal>
|
</Modal>
|
||||||
|
<CreateDatabase
|
||||||
|
executedCallback={handleRefresh}
|
||||||
|
curWorkspaceParams={curWorkspaceParams}
|
||||||
|
ref={createDatabaseRef}
|
||||||
|
/>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -64,7 +64,6 @@ const WorkspaceRight = memo<IProps>((props: IProps) => {
|
|||||||
uniqueData: t,
|
uniqueData: t,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
console.log(workspaceTabList, newTabList);
|
|
||||||
if (workspaceTabList.length) {
|
if (workspaceTabList.length) {
|
||||||
const newWorkspaceTabList = lodash.cloneDeep(workspaceTabList);
|
const newWorkspaceTabList = lodash.cloneDeep(workspaceTabList);
|
||||||
const newAddList: any = [];
|
const newAddList: any = [];
|
||||||
@ -312,11 +311,23 @@ const WorkspaceRight = memo<IProps>((props: IProps) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (doubleClickTreeNodeData.treeNodeType === TreeNodeType.TABLE) {
|
if (doubleClickTreeNodeData.treeNodeType === TreeNodeType.TABLE) {
|
||||||
|
|
||||||
const { extraParams } = doubleClickTreeNodeData;
|
const { extraParams } = doubleClickTreeNodeData;
|
||||||
const { tableName } = extraParams || {};
|
const { tableName } = extraParams || {};
|
||||||
const sql = `SELECT * FROM ${compatibleDataBaseName(tableName!, curWorkspaceParams.databaseType)};\n`;
|
const sql = `SELECT * FROM ${compatibleDataBaseName(tableName!, curWorkspaceParams.databaseType)};\n`;
|
||||||
const title = tableName!;
|
const title = tableName!;
|
||||||
const id = uuidV4();
|
const id = uuidV4();
|
||||||
|
let flag = false;
|
||||||
|
workspaceTabList.forEach((t) => {
|
||||||
|
if (t.uniqueData?.sql === sql) {
|
||||||
|
setActiveConsoleId(t.id);
|
||||||
|
flag = true
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if(flag){
|
||||||
|
return
|
||||||
|
}
|
||||||
setWorkspaceTabList([
|
setWorkspaceTabList([
|
||||||
...(workspaceTabList || []),
|
...(workspaceTabList || []),
|
||||||
{
|
{
|
||||||
@ -355,6 +366,9 @@ const WorkspaceRight = memo<IProps>((props: IProps) => {
|
|||||||
// 更新表名提示
|
// 更新表名提示
|
||||||
useUpdateEffect(() => {
|
useUpdateEffect(() => {
|
||||||
const { dataSourceId, databaseName, schemaName, databaseType } = curWorkspaceParams;
|
const { dataSourceId, databaseName, schemaName, databaseType } = curWorkspaceParams;
|
||||||
|
if (dataSourceId === null || dataSourceId === undefined) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
sqlService
|
sqlService
|
||||||
.getAllTableList({
|
.getAllTableList({
|
||||||
dataSourceId,
|
dataSourceId,
|
||||||
@ -571,6 +585,7 @@ const WorkspaceRight = memo<IProps>((props: IProps) => {
|
|||||||
schemaName: curWorkspaceParams?.schemaName,
|
schemaName: curWorkspaceParams?.schemaName,
|
||||||
consoleId: t.id as number,
|
consoleId: t.id as number,
|
||||||
consoleName: uniqueData.name,
|
consoleName: uniqueData.name,
|
||||||
|
status: uniqueData.status,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
@ -78,11 +78,6 @@ const setAppUpdateType = createRequest<ILatestVersion['type'], boolean>('/api/sy
|
|||||||
method: 'post',
|
method: 'post',
|
||||||
});
|
});
|
||||||
|
|
||||||
// 退出electron时关闭后端服务
|
|
||||||
const stopJavaService = createRequest<void, void>('/api/system/stop', {
|
|
||||||
method: 'post',
|
|
||||||
});
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
getSystemConfig,
|
getSystemConfig,
|
||||||
setSystemConfig,
|
setSystemConfig,
|
||||||
@ -92,6 +87,5 @@ export default {
|
|||||||
getLatestVersion,
|
getLatestVersion,
|
||||||
isUpdateSuccess,
|
isUpdateSuccess,
|
||||||
updateDesktopVersion,
|
updateDesktopVersion,
|
||||||
setAppUpdateType,
|
setAppUpdateType
|
||||||
stopJavaService
|
|
||||||
};
|
};
|
||||||
|
@ -1,10 +1,4 @@
|
|||||||
import createRequest from './base';
|
import createRequest from './base';
|
||||||
import { IVersionResponse } from '@/typings';
|
|
||||||
|
|
||||||
const checkVersion = createRequest<void, IVersionResponse>('/api/client/version/check/v2', {
|
|
||||||
errorLevel: false,
|
|
||||||
outside: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
const dynamicUrl = createRequest<string, void>('', {
|
const dynamicUrl = createRequest<string, void>('', {
|
||||||
dynamicUrl: true,
|
dynamicUrl: true,
|
||||||
@ -12,5 +6,4 @@ const dynamicUrl = createRequest<string, void>('', {
|
|||||||
|
|
||||||
export default {
|
export default {
|
||||||
dynamicUrl,
|
dynamicUrl,
|
||||||
checkVersion,
|
|
||||||
};
|
};
|
||||||
|
@ -288,7 +288,22 @@ const executeUpdateDataSql = createRequest<IExecuteSqlParams, { success: boolean
|
|||||||
/** 获取修改表数据的接口 */
|
/** 获取修改表数据的接口 */
|
||||||
const getExecuteUpdateSql = createRequest<any, string>('/api/rdb/dml/get_update_sql', { method: 'post' });
|
const getExecuteUpdateSql = createRequest<any, string>('/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 {
|
export default {
|
||||||
|
getCreateSchemaSql,
|
||||||
|
getCreateDatabaseSql,
|
||||||
executeUpdateDataSql,
|
executeUpdateDataSql,
|
||||||
executeDDL,
|
executeDDL,
|
||||||
getExecuteUpdateSql,
|
getExecuteUpdateSql,
|
||||||
|
@ -51,6 +51,11 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 文档英文强制换行
|
||||||
|
.f-doc-en-break {
|
||||||
|
word-break: break-all;
|
||||||
|
}
|
||||||
|
|
||||||
@keyframes loading-animation {
|
@keyframes loading-animation {
|
||||||
0% {
|
0% {
|
||||||
transform: rotate(0deg);
|
transform: rotate(0deg);
|
||||||
|
@ -244,9 +244,9 @@ export function formatSql(sql: string, dbType: DatabaseTypeCode) {
|
|||||||
// 桌面端用hash模式,web端用history模式,路由跳转
|
// 桌面端用hash模式,web端用history模式,路由跳转
|
||||||
export function navigate(path: string) {
|
export function navigate(path: string) {
|
||||||
if (__ENV__ === 'desktop') {
|
if (__ENV__ === 'desktop') {
|
||||||
window.location.href = `#${path}`;
|
window.location.replace(`#${path}`)
|
||||||
} else {
|
} else {
|
||||||
window.location.href = path;
|
window.location.replace(path)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,13 +1,32 @@
|
|||||||
package ai.chat2db.plugin.h2;
|
package ai.chat2db.plugin.h2;
|
||||||
|
|
||||||
import java.sql.Connection;
|
import java.sql.Connection;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
|
||||||
import ai.chat2db.spi.DBManage;
|
import ai.chat2db.spi.DBManage;
|
||||||
import ai.chat2db.spi.jdbc.DefaultDBManage;
|
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 ai.chat2db.spi.sql.SQLExecutor;
|
||||||
|
import org.apache.commons.lang3.ObjectUtils;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
public class H2DBManage extends DefaultDBManage implements DBManage {
|
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
|
@Override
|
||||||
public void dropTable(Connection connection, String databaseName, String schemaName, String tableName) {
|
public void dropTable(Connection connection, String databaseName, String schemaName, String tableName) {
|
||||||
|
@ -129,7 +129,7 @@ public class MysqlSqlBuilder extends DefaultSqlBuilder implements SqlBuilder {
|
|||||||
@Override
|
@Override
|
||||||
public String buildCreateDatabaseSql(Database database) {
|
public String buildCreateDatabaseSql(Database database) {
|
||||||
StringBuilder sqlBuilder = new StringBuilder();
|
StringBuilder sqlBuilder = new StringBuilder();
|
||||||
sqlBuilder.append("CREATE DATABASE "+database.getName());
|
sqlBuilder.append("CREATE DATABASE `"+database.getName()+"`");
|
||||||
if (StringUtils.isNotBlank(database.getCharset())) {
|
if (StringUtils.isNotBlank(database.getCharset())) {
|
||||||
sqlBuilder.append(" DEFAULT CHARACTER SET=").append(database.getCharset());
|
sqlBuilder.append(" DEFAULT CHARACTER SET=").append(database.getCharset());
|
||||||
}
|
}
|
||||||
|
@ -4,17 +4,22 @@ import java.sql.Connection;
|
|||||||
|
|
||||||
import ai.chat2db.spi.DBManage;
|
import ai.chat2db.spi.DBManage;
|
||||||
import ai.chat2db.spi.jdbc.DefaultDBManage;
|
import ai.chat2db.spi.jdbc.DefaultDBManage;
|
||||||
|
import ai.chat2db.spi.sql.Chat2DBContext;
|
||||||
import ai.chat2db.spi.sql.ConnectInfo;
|
import ai.chat2db.spi.sql.ConnectInfo;
|
||||||
import ai.chat2db.spi.sql.SQLExecutor;
|
import ai.chat2db.spi.sql.SQLExecutor;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
public class PostgreSQLDBManage extends DefaultDBManage implements DBManage {
|
public class PostgreSQLDBManage extends DefaultDBManage implements DBManage {
|
||||||
@Override
|
@Override
|
||||||
public void connectDatabase(Connection connection, String database) {
|
public void connectDatabase(Connection connection, String database) {
|
||||||
//try {
|
try {
|
||||||
// SQLExecutor.getInstance().execute(connection,"SELECT pg_database_size('"+database+"');");
|
ConnectInfo connectInfo = Chat2DBContext.getConnectInfo();
|
||||||
//} catch (SQLException e) {
|
if (!StringUtils.isEmpty(connectInfo.getSchemaName())) {
|
||||||
// throw new RuntimeException(e);
|
SQLExecutor.getInstance().execute(connection, "SET search_path TO \"" + connectInfo.getSchemaName() + "\"");
|
||||||
//}
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -26,7 +31,7 @@ public class PostgreSQLDBManage extends DefaultDBManage implements DBManage {
|
|||||||
}
|
}
|
||||||
connectInfo.setUrl(url);
|
connectInfo.setUrl(url);
|
||||||
|
|
||||||
return super.getConnection(connectInfo);
|
return super.getConnection(connectInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -53,8 +58,8 @@ public class PostgreSQLDBManage extends DefaultDBManage implements DBManage {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void dropTable(Connection connection, String databaseName, String schemaName, String tableName) {
|
public void dropTable(Connection connection, String databaseName, String schemaName, String tableName) {
|
||||||
String sql = "DROP TABLE "+ tableName;
|
String sql = "DROP TABLE " + tableName;
|
||||||
SQLExecutor.getInstance().executeSql(connection,sql, resultSet -> null);
|
SQLExecutor.getInstance().executeSql(connection, sql, resultSet -> null);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,7 @@ public class SqlServerDBManage extends DefaultDBManage implements DBManage {
|
|||||||
@Override
|
@Override
|
||||||
public void connectDatabase(Connection connection, String database) {
|
public void connectDatabase(Connection connection, String database) {
|
||||||
try {
|
try {
|
||||||
SQLExecutor.getInstance().execute(connection,"use [" + database + "];");
|
SQLExecutor.getInstance().execute(connection, "use [" + database + "];");
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
|
@ -153,7 +153,7 @@ public class SqlServerSqlBuilder extends DefaultSqlBuilder implements SqlBuilder
|
|||||||
sqlBuilder.append("\ngo\n");
|
sqlBuilder.append("\ngo\n");
|
||||||
if (StringUtils.isNotBlank(database.getComment())) {
|
if (StringUtils.isNotBlank(database.getComment())) {
|
||||||
sqlBuilder.append("exec [" + database.getName() + "].sys. sp_addextendedproperty 'MS_Description','")
|
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();
|
return sqlBuilder.toString();
|
||||||
}
|
}
|
||||||
@ -166,7 +166,7 @@ public class SqlServerSqlBuilder extends DefaultSqlBuilder implements SqlBuilder
|
|||||||
if (StringUtils.isNotBlank(schema.getComment())) {
|
if (StringUtils.isNotBlank(schema.getComment())) {
|
||||||
sqlBuilder.append("exec sp_addextendedproperty 'MS_Description','")
|
sqlBuilder.append("exec sp_addextendedproperty 'MS_Description','")
|
||||||
.append(schema.getComment()).append("'").append(",'SCHEMA'")
|
.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();
|
return sqlBuilder.toString();
|
||||||
}
|
}
|
||||||
|
@ -56,7 +56,7 @@ public class Chat2dbWebMvcConfigurer implements WebMvcConfigurer {
|
|||||||
* 全局放行的url
|
* 全局放行的url
|
||||||
*/
|
*/
|
||||||
private static final String[] FRONT_PERMIT_ALL = new String[] {"/favicon.ico", "/error", "/static/**",
|
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
|
@Resource
|
||||||
private UserService userService;
|
private UserService userService;
|
||||||
|
@ -93,7 +93,7 @@ public class RdbDmlController {
|
|||||||
try {
|
try {
|
||||||
boolean flag = true;
|
boolean flag = true;
|
||||||
ExecuteResultVO executeResult = null;
|
ExecuteResultVO executeResult = null;
|
||||||
connection.setAutoCommit(false);
|
//connection.setAutoCommit(false);
|
||||||
ListResult<ExecuteResult> resultDTOListResult = dlTemplateService.execute(param);
|
ListResult<ExecuteResult> resultDTOListResult = dlTemplateService.execute(param);
|
||||||
List<ExecuteResultVO> resultVOS = rdbWebConverter.dto2vo(resultDTOListResult.getData());
|
List<ExecuteResultVO> resultVOS = rdbWebConverter.dto2vo(resultDTOListResult.getData());
|
||||||
if (!CollectionUtils.isEmpty(resultVOS)) {
|
if (!CollectionUtils.isEmpty(resultVOS)) {
|
||||||
@ -107,7 +107,7 @@ public class RdbDmlController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (flag) {
|
if (flag) {
|
||||||
connection.commit();
|
//connection.commit();
|
||||||
return DataResult.of(resultVOS.get(0));
|
return DataResult.of(resultVOS.get(0));
|
||||||
}else {
|
}else {
|
||||||
connection.rollback();
|
connection.rollback();
|
||||||
|
@ -108,7 +108,7 @@ public class DatabaseExportService {
|
|||||||
try {
|
try {
|
||||||
export(outputStream, exportOptions);
|
export(outputStream, exportOptions);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new RuntimeException("导出失败!请联系开发者,邮箱:963565242@qq.com" + e);
|
throw new RuntimeException("导出失败!请联系开发者" + e);
|
||||||
}
|
}
|
||||||
init();
|
init();
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user