From ae97fda5f23848fd8a5c5c3a33b940b175af92bf Mon Sep 17 00:00:00 2001 From: Anton Standrik Date: Mon, 10 Feb 2025 18:06:12 +0300 Subject: [PATCH 1/7] fix: code assistant option --- src/containers/UserSettings/i18n/en.json | 3 +++ src/containers/UserSettings/settings.tsx | 22 ++++++++++++++++++++-- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/src/containers/UserSettings/i18n/en.json b/src/containers/UserSettings/i18n/en.json index 541c692b5..c4cd42f89 100644 --- a/src/containers/UserSettings/i18n/en.json +++ b/src/containers/UserSettings/i18n/en.json @@ -14,6 +14,9 @@ "settings.editor.autocomplete.title": "Enable autocomplete", "settings.editor.autocomplete.description": "You're always able to get suggestions by pressing Ctrl+Space.", + "settings.editor.codeAssistant.title": "Code Assistant", + "settings.editor.codeAssistant.description": "Use Code Assistant for autocomplete.", + "settings.editor.autocomplete-on-enter.title": "Accept suggestion on Enter", "settings.editor.autocomplete-on-enter.description": "Controls whether suggestions should be accepted on Enter, in addition to Tab. Helps to avoid ambiguity between inserting new lines or accepting suggestions.", diff --git a/src/containers/UserSettings/settings.tsx b/src/containers/UserSettings/settings.tsx index eccf42e40..4036a3f88 100644 --- a/src/containers/UserSettings/settings.tsx +++ b/src/containers/UserSettings/settings.tsx @@ -120,6 +120,12 @@ export const enableAutocompleteSetting: SettingProps = { description: i18n('settings.editor.autocomplete.description'), }; +export const enableCodeAssistantSetting: SettingProps = { + settingKey: ENABLE_AUTOCOMPLETE, + title: i18n('settings.editor.codeAssistant.title'), + description: i18n('settings.editor.codeAssistant.description'), +}; + export const autocompleteOnEnterSetting: SettingProps = { settingKey: AUTOCOMPLETE_ON_ENTER, title: i18n('settings.editor.autocomplete-on-enter.title'), @@ -192,14 +198,26 @@ export const aboutPage: SettingsPage = { showTitle: false, }; -export function getUserSettings({singleClusterMode}: {singleClusterMode: boolean}) { +export function getUserSettings({ + singleClusterMode, + inlineCompletionsConfigured, +}: { + singleClusterMode: boolean; + inlineCompletionsConfigured?: boolean; +}) { const experiments = singleClusterMode ? experimentsPage : createNextState(experimentsPage, (draft) => { draft.sections[0].settings.push(useClusterBalancerAsBackendSetting); }); - const settings: YDBEmbeddedUISettings = [generalPage, editorPage, experiments, aboutPage]; + const editor = inlineCompletionsConfigured + ? editorPage + : createNextState(editorPage, (draft) => { + draft.sections[0].settings.push(enableAutocompleteSetting); + }); + + const settings: YDBEmbeddedUISettings = [generalPage, editor, experiments, aboutPage]; return settings; } From f784bf7c103d3b463a87b95cc75169fc0d9a0c43 Mon Sep 17 00:00:00 2001 From: Anton Standrik Date: Mon, 10 Feb 2025 18:11:09 +0300 Subject: [PATCH 2/7] fix: add usage --- src/containers/Tenant/Query/QueryEditor/YqlEditor.tsx | 5 +++-- src/containers/UserSettings/settings.tsx | 5 +++-- src/services/settings.ts | 2 ++ src/utils/constants.ts | 2 ++ 4 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/containers/Tenant/Query/QueryEditor/YqlEditor.tsx b/src/containers/Tenant/Query/QueryEditor/YqlEditor.tsx index ae6fb2223..f4fd85527 100644 --- a/src/containers/Tenant/Query/QueryEditor/YqlEditor.tsx +++ b/src/containers/Tenant/Query/QueryEditor/YqlEditor.tsx @@ -11,7 +11,7 @@ import { selectUserInput, } from '../../../../store/reducers/query/query'; import type {QueryAction} from '../../../../types/store/query'; -import {LAST_USED_QUERY_ACTION_KEY} from '../../../../utils/constants'; +import {ENABLE_CODE_ASSISTANT, LAST_USED_QUERY_ACTION_KEY} from '../../../../utils/constants'; import { useEventHandler, useSetting, @@ -44,6 +44,7 @@ export function YqlEditor({ handleGetExplainQueryClick, }: YqlEditorProps) { const input = useTypedSelector(selectUserInput); + const isCodeAssistEnabled = useSetting(ENABLE_CODE_ASSISTANT); const dispatch = useTypedDispatch(); const historyQueries = useTypedSelector(selectQueriesHistory); const savedQueries = useSavedQueries(); @@ -99,7 +100,7 @@ export function YqlEditor({ } }); - if (window.api.codeAssist) { + if (window.api.codeAssist && isCodeAssistEnabled) { registerMonacoGhost(editor); codeAssist.prepareUserQueriesCache([ ...historyQueries.map((query, index) => ({ diff --git a/src/containers/UserSettings/settings.tsx b/src/containers/UserSettings/settings.tsx index 4036a3f88..367ebcf50 100644 --- a/src/containers/UserSettings/settings.tsx +++ b/src/containers/UserSettings/settings.tsx @@ -6,6 +6,7 @@ import { AUTOCOMPLETE_ON_ENTER, BINARY_DATA_IN_PLAIN_TEXT_DISPLAY, ENABLE_AUTOCOMPLETE, + ENABLE_CODE_ASSISTANT, ENABLE_NETWORK_TABLE_KEY, INVERTED_DISKS_KEY, LANGUAGE_KEY, @@ -121,7 +122,7 @@ export const enableAutocompleteSetting: SettingProps = { }; export const enableCodeAssistantSetting: SettingProps = { - settingKey: ENABLE_AUTOCOMPLETE, + settingKey: ENABLE_CODE_ASSISTANT, title: i18n('settings.editor.codeAssistant.title'), description: i18n('settings.editor.codeAssistant.description'), }; @@ -214,7 +215,7 @@ export function getUserSettings({ const editor = inlineCompletionsConfigured ? editorPage : createNextState(editorPage, (draft) => { - draft.sections[0].settings.push(enableAutocompleteSetting); + draft.sections[0].settings.push(enableCodeAssistantSetting); }); const settings: YDBEmbeddedUISettings = [generalPage, editor, experiments, aboutPage]; diff --git a/src/services/settings.ts b/src/services/settings.ts index 2f8855888..5ecc68a2e 100644 --- a/src/services/settings.ts +++ b/src/services/settings.ts @@ -6,6 +6,7 @@ import { BINARY_DATA_IN_PLAIN_TEXT_DISPLAY, CASE_SENSITIVE_JSON_SEARCH, ENABLE_AUTOCOMPLETE, + ENABLE_CODE_ASSISTANT, ENABLE_NETWORK_TABLE_KEY, INVERTED_DISKS_KEY, IS_HOTKEYS_HELP_HIDDEN_KEY, @@ -42,6 +43,7 @@ export const DEFAULT_USER_SETTINGS = { [USE_SHOW_PLAN_SVG_KEY]: false, [USE_CLUSTER_BALANCER_AS_BACKEND_KEY]: true, [ENABLE_AUTOCOMPLETE]: true, + [ENABLE_CODE_ASSISTANT]: false, [AUTOCOMPLETE_ON_ENTER]: true, [IS_HOTKEYS_HELP_HIDDEN_KEY]: false, [AUTO_REFRESH_INTERVAL]: 0, diff --git a/src/utils/constants.ts b/src/utils/constants.ts index 4772624cf..70e3bdb76 100644 --- a/src/utils/constants.ts +++ b/src/utils/constants.ts @@ -117,6 +117,8 @@ export const USE_CLUSTER_BALANCER_AS_BACKEND_KEY = 'useClusterBalancerAsBacked'; export const ENABLE_AUTOCOMPLETE = 'enableAutocomplete'; +export const ENABLE_CODE_ASSISTANT = 'enableCodeAssistant'; + export const AUTOCOMPLETE_ON_ENTER = 'autocompleteOnEnter'; export const IS_HOTKEYS_HELP_HIDDEN_KEY = 'isHotKeysHelpHidden'; From fc6ff3f8519b7eba5f615e35824b5ca1be77280a Mon Sep 17 00:00:00 2001 From: Anton Standrik Date: Mon, 10 Feb 2025 18:12:39 +0300 Subject: [PATCH 3/7] fix: better naming --- src/containers/UserSettings/settings.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/containers/UserSettings/settings.tsx b/src/containers/UserSettings/settings.tsx index 367ebcf50..cbb2d7988 100644 --- a/src/containers/UserSettings/settings.tsx +++ b/src/containers/UserSettings/settings.tsx @@ -201,10 +201,10 @@ export const aboutPage: SettingsPage = { export function getUserSettings({ singleClusterMode, - inlineCompletionsConfigured, + codeAssistantConfigured, }: { singleClusterMode: boolean; - inlineCompletionsConfigured?: boolean; + codeAssistantConfigured?: boolean; }) { const experiments = singleClusterMode ? experimentsPage @@ -212,7 +212,7 @@ export function getUserSettings({ draft.sections[0].settings.push(useClusterBalancerAsBackendSetting); }); - const editor = inlineCompletionsConfigured + const editor = codeAssistantConfigured ? editorPage : createNextState(editorPage, (draft) => { draft.sections[0].settings.push(enableCodeAssistantSetting); From 30f1b2385c3000035936edb00f68fbe434c00b37 Mon Sep 17 00:00:00 2001 From: Anton Standrik Date: Mon, 10 Feb 2025 18:14:03 +0300 Subject: [PATCH 4/7] fix: default true --- src/services/settings.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/services/settings.ts b/src/services/settings.ts index 5ecc68a2e..6e34f0269 100644 --- a/src/services/settings.ts +++ b/src/services/settings.ts @@ -43,7 +43,7 @@ export const DEFAULT_USER_SETTINGS = { [USE_SHOW_PLAN_SVG_KEY]: false, [USE_CLUSTER_BALANCER_AS_BACKEND_KEY]: true, [ENABLE_AUTOCOMPLETE]: true, - [ENABLE_CODE_ASSISTANT]: false, + [ENABLE_CODE_ASSISTANT]: true, [AUTOCOMPLETE_ON_ENTER]: true, [IS_HOTKEYS_HELP_HIDDEN_KEY]: false, [AUTO_REFRESH_INTERVAL]: 0, From 97af66fa361060bf36ead3928b9151b0fae52db7 Mon Sep 17 00:00:00 2001 From: Anton Standrik Date: Mon, 10 Feb 2025 18:15:59 +0300 Subject: [PATCH 5/7] fix: condition --- src/containers/UserSettings/settings.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/containers/UserSettings/settings.tsx b/src/containers/UserSettings/settings.tsx index cbb2d7988..0dd0344e4 100644 --- a/src/containers/UserSettings/settings.tsx +++ b/src/containers/UserSettings/settings.tsx @@ -213,10 +213,10 @@ export function getUserSettings({ }); const editor = codeAssistantConfigured - ? editorPage - : createNextState(editorPage, (draft) => { + ? createNextState(editorPage, (draft) => { draft.sections[0].settings.push(enableCodeAssistantSetting); - }); + }) + : editorPage; const settings: YDBEmbeddedUISettings = [generalPage, editor, experiments, aboutPage]; From aafff9495c42b93e8c0e1b1f2b9aab67d26f3825 Mon Sep 17 00:00:00 2001 From: Anton Standrik Date: Tue, 11 Feb 2025 01:48:41 +0300 Subject: [PATCH 6/7] fix: use instance instead of hook --- package-lock.json | 8 +-- package.json | 2 +- .../Tenant/Query/QueryEditor/YqlEditor.tsx | 55 +++++++-------- .../Tenant/Query/QueryEditor/helpers.ts | 68 +++++++++++++------ 4 files changed, 76 insertions(+), 57 deletions(-) diff --git a/package-lock.json b/package-lock.json index 26b88bbbc..a8d4b2b10 100644 --- a/package-lock.json +++ b/package-lock.json @@ -26,7 +26,7 @@ "@hookform/resolvers": "^3.10.0", "@reduxjs/toolkit": "^2.5.0", "@tanstack/react-table": "^8.20.6", - "@ydb-platform/monaco-ghost": "^0.4.0", + "@ydb-platform/monaco-ghost": "^0.6.1", "axios": "^1.7.9", "axios-retry": "^4.5.0", "colord": "^2.9.3", @@ -6417,9 +6417,9 @@ "dev": true }, "node_modules/@ydb-platform/monaco-ghost": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/@ydb-platform/monaco-ghost/-/monaco-ghost-0.4.0.tgz", - "integrity": "sha512-yOgfQ7PUIPKmTqpOaKtGLc2gDQAzp3z2jASGLB7IAhC8smdDLoLwtNMz30gKkzU29TnICfp6Eem5fxj6nKqmrQ==", + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/@ydb-platform/monaco-ghost/-/monaco-ghost-0.6.1.tgz", + "integrity": "sha512-BrqRDYQRFIaRHtvHBEesq0ExLM6Az51bk11YG2jIJZ3d9quRx3t+AT3dE6bdlbZqR+jtNGRaC1xfc8IQs0cc4A==", "license": "Apache-2.0", "dependencies": { "uuid": "^9.0.0" diff --git a/package.json b/package.json index ae14682ac..554b5ed38 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,7 @@ "@hookform/resolvers": "^3.10.0", "@reduxjs/toolkit": "^2.5.0", "@tanstack/react-table": "^8.20.6", - "@ydb-platform/monaco-ghost": "^0.4.0", + "@ydb-platform/monaco-ghost": "^0.6.1", "axios": "^1.7.9", "axios-retry": "^4.5.0", "colord": "^2.9.3", diff --git a/src/containers/Tenant/Query/QueryEditor/YqlEditor.tsx b/src/containers/Tenant/Query/QueryEditor/YqlEditor.tsx index f4fd85527..af80fa31e 100644 --- a/src/containers/Tenant/Query/QueryEditor/YqlEditor.tsx +++ b/src/containers/Tenant/Query/QueryEditor/YqlEditor.tsx @@ -1,5 +1,7 @@ +import React from 'react'; + import NiceModal from '@ebay/nice-modal-react'; -import {useMonacoGhost} from '@ydb-platform/monaco-ghost'; +import {createMonacoGhostInstance} from '@ydb-platform/monaco-ghost'; import throttle from 'lodash/throttle'; import type Monaco from 'monaco-editor'; @@ -23,9 +25,8 @@ import {useUpdateErrorsHighlighting} from '../../../../utils/monaco/highlightErr import {QUERY_ACTIONS} from '../../../../utils/query'; import {SAVE_QUERY_DIALOG} from '../SaveQuery/SaveQuery'; import i18n from '../i18n'; -import {useSavedQueries} from '../utils/useSavedQueries'; -import {useCodeAssist, useEditorOptions} from './helpers'; +import {useCodeAssistHelpers, useEditorOptions} from './helpers'; import {getKeyBindings} from './keybindings'; const CONTEXT_MENU_GROUP_ID = 'navigation'; @@ -44,10 +45,11 @@ export function YqlEditor({ handleGetExplainQueryClick, }: YqlEditorProps) { const input = useTypedSelector(selectUserInput); - const isCodeAssistEnabled = useSetting(ENABLE_CODE_ASSISTANT); const dispatch = useTypedDispatch(); + const monacoGhostInstanceRef = React.useRef>(); const historyQueries = useTypedSelector(selectQueriesHistory); - const savedQueries = useSavedQueries(); + const [isCodeAssistEnabled] = useSetting(ENABLE_CODE_ASSISTANT); + const editorOptions = useEditorOptions(); const updateErrorsHighlighting = useUpdateErrorsHighlighting(); @@ -72,20 +74,21 @@ export function YqlEditor({ window.ydbEditor = undefined; }; - const codeAssist = useCodeAssist(); - const {registerMonacoGhost} = useMonacoGhost({ - api: { - getCodeAssistSuggestions: codeAssist.getCodeAssistSuggestions, - }, - eventHandlers: { - onCompletionAccept: codeAssist.onCompletionAccept, - onCompletionDecline: codeAssist.onCompletionDecline, - onCompletionIgnore: codeAssist.onCompletionIgnore, - }, - config: { - language: YQL_LANGUAGE_ID, - }, - }); + const {monacoGhostConfig, prepareUserQueriesCache} = useCodeAssistHelpers(); + + React.useEffect(() => { + if (monacoGhostInstanceRef.current && window.api.codeAssist) { + if (isCodeAssistEnabled) { + monacoGhostInstanceRef.current.register(monacoGhostConfig); + prepareUserQueriesCache(); + } else { + monacoGhostInstanceRef.current.unregister(); + } + } + return () => { + monacoGhostInstanceRef.current?.unregister(); + }; + }, [isCodeAssistEnabled, monacoGhostConfig, prepareUserQueriesCache]); const editorDidMount = (editor: Monaco.editor.IStandaloneCodeEditor, monaco: typeof Monaco) => { window.ydbEditor = editor; @@ -100,19 +103,7 @@ export function YqlEditor({ } }); - if (window.api.codeAssist && isCodeAssistEnabled) { - registerMonacoGhost(editor); - codeAssist.prepareUserQueriesCache([ - ...historyQueries.map((query, index) => ({ - name: `query${index}.yql`, - text: query.queryText, - })), - ...savedQueries.map((query) => ({ - name: query.name, - text: query.body, - })), - ]); - } + monacoGhostInstanceRef.current = createMonacoGhostInstance(editor); initResizeHandler(editor); initUserPrompt(editor, getLastQueryText); editor.focus(); diff --git a/src/containers/Tenant/Query/QueryEditor/helpers.ts b/src/containers/Tenant/Query/QueryEditor/helpers.ts index c4ebb5d23..34c000958 100644 --- a/src/containers/Tenant/Query/QueryEditor/helpers.ts +++ b/src/containers/Tenant/Query/QueryEditor/helpers.ts @@ -4,9 +4,12 @@ import type {AcceptEvent, DeclineEvent, IgnoreEvent, PromptFile} from '@ydb-plat import type Monaco from 'monaco-editor'; import {codeAssistApi} from '../../../../store/reducers/codeAssist/codeAssist'; +import {selectQueriesHistory} from '../../../../store/reducers/query/query'; import type {TelemetryOpenTabs} from '../../../../types/api/codeAssist'; import {AUTOCOMPLETE_ON_ENTER, ENABLE_AUTOCOMPLETE} from '../../../../utils/constants'; -import {useSetting} from '../../../../utils/hooks'; +import {useSetting, useTypedSelector} from '../../../../utils/hooks'; +import {YQL_LANGUAGE_ID} from '../../../../utils/monaco/constats'; +import {useSavedQueries} from '../utils/useSavedQueries'; export type EditorOptions = Monaco.editor.IEditorOptions & Monaco.editor.IGlobalEditorOptions; @@ -36,12 +39,14 @@ export function useEditorOptions() { return options; } -export function useCodeAssist() { +export function useCodeAssistHelpers() { const [sendCodeAssistPrompt] = codeAssistApi.useLazyGetCodeAssistSuggestionsQuery(); const [acceptSuggestion] = codeAssistApi.useAcceptSuggestionMutation(); const [discardSuggestion] = codeAssistApi.useDiscardSuggestionMutation(); const [ignoreSuggestion] = codeAssistApi.useIgnoreSuggestionMutation(); const [sendUserQueriesData] = codeAssistApi.useSendUserQueriesDataMutation(); + const historyQueries = useTypedSelector(selectQueriesHistory); + const savedQueries = useSavedQueries(); const getCodeAssistSuggestions = React.useCallback( async (promptFiles: PromptFile[]) => sendCodeAssistPrompt(promptFiles).unwrap(), @@ -63,26 +68,49 @@ export function useCodeAssist() { [ignoreSuggestion], ); - const prepareUserQueriesCache = React.useCallback( - async (queries: {text: string; name?: string}[]) => { - const preparedData: TelemetryOpenTabs = queries.map((query, index) => ({ - FileName: query.name || `query${index}.yql`, - Text: query.text, - })); - try { - return sendUserQueriesData(preparedData).unwrap(); - } catch { - return {items: []}; - } - }, - [sendUserQueriesData], - ); + const userQueries = React.useMemo(() => { + return [ + ...historyQueries.map((query, index) => ({ + name: `query${index}.yql`, + text: query.queryText, + })), + ...savedQueries.map((query) => ({ + name: query.name, + text: query.body, + })), + ]; + }, [historyQueries, savedQueries]); + + const prepareUserQueriesCache = React.useCallback(async () => { + const preparedData: TelemetryOpenTabs = userQueries.map((query, index) => ({ + FileName: query.name || `query${index}.yql`, + Text: query.text, + })); + try { + return await sendUserQueriesData(preparedData).unwrap(); + } catch { + return {items: []}; + } + }, [sendUserQueriesData, userQueries]); + + const monacoGhostConfig = React.useMemo(() => { + return { + api: { + getCodeAssistSuggestions, + }, + eventHandlers: { + onCompletionAccept, + onCompletionDecline, + onCompletionIgnore, + }, + config: { + language: YQL_LANGUAGE_ID, + }, + }; + }, [getCodeAssistSuggestions, onCompletionAccept, onCompletionDecline, onCompletionIgnore]); return { - getCodeAssistSuggestions, - onCompletionAccept, - onCompletionDecline, - onCompletionIgnore, prepareUserQueriesCache, + monacoGhostConfig, }; } From 48e7356bffaeee8acc433d98e2f33437f2da0115 Mon Sep 17 00:00:00 2001 From: Anton Standrik Date: Tue, 11 Feb 2025 02:09:17 +0300 Subject: [PATCH 7/7] fix: better code --- .../Tenant/Query/QueryEditor/YqlEditor.tsx | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/containers/Tenant/Query/QueryEditor/YqlEditor.tsx b/src/containers/Tenant/Query/QueryEditor/YqlEditor.tsx index af80fa31e..344107a56 100644 --- a/src/containers/Tenant/Query/QueryEditor/YqlEditor.tsx +++ b/src/containers/Tenant/Query/QueryEditor/YqlEditor.tsx @@ -46,7 +46,8 @@ export function YqlEditor({ }: YqlEditorProps) { const input = useTypedSelector(selectUserInput); const dispatch = useTypedDispatch(); - const monacoGhostInstanceRef = React.useRef>(); + const [monacoGhostInstance, setMonacoGhostInstance] = + React.useState>(); const historyQueries = useTypedSelector(selectQueriesHistory); const [isCodeAssistEnabled] = useSetting(ENABLE_CODE_ASSISTANT); @@ -77,18 +78,15 @@ export function YqlEditor({ const {monacoGhostConfig, prepareUserQueriesCache} = useCodeAssistHelpers(); React.useEffect(() => { - if (monacoGhostInstanceRef.current && window.api.codeAssist) { - if (isCodeAssistEnabled) { - monacoGhostInstanceRef.current.register(monacoGhostConfig); - prepareUserQueriesCache(); - } else { - monacoGhostInstanceRef.current.unregister(); - } + if (monacoGhostInstance && isCodeAssistEnabled) { + monacoGhostInstance.register(monacoGhostConfig); + prepareUserQueriesCache(); } + return () => { - monacoGhostInstanceRef.current?.unregister(); + monacoGhostInstance?.unregister(); }; - }, [isCodeAssistEnabled, monacoGhostConfig, prepareUserQueriesCache]); + }, [isCodeAssistEnabled, monacoGhostConfig, monacoGhostInstance, prepareUserQueriesCache]); const editorDidMount = (editor: Monaco.editor.IStandaloneCodeEditor, monaco: typeof Monaco) => { window.ydbEditor = editor; @@ -103,7 +101,10 @@ export function YqlEditor({ } }); - monacoGhostInstanceRef.current = createMonacoGhostInstance(editor); + if (window.api.codeAssist) { + setMonacoGhostInstance(createMonacoGhostInstance(editor)); + } + initResizeHandler(editor); initUserPrompt(editor, getLastQueryText); editor.focus();