diff --git a/src/platform/packages/shared/shared-ux/code_editor/impl/code_editor.tsx b/src/platform/packages/shared/shared-ux/code_editor/impl/code_editor.tsx index b5476cc9b27e6..6e1ae05fb19c2 100644 --- a/src/platform/packages/shared/shared-ux/code_editor/impl/code_editor.tsx +++ b/src/platform/packages/shared/shared-ux/code_editor/impl/code_editor.tsx @@ -202,6 +202,12 @@ export interface CodeEditorProps { */ onFocus?: () => void; onBlur?: () => void; + + /** + * Enables the suggestion widget repositioning. Enabled by default. + * Disabled for cases like embedded console. + */ + enableSuggestWidgetRepositioning?: boolean; } export const CodeEditor: React.FC = ({ @@ -241,6 +247,7 @@ export const CodeEditor: React.FC = ({ htmlId, onFocus, onBlur, + enableSuggestWidgetRepositioning = true, }) => { const { euiTheme } = useEuiTheme(); const { registerContextMenuActions, unregisterContextMenuActions } = useContextMenuUtils(); @@ -611,7 +618,10 @@ export const CodeEditor: React.FC = ({ ) : null} - + {accessibilityOverlayEnabled && isFullScreen && renderPrompt()} = ({ fontSize: isFullScreen ? 16 : 12, lineHeight: isFullScreen ? 24 : 21, contextmenu: enableCustomContextMenu, - fixedOverflowWidgets: true, + fixedOverflowWidgets: enableSuggestWidgetRepositioning, // @ts-expect-error, see https://github.com/microsoft/monaco-editor/issues/3829 'bracketPairColorization.enabled': false, ...options, @@ -842,8 +852,11 @@ const useFitToContent = ({ * @description See {@link https://github.com/elastic/kibana/issues/223981} for the rationale behind this bug fix implementation */ const UseBug223981FixRepositionSuggestWidget: FC< - PropsWithChildren<{ editor: monaco.editor.IStandaloneCodeEditor | null }> -> = ({ children, editor }) => { + PropsWithChildren<{ + editor: monaco.editor.IStandaloneCodeEditor | null; + enableSuggestWidgetRepositioning: boolean; + }> +> = ({ children, editor, enableSuggestWidgetRepositioning }) => { const { euiTheme } = useEuiTheme(); const suggestWidgetModifierClassName = 'kibanaCodeEditor__suggestWidgetModifier'; @@ -851,9 +864,13 @@ const UseBug223981FixRepositionSuggestWidget: FC< // @ts-expect-errors -- "widget" is not part of the TS interface but does exist const suggestionWidget = editor?.getContribution('editor.contrib.suggestController')?.widget ?.value; - // The "onDidShow" and "onDidHide" is not documented so we guard from possible changes in the underlying lib - if (suggestionWidget && suggestionWidget.onDidShow && suggestionWidget.onDidHide) { + if ( + suggestionWidget && + suggestionWidget.onDidShow && + suggestionWidget.onDidHide && + enableSuggestWidgetRepositioning + ) { let $suggestWidgetNode: HTMLElement | null = null; // add a className that hides the suggestion widget by default so we might be to correctly position the suggestion widget, @@ -879,18 +896,20 @@ const UseBug223981FixRepositionSuggestWidget: FC< } }); } - }, [editor, euiTheme.size.m]); + }, [editor, euiTheme.size.m, enableSuggestWidgetRepositioning]); return ( - + {enableSuggestWidgetRepositioning && ( + + )} {children} ); diff --git a/src/platform/plugins/shared/console/public/application/containers/editor/editor.tsx b/src/platform/plugins/shared/console/public/application/containers/editor/editor.tsx index f06b0acfb80c2..1e960c7b58911 100644 --- a/src/platform/plugins/shared/console/public/application/containers/editor/editor.tsx +++ b/src/platform/plugins/shared/console/public/application/containers/editor/editor.tsx @@ -85,228 +85,232 @@ interface Props { loading: boolean; inputEditorValue: string; setInputEditorValue: (value: string) => void; + enableSuggestWidgetRepositioning: boolean; } -export const Editor = memo(({ loading, inputEditorValue, setInputEditorValue }: Props) => { - const { - services: { storage, objectStorageClient }, - } = useServicesContext(); - const styles = useStyles(); - - const { currentTextObject } = useEditorReadContext(); - - const { - requestInFlight, - lastResult: { data: requestData, error: requestError }, - } = useRequestReadContext(); - - const dispatch = useRequestActionContext(); - const editorDispatch = useEditorActionContext(); - - const [fetchingAutocompleteEntities, setFetchingAutocompleteEntities] = useState(false); - - useEffect(() => { - const debouncedSetFechingAutocompleteEntities = debounce( - setFetchingAutocompleteEntities, - DEBOUNCE_DELAY +export const Editor = memo( + ({ loading, inputEditorValue, setInputEditorValue, enableSuggestWidgetRepositioning }: Props) => { + const { + services: { storage, objectStorageClient }, + } = useServicesContext(); + const styles = useStyles(); + + const { currentTextObject } = useEditorReadContext(); + + const { + requestInFlight, + lastResult: { data: requestData, error: requestError }, + } = useRequestReadContext(); + + const dispatch = useRequestActionContext(); + const editorDispatch = useEditorActionContext(); + + const [fetchingAutocompleteEntities, setFetchingAutocompleteEntities] = useState(false); + + useEffect(() => { + const debouncedSetFechingAutocompleteEntities = debounce( + setFetchingAutocompleteEntities, + DEBOUNCE_DELAY + ); + const subscription = getAutocompleteInfo().isLoading$.subscribe( + debouncedSetFechingAutocompleteEntities + ); + + return () => { + subscription.unsubscribe(); + debouncedSetFechingAutocompleteEntities.cancel(); + }; + }, []); + + const [firstPanelSize, secondPanelSize] = storage.get(StorageKeys.SIZE, [ + INITIAL_PANEL_SIZE, + INITIAL_PANEL_SIZE, + ]); + + const isVerticalLayout = useIsWithinBreakpoints(['xs', 's', 'm']); + + /* eslint-disable-next-line react-hooks/exhaustive-deps */ + const onPanelSizeChange = useCallback( + debounce((sizes) => { + storage.set(StorageKeys.SIZE, Object.values(sizes)); + }, 300), + [] ); - const subscription = getAutocompleteInfo().isLoading$.subscribe( - debouncedSetFechingAutocompleteEntities + + /* eslint-disable-next-line react-hooks/exhaustive-deps */ + const debouncedUpdateLocalStorageValue = useCallback( + debounce((newValue: string | undefined) => { + const textObject = { + ...currentTextObject, + text: newValue, + updatedAt: Date.now(), + } as TextObject; + + objectStorageClient.text.update(textObject); + + editorDispatch({ + type: 'setCurrentTextObject', + payload: textObject, + }); + }, DEBOUNCE_DELAY), + [] ); - return () => { - subscription.unsubscribe(); - debouncedSetFechingAutocompleteEntities.cancel(); - }; - }, []); - - const [firstPanelSize, secondPanelSize] = storage.get(StorageKeys.SIZE, [ - INITIAL_PANEL_SIZE, - INITIAL_PANEL_SIZE, - ]); - - const isVerticalLayout = useIsWithinBreakpoints(['xs', 's', 'm']); - - /* eslint-disable-next-line react-hooks/exhaustive-deps */ - const onPanelSizeChange = useCallback( - debounce((sizes) => { - storage.set(StorageKeys.SIZE, Object.values(sizes)); - }, 300), - [] - ); - - /* eslint-disable-next-line react-hooks/exhaustive-deps */ - const debouncedUpdateLocalStorageValue = useCallback( - debounce((newValue: string | undefined) => { - const textObject = { - ...currentTextObject, - text: newValue, - updatedAt: Date.now(), - } as TextObject; - - objectStorageClient.text.update(textObject); - - editorDispatch({ - type: 'setCurrentTextObject', - payload: textObject, - }); - }, DEBOUNCE_DELAY), - [] - ); - - // Always keep the localstorage value in sync with the value in the editor - // to avoid losing the text object when the user navigates away from the shell - useEffect(() => { - debouncedUpdateLocalStorageValue(inputEditorValue); - }, [debouncedUpdateLocalStorageValue, inputEditorValue]); - - if (!currentTextObject) return null; - - const data = getResponseWithMostSevereStatusCode(requestData) ?? requestError; - const isLoading = loading || requestInFlight; - - return ( - <> - {fetchingAutocompleteEntities ? ( -
- -
- ) : null} - onPanelSizeChange(sizes)} - data-test-subj="consoleEditorContainer" - > - {(EuiResizablePanel, EuiResizableButton) => ( - <> - - { + debouncedUpdateLocalStorageValue(inputEditorValue); + }, [debouncedUpdateLocalStorageValue, inputEditorValue]); + + if (!currentTextObject) return null; + + const data = getResponseWithMostSevereStatusCode(requestData) ?? requestError; + const isLoading = loading || requestInFlight; + + return ( + <> + {fetchingAutocompleteEntities ? ( +
+ +
+ ) : null} + onPanelSizeChange(sizes)} + data-test-subj="consoleEditorContainer" + > + {(EuiResizablePanel, EuiResizableButton) => ( + <> + - - {loading ? ( - - ) : ( - - )} - - - {!loading && ( - { - setInputEditorValue(''); - }} - > - {i18n.translate('console.editor.clearConsoleInputButton', { - defaultMessage: 'Clear this input', - })} - + {loading ? ( + + ) : ( + + )} - )} -
-
- - - - - + { + setInputEditorValue(''); + }} + > + {i18n.translate('console.editor.clearConsoleInputButton', { + defaultMessage: 'Clear this input', + })} + + + )} + + + + + + - - {data ? ( - - ) : isLoading ? ( - - ) : ( - - )} - - - {(data || isLoading) && ( - - - dispatch({ type: 'cleanRequest', payload: undefined })} - > - {i18n.translate('console.editor.clearConsoleOutputButton', { - defaultMessage: 'Clear this output', - })} - - - - - - - + {data ? ( + + ) : isLoading ? ( + + ) : ( + + )} - )} - - - - )} -
- - ); -}); + + {(data || isLoading) && ( + + + + dispatch({ type: 'cleanRequest', payload: undefined })} + > + {i18n.translate('console.editor.clearConsoleOutputButton', { + defaultMessage: 'Clear this output', + })} + + + + + + + + + )} + + + + )} + + + ); + } +); diff --git a/src/platform/plugins/shared/console/public/application/containers/editor/monaco_editor.tsx b/src/platform/plugins/shared/console/public/application/containers/editor/monaco_editor.tsx index 5f866487f8425..0de4fe0baf13b 100644 --- a/src/platform/plugins/shared/console/public/application/containers/editor/monaco_editor.tsx +++ b/src/platform/plugins/shared/console/public/application/containers/editor/monaco_editor.tsx @@ -56,9 +56,15 @@ export interface EditorProps { localStorageValue: string | undefined; value: string; setValue: (value: string) => void; + enableSuggestWidgetRepositioning: boolean; } -export const MonacoEditor = ({ localStorageValue, value, setValue }: EditorProps) => { +export const MonacoEditor = ({ + localStorageValue, + value, + setValue, + enableSuggestWidgetRepositioning, +}: EditorProps) => { const context = useServicesContext(); const { services: { @@ -294,6 +300,7 @@ export const MonacoEditor = ({ localStorageValue, value, setValue }: EditorProps suggestionProvider={suggestionProvider} enableFindAction={true} enableCustomContextMenu={true} + enableSuggestWidgetRepositioning={enableSuggestWidgetRepositioning} /> ); diff --git a/src/platform/plugins/shared/console/public/application/containers/main/main.tsx b/src/platform/plugins/shared/console/public/application/containers/main/main.tsx index f0a9d1aa98b2f..15a247a06776d 100644 --- a/src/platform/plugins/shared/console/public/application/containers/main/main.tsx +++ b/src/platform/plugins/shared/console/public/application/containers/main/main.tsx @@ -361,6 +361,7 @@ export function Main({ currentTabProp, isEmbeddable = false }: MainProps) { loading={!done} inputEditorValue={inputEditorValue} setInputEditorValue={setInputEditorValue} + enableSuggestWidgetRepositioning={!isEmbeddable} /> )} {currentTab === HISTORY_TAB_ID && }