mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
[Console] Fix editor value resetting at layout change (#193516)
## Summary This PR fixes the bug where the editor input resets when we resize the page and the layout changes. The following fixes were applied: - The `isVerticalLayout` prop was moved one level down. This removes unnecessary rerendering of the editor when the layout is changed. - Allowed the localstorage value to be undefined. Undefined means that nothing is stored so we should display the default input. If an empty string is stored, we should display an empty editor. - Updates local storage with debounce every time when the editor input is changes. This ensures the editor input is not reset when the editor is rerendered. - Updates the local storage value to `undefined` if it is an empty string when data is being initialized at Main. This ensures that the default input is displayed when we switch between tabs/pages and the input is empty. Before: https://github.com/user-attachments/assets/a0535780-d75a-4df8-9e04-9d34b6f5f4f1 Now: https://github.com/user-attachments/assets/7db46c2c-c35e-461f-99e8-b86c66fb6ae5 --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
194d6307dc
commit
3b8e56fd34
8 changed files with 246 additions and 242 deletions
|
@ -34,5 +34,5 @@ export interface TextObject {
|
|||
*
|
||||
* Used to re-populate a text editor buffer.
|
||||
*/
|
||||
text: string;
|
||||
text: string | undefined;
|
||||
}
|
||||
|
|
|
@ -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 (
|
||||
<EuiPanel
|
||||
color="subdued"
|
||||
|
|
|
@ -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,
|
||||
|
@ -16,6 +16,7 @@ import {
|
|||
EuiFlexItem,
|
||||
EuiButtonEmpty,
|
||||
EuiResizableContainer,
|
||||
useIsWithinBreakpoints,
|
||||
} from '@elastic/eui';
|
||||
import { euiThemeVars } from '@kbn/ui-theme';
|
||||
|
||||
|
@ -29,11 +30,11 @@ import {
|
|||
} from '../../components';
|
||||
import { getAutocompleteInfo, StorageKeys } from '../../../services';
|
||||
import {
|
||||
useEditorReadContext,
|
||||
useServicesContext,
|
||||
useRequestReadContext,
|
||||
useRequestActionContext,
|
||||
useEditorActionContext,
|
||||
useEditorReadContext,
|
||||
} from '../../contexts';
|
||||
import { MonacoEditor } from './monaco_editor';
|
||||
import { MonacoEditorOutput } from './monaco_editor_output';
|
||||
|
@ -45,245 +46,232 @@ const DEBOUNCE_DELAY = 500;
|
|||
|
||||
interface Props {
|
||||
loading: boolean;
|
||||
isVerticalLayout: boolean;
|
||||
inputEditorValue: string;
|
||||
setInputEditorValue: (value: string) => 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<TextObject | null>(null);
|
||||
const { currentTextObject } = useEditorReadContext();
|
||||
const {
|
||||
requestInFlight,
|
||||
lastResult: { data: requestData, error: requestError },
|
||||
} = useRequestReadContext();
|
||||
const { currentTextObject } = useEditorReadContext();
|
||||
|
||||
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();
|
||||
};
|
||||
}, []);
|
||||
|
||||
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),
|
||||
[]
|
||||
useEffect(() => {
|
||||
const debouncedSetFechingAutocompleteEntities = debounce(
|
||||
setFetchingAutocompleteEntities,
|
||||
DEBOUNCE_DELAY
|
||||
);
|
||||
const subscription = getAutocompleteInfo().isLoading$.subscribe(
|
||||
debouncedSetFechingAutocompleteEntities
|
||||
);
|
||||
|
||||
/* eslint-disable-next-line react-hooks/exhaustive-deps */
|
||||
const debouncedUpdateLocalStorageValue = useCallback(
|
||||
debounce((textObject: TextObject) => {
|
||||
editorValueRef.current = textObject;
|
||||
objectStorageClient.text.update(textObject);
|
||||
}, DEBOUNCE_DELAY),
|
||||
[]
|
||||
);
|
||||
return () => {
|
||||
subscription.unsubscribe();
|
||||
debouncedSetFechingAutocompleteEntities.cancel();
|
||||
};
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
editorDispatch({
|
||||
type: 'setCurrentTextObject',
|
||||
payload: editorValueRef.current!,
|
||||
});
|
||||
};
|
||||
}, [editorDispatch]);
|
||||
const [firstPanelSize, secondPanelSize] = storage.get(StorageKeys.SIZE, [
|
||||
INITIAL_PANEL_SIZE,
|
||||
INITIAL_PANEL_SIZE,
|
||||
]);
|
||||
|
||||
// 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 isVerticalLayout = useIsWithinBreakpoints(['xs', 's', 'm']);
|
||||
|
||||
debouncedUpdateLocalStorageValue(textObject);
|
||||
}
|
||||
/* eslint-disable-next-line react-hooks/exhaustive-deps */
|
||||
}, [inputEditorValue, debouncedUpdateLocalStorageValue]);
|
||||
/* eslint-disable-next-line react-hooks/exhaustive-deps */
|
||||
const onPanelSizeChange = useCallback(
|
||||
debounce((sizes) => {
|
||||
storage.set(StorageKeys.SIZE, Object.values(sizes));
|
||||
}, 300),
|
||||
[]
|
||||
);
|
||||
|
||||
const data = getResponseWithMostSevereStatusCode(requestData) ?? requestError;
|
||||
const isLoading = loading || requestInFlight;
|
||||
/* 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;
|
||||
|
||||
if (!currentTextObject) return null;
|
||||
objectStorageClient.text.update(textObject);
|
||||
|
||||
return (
|
||||
<>
|
||||
{fetchingAutocompleteEntities ? (
|
||||
<div className="conApp__requestProgressBarContainer">
|
||||
<EuiProgress size="xs" color="accent" position="absolute" />
|
||||
</div>
|
||||
) : null}
|
||||
<EuiResizableContainer
|
||||
style={{ height: '100%' }}
|
||||
direction={isVerticalLayout ? 'vertical' : 'horizontal'}
|
||||
onPanelWidthChange={(sizes) => onPanelSizeChange(sizes)}
|
||||
data-test-subj="consoleEditorContainer"
|
||||
>
|
||||
{(EuiResizablePanel, EuiResizableButton) => (
|
||||
<>
|
||||
<EuiResizablePanel
|
||||
initialSize={firstPanelSize}
|
||||
minSize={PANEL_MIN_SIZE}
|
||||
tabIndex={0}
|
||||
paddingSize="none"
|
||||
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 ? (
|
||||
<div className="conApp__requestProgressBarContainer">
|
||||
<EuiProgress size="xs" color="accent" position="absolute" />
|
||||
</div>
|
||||
) : null}
|
||||
<EuiResizableContainer
|
||||
style={{ height: '100%' }}
|
||||
direction={isVerticalLayout ? 'vertical' : 'horizontal'}
|
||||
onPanelWidthChange={(sizes) => onPanelSizeChange(sizes)}
|
||||
data-test-subj="consoleEditorContainer"
|
||||
>
|
||||
{(EuiResizablePanel, EuiResizableButton) => (
|
||||
<>
|
||||
<EuiResizablePanel
|
||||
initialSize={firstPanelSize}
|
||||
minSize={PANEL_MIN_SIZE}
|
||||
tabIndex={0}
|
||||
paddingSize="none"
|
||||
>
|
||||
<EuiSplitPanel.Outer
|
||||
grow={true}
|
||||
borderRadius="none"
|
||||
hasShadow={false}
|
||||
style={{ height: '100%' }}
|
||||
>
|
||||
<EuiSplitPanel.Outer
|
||||
<EuiSplitPanel.Inner
|
||||
paddingSize="none"
|
||||
grow={true}
|
||||
borderRadius="none"
|
||||
hasShadow={false}
|
||||
style={{ height: '100%' }}
|
||||
className="consoleEditorPanel"
|
||||
style={{ top: 0, height: 'calc(100% - 40px)' }}
|
||||
>
|
||||
<EuiSplitPanel.Inner
|
||||
paddingSize="none"
|
||||
grow={true}
|
||||
className="consoleEditorPanel"
|
||||
style={{ top: 0, height: 'calc(100% - 40px)' }}
|
||||
>
|
||||
{loading ? (
|
||||
<EditorContentSpinner />
|
||||
) : (
|
||||
<MonacoEditor
|
||||
localStorageValue={currentTextObject.text}
|
||||
value={inputEditorValue}
|
||||
setValue={setInputEditorValue}
|
||||
/>
|
||||
)}
|
||||
</EuiSplitPanel.Inner>
|
||||
|
||||
{!loading && (
|
||||
<EuiSplitPanel.Inner
|
||||
grow={false}
|
||||
paddingSize="s"
|
||||
css={{
|
||||
backgroundColor: euiThemeVars.euiFormBackgroundColor,
|
||||
}}
|
||||
className="consoleEditorPanel"
|
||||
>
|
||||
<EuiButtonEmpty
|
||||
size="xs"
|
||||
color="primary"
|
||||
data-test-subj="clearConsoleInput"
|
||||
onClick={() => setInputEditorValue('')}
|
||||
>
|
||||
{i18n.translate('console.editor.clearConsoleInputButton', {
|
||||
defaultMessage: 'Clear this input',
|
||||
})}
|
||||
</EuiButtonEmpty>
|
||||
</EuiSplitPanel.Inner>
|
||||
{loading ? (
|
||||
<EditorContentSpinner />
|
||||
) : (
|
||||
<MonacoEditor
|
||||
localStorageValue={currentTextObject.text}
|
||||
value={inputEditorValue}
|
||||
setValue={setInputEditorValue}
|
||||
/>
|
||||
)}
|
||||
</EuiSplitPanel.Outer>
|
||||
</EuiResizablePanel>
|
||||
</EuiSplitPanel.Inner>
|
||||
|
||||
<EuiResizableButton
|
||||
className="conApp__resizerButton"
|
||||
aria-label={i18n.translate('console.editor.adjustPanelSizeAriaLabel', {
|
||||
defaultMessage: "Press left/right to adjust panels' sizes",
|
||||
})}
|
||||
/>
|
||||
|
||||
<EuiResizablePanel
|
||||
initialSize={secondPanelSize}
|
||||
minSize={PANEL_MIN_SIZE}
|
||||
tabIndex={0}
|
||||
paddingSize="none"
|
||||
>
|
||||
<EuiSplitPanel.Outer
|
||||
borderRadius="none"
|
||||
hasShadow={false}
|
||||
style={{ height: '100%' }}
|
||||
>
|
||||
{!loading && (
|
||||
<EuiSplitPanel.Inner
|
||||
paddingSize="none"
|
||||
css={{ alignContent: 'center', top: 0 }}
|
||||
grow={false}
|
||||
paddingSize="s"
|
||||
css={{
|
||||
backgroundColor: euiThemeVars.euiFormBackgroundColor,
|
||||
}}
|
||||
className="consoleEditorPanel"
|
||||
>
|
||||
{data ? (
|
||||
<MonacoEditorOutput />
|
||||
) : isLoading ? (
|
||||
<EditorContentSpinner />
|
||||
) : (
|
||||
<OutputPanelEmptyState />
|
||||
)}
|
||||
</EuiSplitPanel.Inner>
|
||||
|
||||
{(data || isLoading) && (
|
||||
<EuiSplitPanel.Inner
|
||||
grow={false}
|
||||
paddingSize="s"
|
||||
css={{
|
||||
backgroundColor: euiThemeVars.euiFormBackgroundColor,
|
||||
<EuiButtonEmpty
|
||||
size="xs"
|
||||
color="primary"
|
||||
data-test-subj="clearConsoleInput"
|
||||
onClick={() => {
|
||||
setInputEditorValue('');
|
||||
}}
|
||||
className="consoleEditorPanel"
|
||||
>
|
||||
<EuiFlexGroup gutterSize="none" responsive={false}>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiButtonEmpty
|
||||
size="xs"
|
||||
color="primary"
|
||||
data-test-subj="clearConsoleOutput"
|
||||
onClick={() => dispatch({ type: 'cleanRequest', payload: undefined })}
|
||||
>
|
||||
{i18n.translate('console.editor.clearConsoleOutputButton', {
|
||||
defaultMessage: 'Clear this output',
|
||||
})}
|
||||
</EuiButtonEmpty>
|
||||
</EuiFlexItem>
|
||||
{i18n.translate('console.editor.clearConsoleInputButton', {
|
||||
defaultMessage: 'Clear this input',
|
||||
})}
|
||||
</EuiButtonEmpty>
|
||||
</EuiSplitPanel.Inner>
|
||||
)}
|
||||
</EuiSplitPanel.Outer>
|
||||
</EuiResizablePanel>
|
||||
|
||||
<EuiFlexItem>
|
||||
<NetworkRequestStatusBar
|
||||
requestInProgress={requestInFlight}
|
||||
requestResult={
|
||||
data
|
||||
? {
|
||||
method: data.request.method.toUpperCase(),
|
||||
endpoint: data.request.path,
|
||||
statusCode: data.response.statusCode,
|
||||
statusText: data.response.statusText,
|
||||
timeElapsedMs: data.response.timeMs,
|
||||
}
|
||||
: undefined
|
||||
}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiSplitPanel.Inner>
|
||||
<EuiResizableButton
|
||||
className="conApp__resizerButton"
|
||||
aria-label={i18n.translate('console.editor.adjustPanelSizeAriaLabel', {
|
||||
defaultMessage: "Press left/right to adjust panels' sizes",
|
||||
})}
|
||||
/>
|
||||
|
||||
<EuiResizablePanel
|
||||
initialSize={secondPanelSize}
|
||||
minSize={PANEL_MIN_SIZE}
|
||||
tabIndex={0}
|
||||
paddingSize="none"
|
||||
>
|
||||
<EuiSplitPanel.Outer borderRadius="none" hasShadow={false} style={{ height: '100%' }}>
|
||||
<EuiSplitPanel.Inner
|
||||
paddingSize="none"
|
||||
css={{ alignContent: 'center', top: 0 }}
|
||||
className="consoleEditorPanel"
|
||||
>
|
||||
{data ? (
|
||||
<MonacoEditorOutput />
|
||||
) : isLoading ? (
|
||||
<EditorContentSpinner />
|
||||
) : (
|
||||
<OutputPanelEmptyState />
|
||||
)}
|
||||
</EuiSplitPanel.Outer>
|
||||
</EuiResizablePanel>
|
||||
</>
|
||||
)}
|
||||
</EuiResizableContainer>
|
||||
</>
|
||||
);
|
||||
}
|
||||
);
|
||||
</EuiSplitPanel.Inner>
|
||||
|
||||
{(data || isLoading) && (
|
||||
<EuiSplitPanel.Inner
|
||||
grow={false}
|
||||
paddingSize="s"
|
||||
css={{
|
||||
backgroundColor: euiThemeVars.euiFormBackgroundColor,
|
||||
}}
|
||||
className="consoleEditorPanel"
|
||||
>
|
||||
<EuiFlexGroup gutterSize="none" responsive={false}>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiButtonEmpty
|
||||
size="xs"
|
||||
color="primary"
|
||||
data-test-subj="clearConsoleOutput"
|
||||
onClick={() => dispatch({ type: 'cleanRequest', payload: undefined })}
|
||||
>
|
||||
{i18n.translate('console.editor.clearConsoleOutputButton', {
|
||||
defaultMessage: 'Clear this output',
|
||||
})}
|
||||
</EuiButtonEmpty>
|
||||
</EuiFlexItem>
|
||||
|
||||
<EuiFlexItem>
|
||||
<NetworkRequestStatusBar
|
||||
requestInProgress={requestInFlight}
|
||||
requestResult={
|
||||
data
|
||||
? {
|
||||
method: data.request.method.toUpperCase(),
|
||||
endpoint: data.request.path,
|
||||
statusCode: data.response.statusCode,
|
||||
statusText: data.response.statusText,
|
||||
timeElapsedMs: data.response.timeMs,
|
||||
}
|
||||
: undefined
|
||||
}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiSplitPanel.Inner>
|
||||
)}
|
||||
</EuiSplitPanel.Outer>
|
||||
</EuiResizablePanel>
|
||||
</>
|
||||
)}
|
||||
</EuiResizableContainer>
|
||||
</>
|
||||
);
|
||||
});
|
||||
|
|
|
@ -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 () => {
|
||||
|
|
|
@ -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<any>(null);
|
||||
|
||||
const isVerticalLayout = useIsWithinBreakpoints(['xs', 's', 'm']);
|
||||
|
||||
const initialize = useCallback(() => {
|
||||
const nextSelectedIndex = 0;
|
||||
setViewingReq(requests[nextSelectedIndex]);
|
||||
|
|
|
@ -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);
|
||||
|
@ -186,6 +183,8 @@ export function Main({ currentTabProp, isEmbeddable = false }: MainProps) {
|
|||
);
|
||||
}
|
||||
|
||||
if (!currentTextObject) return null;
|
||||
|
||||
const shortcutsButton = (
|
||||
<NavIconButton
|
||||
iconType="keyboard"
|
||||
|
@ -314,13 +313,12 @@ export function Main({ currentTabProp, isEmbeddable = false }: MainProps) {
|
|||
{currentTab === SHELL_TAB_ID && (
|
||||
<Editor
|
||||
loading={!done}
|
||||
isVerticalLayout={isVerticalLayout}
|
||||
inputEditorValue={inputEditorValue}
|
||||
setInputEditorValue={setInputEditorValue}
|
||||
/>
|
||||
)}
|
||||
{currentTab === HISTORY_TAB_ID && <History isVerticalLayout={isVerticalLayout} />}
|
||||
{currentTab === CONFIG_TAB_ID && <Config isVerticalLayout={isVerticalLayout} />}
|
||||
{currentTab === HISTORY_TAB_ID && <History />}
|
||||
{currentTab === CONFIG_TAB_ID && <Config />}
|
||||
</EuiSplitPanel.Inner>
|
||||
<EuiHorizontalRule margin="none" />
|
||||
<EuiSplitPanel.Inner
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
*/
|
||||
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
import { TextObject } from '../../../../common/text_object';
|
||||
import { migrateToTextObjects } from './data_migration';
|
||||
import { useEditorActionContext, useServicesContext } from '../../contexts';
|
||||
|
||||
|
@ -37,16 +38,29 @@ export const useDataInit = () => {
|
|||
const newObject = await objectStorageClient.text.create({
|
||||
createdAt: Date.now(),
|
||||
updatedAt: Date.now(),
|
||||
text: '',
|
||||
text: undefined,
|
||||
});
|
||||
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);
|
||||
|
|
|
@ -33,7 +33,7 @@
|
|||
"@kbn/react-kibana-mount",
|
||||
"@kbn/ui-theme",
|
||||
"@kbn/core-doc-links-browser",
|
||||
"@kbn/shared-ux-router"
|
||||
"@kbn/shared-ux-router",
|
||||
],
|
||||
"exclude": [
|
||||
"target/**/*",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue