diff --git a/querybook/config/user_setting.yaml b/querybook/config/user_setting.yaml index 20d62ee50..7ea95eb5f 100644 --- a/querybook/config/user_setting.yaml +++ b/querybook/config/user_setting.yaml @@ -50,6 +50,14 @@ show_full_view: - disabled helper: Instead of modal, show full view when opening table/execution/snippet +query_suggestions: + default: disabled + tab: editor + options: + - enabled + - disabled + helper: (Experimental) Enable to receive inline AI generated query suggestions as you type from within the editor. + editor_font_size: default: medium tab: editor diff --git a/querybook/webapp/components/QueryEditor/BoundQueryEditor.tsx b/querybook/webapp/components/QueryEditor/BoundQueryEditor.tsx index 708a80ee1..830ca3de9 100644 --- a/querybook/webapp/components/QueryEditor/BoundQueryEditor.tsx +++ b/querybook/webapp/components/QueryEditor/BoundQueryEditor.tsx @@ -49,8 +49,14 @@ export const BoundQueryEditor = React.forwardRef< const editorRef = useForwardedRef(ref); // Code Editor related Props - const { codeEditorTheme, keyMap, options, fontSize, autoCompleteType } = - useUserQueryEditorConfig(searchContext); + const { + codeEditorTheme, + keyMap, + options, + fontSize, + autoCompleteType, + queryAISuggestionsEnabled, + } = useUserQueryEditorConfig(searchContext); const combinedOptions = useMemo( () => ({ ...options, @@ -103,6 +109,7 @@ export const BoundQueryEditor = React.forwardRef< theme={codeEditorTheme} autoCompleteType={autoCompleteType} fontSize={fontSize} + queryAISuggestionsEnabled={queryAISuggestionsEnabled} getTableByName={fetchDataTable} functionDocumentationByNameByLanguage={ functionDocumentationByNameByLanguage diff --git a/querybook/webapp/components/QueryEditor/QueryEditor.tsx b/querybook/webapp/components/QueryEditor/QueryEditor.tsx index 4510c7298..966ffc666 100644 --- a/querybook/webapp/components/QueryEditor/QueryEditor.tsx +++ b/querybook/webapp/components/QueryEditor/QueryEditor.tsx @@ -57,6 +57,7 @@ export interface IQueryEditorProps extends IStyledQueryEditorProps { keyMap?: CodeMirrorKeyMap; className?: string; autoCompleteType?: AutoCompleteType; + queryAISuggestionsEnabled?: boolean; /** * If provided, then the container component will handle the fullscreen logic @@ -115,6 +116,7 @@ export const QueryEditor: React.FC< keyMap = {}, className, autoCompleteType = 'all', + queryAISuggestionsEnabled, onFullScreen, onChange, @@ -617,16 +619,24 @@ export const QueryEditor: React.FC< onTextHover, ]); - const editorDidMount = useCallback((editor: CodeMirror.Editor) => { - editorRef.current = editor; + const editorDidMount = useCallback( + (editor: CodeMirror.Editor) => { + editorRef.current = editor; - // There is a strange bug where codemirror would start with the wrong height (on Execs tab) - // which can only be solved by clicking on it - // The current work around is to add refresh on mount - setTimeout(() => { - editor.refresh(); - }, 50); - }, []); + if (queryAISuggestionsEnabled) { + // Enable query ai suggestion feature + editor.queryAISuggestions(); + } + + // There is a strange bug where codemirror would start with the wrong height (on Execs tab) + // which can only be solved by clicking on it + // The current work around is to add refresh on mount + setTimeout(() => { + editor.refresh(); + }, 50); + }, + [queryAISuggestionsEnabled] + ); const onBeforeChange = useCallback( (editor: CodeMirror.Editor, data, value: string) => { diff --git a/querybook/webapp/hooks/redux/useUserQueryEditorConfig.ts b/querybook/webapp/hooks/redux/useUserQueryEditorConfig.ts index 0572db33c..dc280c4fa 100644 --- a/querybook/webapp/hooks/redux/useUserQueryEditorConfig.ts +++ b/querybook/webapp/hooks/redux/useUserQueryEditorConfig.ts @@ -17,6 +17,7 @@ export function useUserQueryEditorConfig( keyMap: CodeMirrorKeyMap; options: CodeMirror.EditorConfiguration; autoCompleteType: AutoCompleteType; + queryAISuggestionsEnabled: boolean; } { const editorSettings = useShallowSelector((state: IStoreState) => ({ theme: getCodeEditorTheme(state.user.computedSettings['theme']), @@ -26,6 +27,8 @@ export function useUserQueryEditorConfig( ], autoComplete: state.user.computedSettings['auto_complete'], tab: state.user.computedSettings['tab'], + queryAISuggestionsEnabled: + state.user.computedSettings['query_suggestions'] === 'enabled', })); const indentWithTabs = editorSettings.tab === 'tab'; const tabSize = @@ -106,5 +109,6 @@ export function useUserQueryEditorConfig( // From: https://github.com/codemirror/CodeMirror/issues/988 keyMap, options, + queryAISuggestionsEnabled: editorSettings.queryAISuggestionsEnabled, }; } diff --git a/querybook/webapp/lib/codemirror/codemirror-copilot.ts b/querybook/webapp/lib/codemirror/codemirror-copilot.ts new file mode 100644 index 000000000..2f7fb404b --- /dev/null +++ b/querybook/webapp/lib/codemirror/codemirror-copilot.ts @@ -0,0 +1,9 @@ +import CodeMirror from 'codemirror'; + +CodeMirror.defineExtension('queryAISuggestions', function () { + this.on('keyup', async (editor, event) => { + if (event.code === 'Space') { + console.log('CodeMirror Query Suggestions Extension'); + } + }); +}); diff --git a/querybook/webapp/lib/codemirror/index.ts b/querybook/webapp/lib/codemirror/index.ts index e4b530c67..f63fd573a 100644 --- a/querybook/webapp/lib/codemirror/index.ts +++ b/querybook/webapp/lib/codemirror/index.ts @@ -18,14 +18,15 @@ import 'codemirror/addon/runmode/runmode'; // Search highlighting import 'codemirror/addon/search/match-highlighter.js'; import 'codemirror/lib/codemirror.css'; +import 'codemirror/mode/jinja2/jinja2'; // From codemirror non-react package: import 'codemirror/mode/sql/sql'; -import 'codemirror/mode/jinja2/jinja2'; - import 'codemirror/theme/duotone-light.css'; import 'codemirror/theme/material-palenight.css'; import 'codemirror/theme/monokai.css'; import 'codemirror/theme/solarized.css'; +// Query AI Suggestions +import 'lib/codemirror/codemirror-copilot'; // This should apply the hover option to codemirror import 'lib/codemirror/codemirror-hover'; @@ -33,6 +34,9 @@ import 'lib/codemirror/codemirror-hover'; import './editor_styles.scss'; declare module 'codemirror' { + interface Editor { + queryAISuggestions(): void; + } // This is copied from runmode.d.ts. Not sure how to import it :( function runMode( text: string,