Skip to content

Commit c33cd5c

Browse files
committed
feat:Open table to support filtering
1 parent 7ed715a commit c33cd5c

17 files changed

Lines changed: 413 additions & 68 deletions

File tree

chat2db-client/src/components/ConsoleEditor/components/SelectBoundInfo/index.tsx

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@ import {
1515
registerIntelliSenseKeyword,
1616
registerIntelliSenseTable,
1717
registerIntelliSenseDatabase,
18+
resetSenseKeyword,
19+
resetSenseTable,
20+
resetSenseDatabase,
21+
resetSenseField,
1822
} from '@/utils/IntelliSense';
1923

2024
interface IProps {
@@ -42,6 +46,15 @@ const SelectBoundInfo = memo((props: IProps) => {
4246
const [schemaList, setSchemaList] = useState<IOption<string>[]>([emptyOption]);
4347
const [allTableList, setAllTableList] = useState<any>([]);
4448

49+
useEffect(() => {
50+
if(!isActive){
51+
resetSenseKeyword();
52+
resetSenseTable();
53+
resetSenseDatabase();
54+
resetSenseField();
55+
}
56+
}, [isActive]);
57+
4558
const dataSourceList = useMemo(() => {
4659
return (
4760
connectionList?.map((item) => ({
@@ -55,16 +68,19 @@ const SelectBoundInfo = memo((props: IProps) => {
5568

5669
const supportDatabase = useMemo(() => {
5770
return connectionList?.find((item) => item.id === boundInfo.dataSourceId)?.supportDatabase;
58-
}, [boundInfo.dataSourceId,connectionList]);
71+
}, [boundInfo.dataSourceId, connectionList]);
5972

6073
const supportSchema = useMemo(() => {
6174
return connectionList?.find((item) => item.id === boundInfo.dataSourceId)?.supportSchema;
62-
}, [boundInfo.dataSourceId,connectionList]);
75+
}, [boundInfo.dataSourceId, connectionList]);
6376

6477
// 编辑器绑定的数据库类型变化时,重新注册智能提示
6578
useEffect(() => {
79+
if(!isActive){
80+
return
81+
}
6682
registerIntelliSenseKeyword(boundInfo.databaseType);
67-
}, [boundInfo.dataSourceId]);
83+
}, [boundInfo.dataSourceId, isActive]);
6884

6985
// 当数据源变化时,重新获取数据库列表
7086
useEffect(() => {

chat2db-client/src/components/Iconfont/index.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@ if (__ENV__ === 'local') {
99
/* 在线链接服务仅供平台体验和调试使用,平台不承诺服务的稳定性,企业客户需下载字体包自行发布使用并做好备份。 */
1010
@font-face {
1111
font-family: 'iconfont'; /* Project id 3633546 */
12-
src: url('//at.alicdn.com/t/c/font_3633546_oqofqe5r679.woff2?t=1703676557975') format('woff2'),
13-
url('//at.alicdn.com/t/c/font_3633546_oqofqe5r679.woff?t=1703676557975') format('woff'),
14-
url('//at.alicdn.com/t/c/font_3633546_oqofqe5r679.ttf?t=1703676557975') format('truetype');
12+
src: url('//at.alicdn.com/t/c/font_3633546_yr9ay65j0fs.woff2?t=1703837870848') format('woff2'),
13+
url('//at.alicdn.com/t/c/font_3633546_yr9ay65j0fs.woff?t=1703837870848') format('woff'),
14+
url('//at.alicdn.com/t/c/font_3633546_yr9ay65j0fs.ttf?t=1703837870848') format('truetype');
1515
}
1616
`;
1717
const style = document.createElement('style');

chat2db-client/src/components/MonacoEditor/index.tsx

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,8 @@ interface IProps {
3333
defaultValue?: string;
3434
appendValue?: IAppendValue;
3535
didMount?: (editor: IEditorIns) => any;
36-
shortcutKey?: (editor, monaco) => void;
37-
isActive?: boolean;
36+
shortcutKey?: (editor, monaco, isActive: boolean) => void;
37+
focusChange?: (isActive: boolean) => void;
3838
}
3939

4040
export interface IExportRefFunction {
@@ -51,14 +51,14 @@ function MonacoEditor(props: IProps, ref: ForwardedRef<IExportRefFunction>) {
5151
language = 'sql',
5252
didMount,
5353
options,
54-
isActive,
5554
defaultValue,
5655
appendValue,
5756
shortcutKey,
5857
} = props;
5958
const editorRef = useRef<IEditorIns>();
6059
const quickInputCommand = useRef<any>();
6160
const [appTheme] = useTheme();
61+
const [isActive, setIsActive] = React.useState(false);
6262

6363
// init
6464
useEffect(() => {
@@ -108,12 +108,32 @@ function MonacoEditor(props: IProps, ref: ForwardedRef<IExportRefFunction>) {
108108
};
109109
}, []);
110110

111+
// 如果编辑器聚焦,就设置为true
111112
useEffect(() => {
112-
if (editorRef.current && isActive) {
113+
const focus = () => {
114+
setIsActive(true);
115+
props.focusChange && props.focusChange(true);
116+
};
117+
const blur = () => {
118+
setIsActive(false);
119+
props.focusChange && props.focusChange(false);
120+
};
121+
editorRef.current?.onDidFocusEditorText(focus);
122+
editorRef.current?.onDidBlurEditorText(blur);
123+
// 移除监听
124+
// return () => {
125+
// editorRef.current?.removeEventListener('focus', focus);
126+
// editorRef.current?.removeEventListener('blur', blur);
127+
// };
128+
}, []);
129+
130+
131+
useEffect(() => {
132+
if (editorRef.current) {
113133
// eg:
114134
// editor.addCommand(monaco.KeyMod.CtrlCmd | monaco.KeyMod.Shift | monaco.KeyCode.KeyL, () => {
115135
// });
116-
shortcutKey?.(editorRef.current, monaco);
136+
shortcutKey?.(editorRef.current, monaco, isActive);
117137
}
118138
}, [editorRef.current, isActive]);
119139

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
.screeningResult{
2+
display: flex;
3+
align-items: center;
4+
height: 18px;
5+
padding: 4px 0px;
6+
border-bottom: 1px solid var(--color-border);
7+
.whereBox,.orderByBox{
8+
width: 50%;
9+
display: flex;
10+
align-items: center;
11+
height: 100%;
12+
margin: 0px 4px;
13+
.titleBox{
14+
display: flex;
15+
align-items: center;
16+
margin-right: 10px;
17+
width: 70px;
18+
flex-shrink: 0;
19+
}
20+
.titleIcon{
21+
margin-right: 4px;
22+
}
23+
.title{
24+
color: var(--color-text-secondary);
25+
flex-shrink: 0;
26+
font-weight: 500;
27+
}
28+
.activeTitle{
29+
color: var(--color-primary-text);
30+
}
31+
.monacoEditor{
32+
flex: 1;
33+
height: 100%;
34+
width: 0px;
35+
}
36+
}
37+
:global {
38+
.decorationsOverviewRuler{
39+
display: none !important;
40+
}
41+
}
42+
}
Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
import React, { memo, useEffect, useContext } from 'react';
2+
import classnames from 'classnames';
3+
import styles from './index.less';
4+
import Iconfont from '@/components/Iconfont';
5+
import SingleFileMonacoEditor from '@/components/SingleFileMonacoEditor';
6+
import * as monaco from 'monaco-editor/esm/vs/editor/editor.api';
7+
import { IExecuteSqlParams } from '@/service/sql';
8+
import { Context } from '@/components/SearchResult';
9+
10+
interface IProps {
11+
className?: string;
12+
promptWord: any[];
13+
getTableData: (params?: Partial<IExecuteSqlParams>) => void;
14+
}
15+
16+
const keywordHintList = [
17+
'AND',
18+
'OR',
19+
'NOT',
20+
'IS',
21+
'NULL',
22+
'IN',
23+
'IS NOT NULL',
24+
'IS NULL',
25+
'IS NOT',
26+
'NOT IN',
27+
'EXISTS',
28+
'BETWEEN',
29+
'LIKE',
30+
'ASC',
31+
'DESC',
32+
]
33+
34+
export default memo<IProps>((props) => {
35+
const { promptWord, getTableData } = props;
36+
const { notChangedSql } = useContext(Context);
37+
const [isActive, setIsActive] = React.useState(false);
38+
const keywordHintRef = React.useRef<any>(null);
39+
const fieldHintRef = React.useRef<any>(null);
40+
const whereSingleFileMonacoEditorRef = React.useRef<any>(null);
41+
const orderBySingleFileMonacoEditorRef = React.useRef<any>(null);
42+
43+
useEffect(() => {
44+
keywordHintRef.current && keywordHintRef.current.dispose();
45+
fieldHintRef.current && fieldHintRef.current.dispose();
46+
if (isActive) {
47+
registerPromptWord();
48+
}
49+
}, [promptWord, isActive]);
50+
51+
const registerPromptWord = () => {
52+
const suggestions = promptWord.slice(1).map((item) => {
53+
return {
54+
insertText: item.name,
55+
kind: monaco.languages.CompletionItemKind.Field,
56+
label: item.name,
57+
};
58+
});
59+
60+
const provideCompletionItems: any = () => {
61+
return {
62+
suggestions,
63+
};
64+
};
65+
66+
keywordHintRef.current = monaco.languages.registerCompletionItemProvider('sql', {
67+
provideCompletionItems,
68+
triggerCharacters: [],
69+
});
70+
71+
keywordHintRef.current = monaco.languages.registerCompletionItemProvider('sql', {
72+
provideCompletionItems: () => {
73+
return {
74+
suggestions: keywordHintList.map((item) => {
75+
return {
76+
insertText: item,
77+
kind: monaco.languages.CompletionItemKind.Keyword,
78+
label: item,
79+
};
80+
}),
81+
};
82+
},
83+
triggerCharacters: [],
84+
});
85+
};
86+
87+
const search = () => {
88+
const whereValue = whereSingleFileMonacoEditorRef.current?.getAllContent().trim() || '';
89+
const orderByValue = orderBySingleFileMonacoEditorRef.current?.getAllContent().trim() || '';
90+
let sql = whereValue ? notChangedSql + ' WHERE ' + whereValue : notChangedSql;
91+
sql = orderByValue ? sql + ' ORDER BY ' + orderByValue : sql;
92+
getTableData({ sql });
93+
};
94+
95+
const focusChange = (_isActive: boolean) => {
96+
setIsActive(_isActive);
97+
};
98+
99+
return (
100+
<div className={styles.screeningResult}>
101+
<div className={styles.whereBox}>
102+
<div className={styles.titleBox}>
103+
<Iconfont box boxSize={20} classNameBox={styles.titleIcon} code="&#xe66a;" />
104+
<div
105+
className={classnames(styles.title, {
106+
[styles.activeTitle]: true,
107+
})}
108+
>
109+
WHERE
110+
</div>
111+
</div>
112+
<SingleFileMonacoEditor
113+
ref={whereSingleFileMonacoEditorRef}
114+
focusChange={focusChange}
115+
handelEnter={search}
116+
className={styles.monacoEditor}
117+
/>
118+
</div>
119+
<div className={styles.orderByBox}>
120+
<div className={styles.titleBox}>
121+
<Iconfont box boxSize={20} classNameBox={styles.titleIcon} code="&#xe69a;" />
122+
<div
123+
className={classnames(styles.title, {
124+
[styles.activeTitle]: true,
125+
})}
126+
>
127+
ORDER BY
128+
</div>
129+
</div>
130+
<SingleFileMonacoEditor
131+
ref={orderBySingleFileMonacoEditorRef}
132+
focusChange={focusChange}
133+
handelEnter={search}
134+
className={styles.monacoEditor}
135+
/>
136+
</div>
137+
</div>
138+
);
139+
});

0 commit comments

Comments
 (0)