mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 17:59:23 -04:00
[Console] Fix load from remote (#52814)
* Fix load remote state * Clean up variable usage, add comment, move forceRetokenize to private method * Optimize sequence of checking hash on initial load
This commit is contained in:
parent
0279eb7b1c
commit
21334e7b15
3 changed files with 90 additions and 35 deletions
|
@ -20,6 +20,11 @@
|
|||
import React, { CSSProperties, useCallback, useEffect, useRef, useState } from 'react';
|
||||
import { EuiToolTip } from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { debounce } from 'lodash';
|
||||
|
||||
// Node v5 querystring for browser.
|
||||
// @ts-ignore
|
||||
import * as qs from 'querystring-browser';
|
||||
|
||||
import { EuiIcon, EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
|
||||
import { useServicesContext, useEditorReadContext } from '../../../../contexts';
|
||||
|
@ -80,17 +85,64 @@ function EditorUI() {
|
|||
|
||||
useEffect(() => {
|
||||
editorInstanceRef.current = senseEditor.create(editorRef.current!);
|
||||
const editor = editorInstanceRef.current;
|
||||
|
||||
const { content: text } = history.getSavedEditorState() || {
|
||||
content: DEFAULT_INPUT_VALUE,
|
||||
const readQueryParams = () => {
|
||||
const [, queryString] = (window.location.hash || '').split('?');
|
||||
return qs.parse(queryString || '');
|
||||
};
|
||||
editorInstanceRef.current.update(text);
|
||||
|
||||
const loadBufferFromRemote = (url: string) => {
|
||||
if (/^https?:\/\//.test(url)) {
|
||||
const loadFrom: Record<string, any> = {
|
||||
url,
|
||||
// Having dataType here is required as it doesn't allow jQuery to `eval` content
|
||||
// coming from the external source thereby preventing XSS attack.
|
||||
dataType: 'text',
|
||||
kbnXsrfToken: false,
|
||||
};
|
||||
|
||||
if (/https?:\/\/api\.github\.com/.test(url)) {
|
||||
loadFrom.headers = { Accept: 'application/vnd.github.v3.raw' };
|
||||
}
|
||||
|
||||
// Fire and forget.
|
||||
$.ajax(loadFrom).done(async data => {
|
||||
const coreEditor = editor.getCoreEditor();
|
||||
await editor.update(data, true);
|
||||
editor.moveToNextRequestEdge(false);
|
||||
coreEditor.clearSelection();
|
||||
editor.highlightCurrentRequestsAndUpdateActionBar();
|
||||
coreEditor.getContainer().focus();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// Support for loading a console snippet from a remote source, like support docs.
|
||||
const onHashChange = debounce(() => {
|
||||
const { load_from: url } = readQueryParams();
|
||||
if (!url) {
|
||||
return;
|
||||
}
|
||||
loadBufferFromRemote(url);
|
||||
}, 200);
|
||||
window.addEventListener('hashchange', onHashChange);
|
||||
|
||||
const initialQueryParams = readQueryParams();
|
||||
if (initialQueryParams.load_from) {
|
||||
loadBufferFromRemote(initialQueryParams.load_from);
|
||||
} else {
|
||||
const { content: text } = history.getSavedEditorState() || {
|
||||
content: DEFAULT_INPUT_VALUE,
|
||||
};
|
||||
editor.update(text);
|
||||
}
|
||||
|
||||
function setupAutosave() {
|
||||
let timer: number;
|
||||
const saveDelay = 500;
|
||||
|
||||
editorInstanceRef.current!.getCoreEditor().on('change', () => {
|
||||
editor.getCoreEditor().on('change', () => {
|
||||
if (timer) {
|
||||
clearTimeout(timer);
|
||||
}
|
||||
|
@ -100,35 +152,34 @@ function EditorUI() {
|
|||
|
||||
function saveCurrentState() {
|
||||
try {
|
||||
const content = editorInstanceRef.current!.getCoreEditor().getValue();
|
||||
const content = editor.getCoreEditor().getValue();
|
||||
history.updateCurrentState(content);
|
||||
} catch (e) {
|
||||
// Ignoring saving error
|
||||
}
|
||||
}
|
||||
|
||||
setInputEditor(editorInstanceRef.current);
|
||||
setInputEditor(editor);
|
||||
setTextArea(editorRef.current!.querySelector('textarea'));
|
||||
|
||||
mappings.retrieveAutoCompleteInfo();
|
||||
|
||||
const unsubscribeResizer = subscribeResizeChecker(
|
||||
editorRef.current!,
|
||||
editorInstanceRef.current.getCoreEditor()
|
||||
);
|
||||
const unsubscribeResizer = subscribeResizeChecker(editorRef.current!, editor.getCoreEditor());
|
||||
setupAutosave();
|
||||
|
||||
return () => {
|
||||
unsubscribeResizer();
|
||||
mappings.clearSubscriptions();
|
||||
window.removeEventListener('hashchange', onHashChange);
|
||||
};
|
||||
}, [history, setInputEditor]);
|
||||
|
||||
useEffect(() => {
|
||||
applyCurrentSettings(editorInstanceRef.current!.getCoreEditor(), settings);
|
||||
const { current: editor } = editorInstanceRef;
|
||||
applyCurrentSettings(editor!.getCoreEditor(), settings);
|
||||
// Preserve legacy focus behavior after settings have updated.
|
||||
editorInstanceRef
|
||||
.current!.getCoreEditor()
|
||||
editor!
|
||||
.getCoreEditor()
|
||||
.getContainer()
|
||||
.focus();
|
||||
}, [settings]);
|
||||
|
|
|
@ -16,15 +16,18 @@
|
|||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import { useCallback } from 'react';
|
||||
import { useEditorActionContext } from '../contexts/editor_context';
|
||||
import { instance as registry } from '../contexts/editor_context/editor_registry';
|
||||
|
||||
export const useSetInputEditor = () => {
|
||||
const dispatch = useEditorActionContext();
|
||||
|
||||
return (editor: any) => {
|
||||
dispatch({ type: 'setInputEditor', payload: editor });
|
||||
registry.setInputEditor(editor);
|
||||
};
|
||||
return useCallback(
|
||||
(editor: any) => {
|
||||
dispatch({ type: 'setInputEditor', payload: editor });
|
||||
registry.setInputEditor(editor);
|
||||
},
|
||||
[dispatch]
|
||||
);
|
||||
};
|
||||
|
|
|
@ -104,25 +104,12 @@ export class LegacyCoreEditor implements CoreEditor {
|
|||
return this.editor.getValue();
|
||||
}
|
||||
|
||||
setValue(text: string, forceRetokenize: boolean): Promise<void> {
|
||||
async setValue(text: string, forceRetokenize: boolean): Promise<void> {
|
||||
const session = this.editor.getSession();
|
||||
session.setValue(text);
|
||||
return new Promise(resolve => {
|
||||
if (!forceRetokenize) {
|
||||
// resolve immediately
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
|
||||
// force update of tokens, but not on this thread to allow for ace rendering.
|
||||
setTimeout(function() {
|
||||
let i;
|
||||
for (i = 0; i < session.getLength(); i++) {
|
||||
session.getTokens(i);
|
||||
}
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
if (forceRetokenize) {
|
||||
await this.forceRetokenize();
|
||||
}
|
||||
}
|
||||
|
||||
getLineValue(lineNumber: number): string {
|
||||
|
@ -241,6 +228,20 @@ export class LegacyCoreEditor implements CoreEditor {
|
|||
return Boolean((this.editor as any).completer && (this.editor as any).completer.activated);
|
||||
}
|
||||
|
||||
private forceRetokenize() {
|
||||
const session = this.editor.getSession();
|
||||
return new Promise(resolve => {
|
||||
// force update of tokens, but not on this thread to allow for ace rendering.
|
||||
setTimeout(function() {
|
||||
let i;
|
||||
for (i = 0; i < session.getLength(); i++) {
|
||||
session.getTokens(i);
|
||||
}
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/camelcase
|
||||
private DO_NOT_USE_onPaste(text: string) {
|
||||
if (text && curl.detectCURL(text)) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue