From f1529096e92b4b182b25a4891da6bbaece7d5e56 Mon Sep 17 00:00:00 2001 From: Elena Stoeva Date: Wed, 18 Sep 2024 14:34:06 +0100 Subject: [PATCH 1/6] [Console] Fix editor value resetting at layout change --- .../application/containers/config/config.tsx | 14 +- .../application/containers/editor/editor.tsx | 416 +++++++++--------- .../containers/history/history.tsx | 9 +- .../application/containers/main/main.tsx | 8 +- 4 files changed, 221 insertions(+), 226 deletions(-) diff --git a/src/plugins/console/public/application/containers/config/config.tsx b/src/plugins/console/public/application/containers/config/config.tsx index 503fdbd9c7354..8605a099182ba 100644 --- a/src/plugins/console/public/application/containers/config/config.tsx +++ b/src/plugins/console/public/application/containers/config/config.tsx @@ -8,16 +8,20 @@ */ import React from 'react'; -import { EuiFlexGroup, EuiFlexItem, EuiPanel, EuiSpacer } from '@elastic/eui'; +import { + EuiFlexGroup, + EuiFlexItem, + EuiPanel, + EuiSpacer, + useIsWithinBreakpoints, +} from '@elastic/eui'; import { Settings } from './settings'; import { Variables } from './variables'; -export interface Props { - isVerticalLayout: boolean; -} +export function Config() { + const isVerticalLayout = useIsWithinBreakpoints(['xs', 's', 'm']); -export function Config({ isVerticalLayout }: Props) { return ( void; } -export const Editor = memo( - ({ loading, isVerticalLayout, inputEditorValue, setInputEditorValue }: Props) => { - const { - services: { storage, objectStorageClient }, - } = useServicesContext(); +export const Editor = memo(({ loading, inputEditorValue, setInputEditorValue }: Props) => { + const { + services: { storage, objectStorageClient }, + } = useServicesContext(); - const editorValueRef = useRef(null); - const { currentTextObject } = useEditorReadContext(); - const { - requestInFlight, - lastResult: { data: requestData, error: requestError }, - } = useRequestReadContext(); + const editorValueRef = useRef(null); + const { currentTextObject } = useEditorReadContext(); + const { + requestInFlight, + lastResult: { data: requestData, error: requestError }, + } = useRequestReadContext(); - const dispatch = useRequestActionContext(); - const editorDispatch = useEditorActionContext(); + const dispatch = useRequestActionContext(); + const editorDispatch = useEditorActionContext(); - const [fetchingAutocompleteEntities, setFetchingAutocompleteEntities] = useState(false); + const [fetchingAutocompleteEntities, setFetchingAutocompleteEntities] = useState(false); - useEffect(() => { - const debouncedSetFechingAutocompleteEntities = debounce( - setFetchingAutocompleteEntities, - DEBOUNCE_DELAY - ); - const subscription = getAutocompleteInfo().isLoading$.subscribe( - debouncedSetFechingAutocompleteEntities - ); + useEffect(() => { + const debouncedSetFechingAutocompleteEntities = debounce( + setFetchingAutocompleteEntities, + DEBOUNCE_DELAY + ); + const subscription = getAutocompleteInfo().isLoading$.subscribe( + debouncedSetFechingAutocompleteEntities + ); - return () => { - subscription.unsubscribe(); - debouncedSetFechingAutocompleteEntities.cancel(); - }; - }, []); + return () => { + subscription.unsubscribe(); + debouncedSetFechingAutocompleteEntities.cancel(); + }; + }, []); - const [firstPanelSize, secondPanelSize] = storage.get(StorageKeys.SIZE, [ - INITIAL_PANEL_SIZE, - INITIAL_PANEL_SIZE, - ]); + const [firstPanelSize, secondPanelSize] = storage.get(StorageKeys.SIZE, [ + INITIAL_PANEL_SIZE, + INITIAL_PANEL_SIZE, + ]); - /* eslint-disable-next-line react-hooks/exhaustive-deps */ - const onPanelSizeChange = useCallback( - debounce((sizes) => { - storage.set(StorageKeys.SIZE, Object.values(sizes)); - }, 300), - [] - ); + const isVerticalLayout = useIsWithinBreakpoints(['xs', 's', 'm']); - /* eslint-disable-next-line react-hooks/exhaustive-deps */ - const debouncedUpdateLocalStorageValue = useCallback( - debounce((textObject: TextObject) => { - editorValueRef.current = textObject; - objectStorageClient.text.update(textObject); - }, DEBOUNCE_DELAY), - [] - ); + /* eslint-disable-next-line react-hooks/exhaustive-deps */ + const onPanelSizeChange = useCallback( + debounce((sizes) => { + storage.set(StorageKeys.SIZE, Object.values(sizes)); + }, 300), + [] + ); - useEffect(() => { - return () => { - editorDispatch({ - type: 'setCurrentTextObject', - payload: editorValueRef.current!, - }); - }; - }, [editorDispatch]); + /* eslint-disable-next-line react-hooks/exhaustive-deps */ + const debouncedUpdateLocalStorageValue = useCallback( + debounce((textObject: TextObject) => { + editorValueRef.current = textObject; + objectStorageClient.text.update(textObject); + }, DEBOUNCE_DELAY), + [] + ); - // Always keep the localstorage in sync with the value in the editor - // to avoid losing the text object when the user navigates away from the shell - useEffect(() => { - // Only update when its not empty, this is to avoid setting the localstorage value - // to an empty string that will then be replaced by the example request. - if (inputEditorValue !== '') { - const textObject = { - ...currentTextObject, - text: inputEditorValue, - updatedAt: Date.now(), - } as TextObject; + useEffect(() => { + return () => { + editorDispatch({ + type: 'setCurrentTextObject', + payload: editorValueRef.current!, + }); + }; + }, [editorDispatch]); - debouncedUpdateLocalStorageValue(textObject); - } - /* eslint-disable-next-line react-hooks/exhaustive-deps */ - }, [inputEditorValue, debouncedUpdateLocalStorageValue]); + // Always keep the localstorage in sync with the value in the editor + // to avoid losing the text object when the user navigates away from the shell + useEffect(() => { + // Only update when its not empty, this is to avoid setting the localstorage value + // to an empty string that will then be replaced by the example request. + if (inputEditorValue !== '') { + const textObject = { + ...currentTextObject, + text: inputEditorValue, + updatedAt: Date.now(), + } as TextObject; - const data = getResponseWithMostSevereStatusCode(requestData) ?? requestError; - const isLoading = loading || requestInFlight; + debouncedUpdateLocalStorageValue(textObject); + } + /* eslint-disable-next-line react-hooks/exhaustive-deps */ + }, [inputEditorValue, debouncedUpdateLocalStorageValue]); + + const data = getResponseWithMostSevereStatusCode(requestData) ?? requestError; + const isLoading = loading || requestInFlight; - if (!currentTextObject) return null; + if (!currentTextObject) return null; - return ( - <> - {fetchingAutocompleteEntities ? ( -
- -
- ) : null} - onPanelSizeChange(sizes)} - data-test-subj="consoleEditorContainer" - > - {(EuiResizablePanel, EuiResizableButton) => ( - <> - + {fetchingAutocompleteEntities ? ( +
+ +
+ ) : null} + onPanelSizeChange(sizes)} + data-test-subj="consoleEditorContainer" + > + {(EuiResizablePanel, EuiResizableButton) => ( + <> + + - + {loading ? ( + + ) : ( + + )} + + + {!loading && ( - {loading ? ( - - ) : ( - - )} - - - {!loading && ( - setInputEditorValue('')} > - setInputEditorValue('')} - > - {i18n.translate('console.editor.clearConsoleInputButton', { - defaultMessage: 'Clear this input', - })} - - - )} - - + {i18n.translate('console.editor.clearConsoleInputButton', { + defaultMessage: 'Clear this input', + })} + + + )} + +
- + - - + + + {data ? ( + + ) : isLoading ? ( + + ) : ( + + )} + + + {(data || isLoading) && ( - {data ? ( - - ) : isLoading ? ( - - ) : ( - - )} - + + + dispatch({ type: 'cleanRequest', payload: undefined })} + > + {i18n.translate('console.editor.clearConsoleOutputButton', { + defaultMessage: 'Clear this output', + })} + + - {(data || isLoading) && ( - - - - dispatch({ type: 'cleanRequest', payload: undefined })} - > - {i18n.translate('console.editor.clearConsoleOutputButton', { - defaultMessage: 'Clear this output', - })} - - - - - - - - - )} - - - - )} -
- - ); - } -); + + + + + + )} + + + + )} + + + ); +}); diff --git a/src/plugins/console/public/application/containers/history/history.tsx b/src/plugins/console/public/application/containers/history/history.tsx index 93777a364356e..f6d18d6d06dd1 100644 --- a/src/plugins/console/public/application/containers/history/history.tsx +++ b/src/plugins/console/public/application/containers/history/history.tsx @@ -26,6 +26,7 @@ import { EuiFormFieldset, EuiCheckableCard, EuiResizableContainer, + useIsWithinBreakpoints, } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; @@ -77,11 +78,7 @@ const CheckeableCardLabel = ({ historyItem }: { historyItem: HistoryProps }) => ); }; -interface Props { - isVerticalLayout: boolean; -} - -export function History({ isVerticalLayout }: Props) { +export function History() { const { euiTheme } = useEuiTheme(); const { services: { history, routeHistory }, @@ -99,6 +96,8 @@ export function History({ isVerticalLayout }: Props) { const [viewingReq, setViewingReq] = useState(null); + const isVerticalLayout = useIsWithinBreakpoints(['xs', 's', 'm']); + const initialize = useCallback(() => { const nextSelectedIndex = 0; setViewingReq(requests[nextSelectedIndex]); diff --git a/src/plugins/console/public/application/containers/main/main.tsx b/src/plugins/console/public/application/containers/main/main.tsx index c52e94f50749f..4f72cc648317a 100644 --- a/src/plugins/console/public/application/containers/main/main.tsx +++ b/src/plugins/console/public/application/containers/main/main.tsx @@ -18,7 +18,6 @@ import { EuiButtonEmpty, EuiHorizontalRule, EuiScreenReaderOnly, - useIsWithinBreakpoints, useEuiOverflowScroll, useEuiTheme, } from '@elastic/eui'; @@ -84,8 +83,6 @@ export function Main({ currentTabProp, isEmbeddable = false }: MainProps) { services: { notifications, routeHistory }, } = useServicesContext(); - const isVerticalLayout = useIsWithinBreakpoints(['xs', 's', 'm']); - const storageTourState = localStorage.getItem(TOUR_STORAGE_KEY); const initialTourState = storageTourState ? JSON.parse(storageTourState) : INITIAL_TOUR_CONFIG; const [tourStepProps, actions, tourState] = useEuiTour(getTourSteps(docLinks), initialTourState); @@ -314,13 +311,12 @@ export function Main({ currentTabProp, isEmbeddable = false }: MainProps) { {currentTab === SHELL_TAB_ID && ( )} - {currentTab === HISTORY_TAB_ID && } - {currentTab === CONFIG_TAB_ID && } + {currentTab === HISTORY_TAB_ID && } + {currentTab === CONFIG_TAB_ID && } Date: Fri, 20 Sep 2024 07:22:23 +0100 Subject: [PATCH 2/6] Fix localstorage update --- src/plugins/console/common/text_object.ts | 2 +- .../application/containers/editor/editor.tsx | 422 +++++++++--------- .../editor/hooks/use_set_initial_value.ts | 5 +- .../application/containers/main/main.tsx | 3 + .../hooks/use_data_init/use_data_init.ts | 2 +- 5 files changed, 225 insertions(+), 209 deletions(-) diff --git a/src/plugins/console/common/text_object.ts b/src/plugins/console/common/text_object.ts index 26fa59ec437cc..2fb6830f260da 100644 --- a/src/plugins/console/common/text_object.ts +++ b/src/plugins/console/common/text_object.ts @@ -34,5 +34,5 @@ export interface TextObject { * * Used to re-populate a text editor buffer. */ - text: string; + text: string | undefined; } diff --git a/src/plugins/console/public/application/containers/editor/editor.tsx b/src/plugins/console/public/application/containers/editor/editor.tsx index 73c212e7eaf12..320f1cf0bc457 100644 --- a/src/plugins/console/public/application/containers/editor/editor.tsx +++ b/src/plugins/console/public/application/containers/editor/editor.tsx @@ -30,7 +30,6 @@ import { } from '../../components'; import { getAutocompleteInfo, StorageKeys } from '../../../services'; import { - useEditorReadContext, useServicesContext, useRequestReadContext, useRequestActionContext, @@ -46,240 +45,253 @@ const DEBOUNCE_DELAY = 500; interface Props { loading: boolean; + initialTextObject: TextObject; inputEditorValue: string; setInputEditorValue: (value: string) => void; } -export const Editor = memo(({ loading, inputEditorValue, setInputEditorValue }: Props) => { - const { - services: { storage, objectStorageClient }, - } = useServicesContext(); +export const Editor = memo( + ({ loading, initialTextObject, inputEditorValue, setInputEditorValue }: Props) => { + const { + services: { storage, objectStorageClient }, + } = useServicesContext(); - const editorValueRef = useRef(null); - const { currentTextObject } = useEditorReadContext(); - const { - requestInFlight, - lastResult: { data: requestData, error: requestError }, - } = useRequestReadContext(); + const editorValueRef = useRef(null); + const [localStorageValue, setLocalStorageValue] = useState( + initialTextObject.text + ); - const dispatch = useRequestActionContext(); - const editorDispatch = useEditorActionContext(); + const { + requestInFlight, + lastResult: { data: requestData, error: requestError }, + } = useRequestReadContext(); - const [fetchingAutocompleteEntities, setFetchingAutocompleteEntities] = useState(false); + const dispatch = useRequestActionContext(); + const editorDispatch = useEditorActionContext(); - useEffect(() => { - const debouncedSetFechingAutocompleteEntities = debounce( - setFetchingAutocompleteEntities, - DEBOUNCE_DELAY - ); - const subscription = getAutocompleteInfo().isLoading$.subscribe( - debouncedSetFechingAutocompleteEntities - ); + const [fetchingAutocompleteEntities, setFetchingAutocompleteEntities] = useState(false); - return () => { - subscription.unsubscribe(); - debouncedSetFechingAutocompleteEntities.cancel(); - }; - }, []); + useEffect(() => { + const debouncedSetFechingAutocompleteEntities = debounce( + setFetchingAutocompleteEntities, + DEBOUNCE_DELAY + ); + const subscription = getAutocompleteInfo().isLoading$.subscribe( + debouncedSetFechingAutocompleteEntities + ); - const [firstPanelSize, secondPanelSize] = storage.get(StorageKeys.SIZE, [ - INITIAL_PANEL_SIZE, - INITIAL_PANEL_SIZE, - ]); + return () => { + subscription.unsubscribe(); + debouncedSetFechingAutocompleteEntities.cancel(); + }; + }, []); - const isVerticalLayout = useIsWithinBreakpoints(['xs', 's', 'm']); + const [firstPanelSize, secondPanelSize] = storage.get(StorageKeys.SIZE, [ + INITIAL_PANEL_SIZE, + INITIAL_PANEL_SIZE, + ]); - /* eslint-disable-next-line react-hooks/exhaustive-deps */ - const onPanelSizeChange = useCallback( - debounce((sizes) => { - storage.set(StorageKeys.SIZE, Object.values(sizes)); - }, 300), - [] - ); + const isVerticalLayout = useIsWithinBreakpoints(['xs', 's', 'm']); - /* eslint-disable-next-line react-hooks/exhaustive-deps */ - const debouncedUpdateLocalStorageValue = useCallback( - debounce((textObject: TextObject) => { - editorValueRef.current = textObject; - objectStorageClient.text.update(textObject); - }, DEBOUNCE_DELAY), - [] - ); + /* eslint-disable-next-line react-hooks/exhaustive-deps */ + const onPanelSizeChange = useCallback( + debounce((sizes) => { + storage.set(StorageKeys.SIZE, Object.values(sizes)); + }, 300), + [] + ); - useEffect(() => { - return () => { - editorDispatch({ - type: 'setCurrentTextObject', - payload: editorValueRef.current!, - }); - }; - }, [editorDispatch]); + /* eslint-disable-next-line react-hooks/exhaustive-deps */ + const debouncedUpdateLocalStorageValue = useCallback( + debounce((newValue: string | undefined) => { + const textObject = { + ...initialTextObject, + text: newValue, + updatedAt: Date.now(), + } as TextObject; - // Always keep the localstorage in sync with the value in the editor - // to avoid losing the text object when the user navigates away from the shell - useEffect(() => { - // Only update when its not empty, this is to avoid setting the localstorage value - // to an empty string that will then be replaced by the example request. - if (inputEditorValue !== '') { - const textObject = { - ...currentTextObject, - text: inputEditorValue, - updatedAt: Date.now(), - } as TextObject; + editorValueRef.current = textObject; + objectStorageClient.text.update(textObject); + setLocalStorageValue(newValue); + }, DEBOUNCE_DELAY), + [] + ); - debouncedUpdateLocalStorageValue(textObject); - } - /* eslint-disable-next-line react-hooks/exhaustive-deps */ - }, [inputEditorValue, debouncedUpdateLocalStorageValue]); + // 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]); - const data = getResponseWithMostSevereStatusCode(requestData) ?? requestError; - const isLoading = loading || requestInFlight; + // When the editor unmounts, we update the currentTextObject + useEffect(() => { + return () => { + // If the editor is empty, reset localstorage value to undefined + // so that next time we open Console the default input is displayed + if (!inputEditorValue) { + debouncedUpdateLocalStorageValue(undefined); + } + editorDispatch({ + type: 'setCurrentTextObject', + payload: editorValueRef.current!, + }); + }; + }, [editorDispatch]); - if (!currentTextObject) return null; + const data = getResponseWithMostSevereStatusCode(requestData) ?? requestError; + const isLoading = loading || requestInFlight; - return ( - <> - {fetchingAutocompleteEntities ? ( -
- -
- ) : null} - onPanelSizeChange(sizes)} - data-test-subj="consoleEditorContainer" - > - {(EuiResizablePanel, EuiResizableButton) => ( - <> - - + {fetchingAutocompleteEntities ? ( +
+ +
+ ) : null} + onPanelSizeChange(sizes)} + data-test-subj="consoleEditorContainer" + > + {(EuiResizablePanel, EuiResizableButton) => ( + <> + - - {loading ? ( - - ) : ( - - )} - - - {!loading && ( - setInputEditorValue('')} - > - {i18n.translate('console.editor.clearConsoleInputButton', { - defaultMessage: 'Clear this input', - })} - + {loading ? ( + + ) : ( + + )} - )} -
-
- - - - - - {data ? ( - - ) : isLoading ? ( - - ) : ( - + {!loading && ( + + { + debouncedUpdateLocalStorageValue(''); + setInputEditorValue(''); + }} + > + {i18n.translate('console.editor.clearConsoleInputButton', { + defaultMessage: 'Clear this input', + })} + + )} - + + + + - {(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/plugins/console/public/application/containers/editor/hooks/use_set_initial_value.ts b/src/plugins/console/public/application/containers/editor/hooks/use_set_initial_value.ts index 961ea586bc291..9e96c1af2734b 100644 --- a/src/plugins/console/public/application/containers/editor/hooks/use_set_initial_value.ts +++ b/src/plugins/console/public/application/containers/editor/hooks/use_set_initial_value.ts @@ -61,7 +61,7 @@ export const useSetInitialValue = (params: SetInitialValueParams) => { if (parsedURL.origin === 'https://www.elastic.co') { const resp = await fetch(parsedURL); const data = await resp.text(); - setValue(`${localStorageValue}\n\n${data}`); + setValue(`${localStorageValue ?? ''}\n\n${data}`); } else { toasts.addWarning( i18n.translate('console.monaco.loadFromDataUnrecognizedUrlErrorMessage', { @@ -107,7 +107,8 @@ export const useSetInitialValue = (params: SetInitialValueParams) => { if (loadFromParam) { loadBufferFromRemote(loadFromParam); } else { - setValue(localStorageValue || DEFAULT_INPUT_VALUE); + // Only set to default input value if the localstorage value is undefined + setValue(localStorageValue ?? DEFAULT_INPUT_VALUE); } return () => { diff --git a/src/plugins/console/public/application/containers/main/main.tsx b/src/plugins/console/public/application/containers/main/main.tsx index 4f72cc648317a..904e37cb2d0f1 100644 --- a/src/plugins/console/public/application/containers/main/main.tsx +++ b/src/plugins/console/public/application/containers/main/main.tsx @@ -183,6 +183,8 @@ export function Main({ currentTabProp, isEmbeddable = false }: MainProps) { ); } + if (!currentTextObject) return null; + const shortcutsButton = ( diff --git a/src/plugins/console/public/application/hooks/use_data_init/use_data_init.ts b/src/plugins/console/public/application/hooks/use_data_init/use_data_init.ts index 16e231b549da8..ea9626f9bdafb 100644 --- a/src/plugins/console/public/application/hooks/use_data_init/use_data_init.ts +++ b/src/plugins/console/public/application/hooks/use_data_init/use_data_init.ts @@ -37,7 +37,7 @@ export const useDataInit = () => { const newObject = await objectStorageClient.text.create({ createdAt: Date.now(), updatedAt: Date.now(), - text: '', + text: undefined, }); dispatch({ type: 'setCurrentTextObject', payload: newObject }); } else { From 7512ee2d3b7ee78254e0ded08cc70673d8940b03 Mon Sep 17 00:00:00 2001 From: Elena Stoeva Date: Mon, 23 Sep 2024 12:25:28 +0100 Subject: [PATCH 3/6] Fix storing to local storage --- .../application/containers/editor/editor.tsx | 414 +++++++++--------- .../application/containers/main/main.tsx | 1 - .../hooks/use_data_init/use_data_init.ts | 26 +- 3 files changed, 217 insertions(+), 224 deletions(-) diff --git a/src/plugins/console/public/application/containers/editor/editor.tsx b/src/plugins/console/public/application/containers/editor/editor.tsx index 320f1cf0bc457..3147542044e27 100644 --- a/src/plugins/console/public/application/containers/editor/editor.tsx +++ b/src/plugins/console/public/application/containers/editor/editor.tsx @@ -7,7 +7,7 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import React, { useRef, useCallback, memo, useEffect, useState } from 'react'; +import React, { useCallback, memo, useEffect, useState } from 'react'; import { debounce } from 'lodash'; import { EuiProgress, @@ -34,6 +34,7 @@ import { useRequestReadContext, useRequestActionContext, useEditorActionContext, + useEditorReadContext, } from '../../contexts'; import { MonacoEditor } from './monaco_editor'; import { MonacoEditorOutput } from './monaco_editor_output'; @@ -45,253 +46,232 @@ const DEBOUNCE_DELAY = 500; interface Props { loading: boolean; - initialTextObject: TextObject; inputEditorValue: string; setInputEditorValue: (value: string) => void; } -export const Editor = memo( - ({ loading, initialTextObject, inputEditorValue, setInputEditorValue }: Props) => { - const { - services: { storage, objectStorageClient }, - } = useServicesContext(); +export const Editor = memo(({ loading, inputEditorValue, setInputEditorValue }: Props) => { + const { + services: { storage, objectStorageClient }, + } = useServicesContext(); - const editorValueRef = useRef(null); - const [localStorageValue, setLocalStorageValue] = useState( - initialTextObject.text - ); + const { currentTextObject } = useEditorReadContext(); + + const { + requestInFlight, + lastResult: { data: requestData, error: requestError }, + } = useRequestReadContext(); - const { - requestInFlight, - lastResult: { data: requestData, error: requestError }, - } = useRequestReadContext(); + const dispatch = useRequestActionContext(); + const editorDispatch = useEditorActionContext(); - const dispatch = useRequestActionContext(); - const editorDispatch = useEditorActionContext(); + const [fetchingAutocompleteEntities, setFetchingAutocompleteEntities] = useState(false); - const [fetchingAutocompleteEntities, setFetchingAutocompleteEntities] = useState(false); + useEffect(() => { + const debouncedSetFechingAutocompleteEntities = debounce( + setFetchingAutocompleteEntities, + DEBOUNCE_DELAY + ); + const subscription = getAutocompleteInfo().isLoading$.subscribe( + debouncedSetFechingAutocompleteEntities + ); - useEffect(() => { - const debouncedSetFechingAutocompleteEntities = debounce( - setFetchingAutocompleteEntities, - DEBOUNCE_DELAY - ); - const subscription = getAutocompleteInfo().isLoading$.subscribe( - debouncedSetFechingAutocompleteEntities - ); + return () => { + subscription.unsubscribe(); + debouncedSetFechingAutocompleteEntities.cancel(); + }; + }, []); - return () => { - subscription.unsubscribe(); - debouncedSetFechingAutocompleteEntities.cancel(); - }; - }, []); + const [firstPanelSize, secondPanelSize] = storage.get(StorageKeys.SIZE, [ + INITIAL_PANEL_SIZE, + INITIAL_PANEL_SIZE, + ]); - const [firstPanelSize, secondPanelSize] = storage.get(StorageKeys.SIZE, [ - INITIAL_PANEL_SIZE, - INITIAL_PANEL_SIZE, - ]); + const isVerticalLayout = useIsWithinBreakpoints(['xs', 's', 'm']); - 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 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; - /* eslint-disable-next-line react-hooks/exhaustive-deps */ - const debouncedUpdateLocalStorageValue = useCallback( - debounce((newValue: string | undefined) => { - const textObject = { - ...initialTextObject, - text: newValue, - updatedAt: Date.now(), - } as TextObject; + objectStorageClient.text.update(textObject); - editorValueRef.current = textObject; - objectStorageClient.text.update(textObject); - setLocalStorageValue(newValue); - }, DEBOUNCE_DELAY), - [] - ); + 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]); + // 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]); - // When the editor unmounts, we update the currentTextObject - useEffect(() => { - return () => { - // If the editor is empty, reset localstorage value to undefined - // so that next time we open Console the default input is displayed - if (!inputEditorValue) { - debouncedUpdateLocalStorageValue(undefined); - } - editorDispatch({ - type: 'setCurrentTextObject', - payload: editorValueRef.current!, - }); - }; - }, [editorDispatch]); + if (!currentTextObject) return null; - const data = getResponseWithMostSevereStatusCode(requestData) ?? requestError; - const isLoading = loading || requestInFlight; + const data = getResponseWithMostSevereStatusCode(requestData) ?? requestError; + const isLoading = loading || requestInFlight; - return ( - <> - {fetchingAutocompleteEntities ? ( -
- -
- ) : null} - onPanelSizeChange(sizes)} - data-test-subj="consoleEditorContainer" - > - {(EuiResizablePanel, EuiResizableButton) => ( - <> - + {fetchingAutocompleteEntities ? ( +
+ +
+ ) : null} + onPanelSizeChange(sizes)} + data-test-subj="consoleEditorContainer" + > + {(EuiResizablePanel, EuiResizableButton) => ( + <> + + - + {loading ? ( + + ) : ( + + )} +
+ + {!loading && ( - {loading ? ( - - ) : ( - - )} - - - {!loading && ( - { + setInputEditorValue(''); }} - className="consoleEditorPanel" > - { - debouncedUpdateLocalStorageValue(''); - setInputEditorValue(''); - }} - > - {i18n.translate('console.editor.clearConsoleInputButton', { - defaultMessage: 'Clear this input', - })} - - - )} - - + {i18n.translate('console.editor.clearConsoleInputButton', { + defaultMessage: 'Clear this input', + })} + + + )} + + - + - - + + + {data ? ( + + ) : isLoading ? ( + + ) : ( + + )} + + + {(data || isLoading) && ( - {data ? ( - - ) : isLoading ? ( - - ) : ( - - )} - + + + dispatch({ type: 'cleanRequest', payload: undefined })} + > + {i18n.translate('console.editor.clearConsoleOutputButton', { + defaultMessage: 'Clear this output', + })} + + - {(data || isLoading) && ( - - - - dispatch({ type: 'cleanRequest', payload: undefined })} - > - {i18n.translate('console.editor.clearConsoleOutputButton', { - defaultMessage: 'Clear this output', - })} - - - - - - - - - )} - - - - )} - - - ); - } -); + + + + + + )} + + + + )} + + + ); +}); diff --git a/src/plugins/console/public/application/containers/main/main.tsx b/src/plugins/console/public/application/containers/main/main.tsx index 904e37cb2d0f1..00e2a0941cb3a 100644 --- a/src/plugins/console/public/application/containers/main/main.tsx +++ b/src/plugins/console/public/application/containers/main/main.tsx @@ -313,7 +313,6 @@ export function Main({ currentTabProp, isEmbeddable = false }: MainProps) { {currentTab === SHELL_TAB_ID && ( diff --git a/src/plugins/console/public/application/hooks/use_data_init/use_data_init.ts b/src/plugins/console/public/application/hooks/use_data_init/use_data_init.ts index ea9626f9bdafb..636ae36baf110 100644 --- a/src/plugins/console/public/application/hooks/use_data_init/use_data_init.ts +++ b/src/plugins/console/public/application/hooks/use_data_init/use_data_init.ts @@ -10,6 +10,7 @@ import { useCallback, useEffect, useState } from 'react'; import { migrateToTextObjects } from './data_migration'; import { useEditorActionContext, useServicesContext } from '../../contexts'; +import { TextObject } from "@kbn/console-plugin/common/text_object"; export const useDataInit = () => { const [error, setError] = useState(null); @@ -41,12 +42,25 @@ export const useDataInit = () => { }); dispatch({ type: 'setCurrentTextObject', payload: newObject }); } else { - dispatch({ - type: 'setCurrentTextObject', - // For backwards compatibility, we sort here according to date created to - // always take the first item created. - payload: results.sort((a, b) => a.createdAt - b.createdAt)[0], - }); + // For backwards compatibility, we sort here according to date created to + // always take the first item created. + const lastObject = results.sort((a, b) => a.createdAt - b.createdAt)[0]; + if (lastObject.text === '') { + // If the last stored text is empty, add a new object with undefined text so that the default input is displayed at initial render + const textObject = { + ...lastObject, + text: undefined, + updatedAt: Date.now(), + } as TextObject; + + objectStorageClient.text.update(textObject); + dispatch({ type: 'setCurrentTextObject', payload: textObject }); + } else { + dispatch({ + type: 'setCurrentTextObject', + payload: lastObject, + }); + } } } catch (e) { setError(e); From 2d9c00893207cfede7509f89d2751ce94e97facb Mon Sep 17 00:00:00 2001 From: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Date: Mon, 23 Sep 2024 11:38:31 +0000 Subject: [PATCH 4/6] [CI] Auto-commit changed files from 'node scripts/notice' --- src/plugins/console/tsconfig.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/plugins/console/tsconfig.json b/src/plugins/console/tsconfig.json index a13333dfa8b30..c723e5e06bf9d 100644 --- a/src/plugins/console/tsconfig.json +++ b/src/plugins/console/tsconfig.json @@ -33,7 +33,8 @@ "@kbn/react-kibana-mount", "@kbn/ui-theme", "@kbn/core-doc-links-browser", - "@kbn/shared-ux-router" + "@kbn/shared-ux-router", + "@kbn/console-plugin" ], "exclude": [ "target/**/*", From a5722f35369ce87c4d8d2a6d56dfac6db0f75b98 Mon Sep 17 00:00:00 2001 From: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Date: Mon, 23 Sep 2024 12:36:04 +0000 Subject: [PATCH 5/6] [CI] Auto-commit changed files from 'node scripts/eslint --no-cache --fix' --- .../public/application/hooks/use_data_init/use_data_init.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/console/public/application/hooks/use_data_init/use_data_init.ts b/src/plugins/console/public/application/hooks/use_data_init/use_data_init.ts index 636ae36baf110..0bcafb1e841c3 100644 --- a/src/plugins/console/public/application/hooks/use_data_init/use_data_init.ts +++ b/src/plugins/console/public/application/hooks/use_data_init/use_data_init.ts @@ -8,9 +8,9 @@ */ import { useCallback, useEffect, useState } from 'react'; +import { TextObject } from '../../../../common/text_object'; import { migrateToTextObjects } from './data_migration'; import { useEditorActionContext, useServicesContext } from '../../contexts'; -import { TextObject } from "@kbn/console-plugin/common/text_object"; export const useDataInit = () => { const [error, setError] = useState(null); From 08415c74f46c7525d2b74d90086ea7723e6e0b32 Mon Sep 17 00:00:00 2001 From: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Date: Mon, 23 Sep 2024 12:50:22 +0000 Subject: [PATCH 6/6] [CI] Auto-commit changed files from 'node scripts/notice' --- src/plugins/console/tsconfig.json | 1 - 1 file changed, 1 deletion(-) diff --git a/src/plugins/console/tsconfig.json b/src/plugins/console/tsconfig.json index c723e5e06bf9d..2b0f6127cd4af 100644 --- a/src/plugins/console/tsconfig.json +++ b/src/plugins/console/tsconfig.json @@ -34,7 +34,6 @@ "@kbn/ui-theme", "@kbn/core-doc-links-browser", "@kbn/shared-ux-router", - "@kbn/console-plugin" ], "exclude": [ "target/**/*",