[TSVB] Replaces EuiCodeEditor 👉 Monaco editor (#100684)

* Сhanged EuiCodeEditor to CodeEditor (monaco) at markdown_editor.js

* Added css lang support for monaco-editor.

* Added .d.ts for css lang import directly from monaco.

* Moved handlebars_url language to the code_editor.

Moved handlebars_url language registration to the code_editor.
Changed the way of registration of languages.

* Added merge for markdown_handlebars lang.

* Changed to simple markdown syntax.

Handlebars syntax breaks highlighting of special chars in markdown syntax.

* Removed useless mergeConfig function.

* Removed legacy import.

* Refactor export from monaco-editor.

* Fixed 'Could not find a declaration file for module'

* Fixed tests.

* Fixed typings errors.

* Added comment to typings.

* Fixed clearMarkdown for Monaco editor.

* Made changes based on suggestions.

* Fixed types errors.

* Fixed function tests types errors.

* Fixes, based on nits.

* Fixes based on nits.

Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
Yaroslav Kuznietsov 2021-06-18 21:25:11 +03:00 committed by GitHub
parent 61b6496476
commit a7444835dd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
24 changed files with 204 additions and 56 deletions

View file

@ -6,7 +6,8 @@
* Side Public License, v 1.
*/
import { LangModule as LangModuleType } from '../types';
import { ID } from './constants';
import { lexerRules } from './lexer_rules';
export const EsqlLang = { ID, lexerRules };
export const EsqlLang: LangModuleType = { ID, lexerRules };

View file

@ -0,0 +1,21 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
import { monaco } from './monaco_imports';
import { LangModule as LangModuleType } from './types';
function registerLanguage(language: LangModuleType) {
const { ID, lexerRules, languageConfiguration } = language;
monaco.languages.register({ id: ID });
monaco.languages.setMonarchTokensProvider(ID, lexerRules);
if (languageConfiguration) {
monaco.languages.setLanguageConfiguration(ID, languageConfiguration);
}
}
export { registerLanguage };

View file

@ -12,7 +12,13 @@ import './register_globals';
export { monaco } from './monaco_imports';
export { XJsonLang } from './xjson';
export { PainlessLang, PainlessContext, PainlessAutocompleteField } from './painless';
/* eslint-disable-next-line @kbn/eslint/module_migration */
import * as BarePluginApi from 'monaco-editor/esm/vs/editor/editor.api';
export { BarePluginApi };
import { registerLanguage } from './helpers';
import {
LangModule as LangModuleType,
CompleteLangModule as CompleteLangModuleType,
} from './types';
export { BarePluginApi, registerLanguage, LangModuleType, CompleteLangModuleType };

View file

@ -9,8 +9,9 @@
import { ID } from './constants';
import { lexerRules, languageConfiguration } from './lexer_rules';
import { getSuggestionProvider, getSyntaxErrors } from './language';
import { CompleteLangModule as CompleteLangModuleType } from '../types';
export const PainlessLang = {
export const PainlessLang: CompleteLangModuleType = {
ID,
getSuggestionProvider,
lexerRules,

View file

@ -10,6 +10,8 @@ import { XJsonLang } from './xjson';
import { PainlessLang } from './painless';
import { EsqlLang } from './esql';
import { monaco } from './monaco_imports';
import { registerLanguage } from './helpers';
// @ts-ignore
import xJsonWorkerSrc from '!!raw-loader!../../target_web/xjson.editor.worker.js';
// @ts-ignore
@ -20,14 +22,9 @@ import painlessWorkerSrc from '!!raw-loader!../../target_web/painless.editor.wor
/**
* Register languages and lexer rules
*/
monaco.languages.register({ id: XJsonLang.ID });
monaco.languages.setMonarchTokensProvider(XJsonLang.ID, XJsonLang.lexerRules);
monaco.languages.setLanguageConfiguration(XJsonLang.ID, XJsonLang.languageConfiguration);
monaco.languages.register({ id: PainlessLang.ID });
monaco.languages.setMonarchTokensProvider(PainlessLang.ID, PainlessLang.lexerRules);
monaco.languages.setLanguageConfiguration(PainlessLang.ID, PainlessLang.languageConfiguration);
monaco.languages.register({ id: EsqlLang.ID });
monaco.languages.setMonarchTokensProvider(EsqlLang.ID, EsqlLang.lexerRules);
registerLanguage(XJsonLang);
registerLanguage(PainlessLang);
registerLanguage(EsqlLang);
/**
* Create web workers by language ID

View file

@ -0,0 +1,22 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
import { monaco } from './monaco_imports';
export interface LangModule {
ID: string;
lexerRules: monaco.languages.IMonarchLanguage;
languageConfiguration?: monaco.languages.LanguageConfiguration;
getSuggestionProvider?: Function;
getSyntaxErrors?: Function;
}
export interface CompleteLangModule extends LangModule {
languageConfiguration: monaco.languages.LanguageConfiguration;
getSuggestionProvider: Function;
getSyntaxErrors: Function;
}

View file

@ -12,5 +12,6 @@
import './language';
import { ID } from './constants';
import { lexerRules, languageConfiguration } from './lexer_rules';
import { LangModule as LangModuleType } from '../types';
export const XJsonLang = { ID, lexerRules, languageConfiguration };
export const XJsonLang: LangModuleType = { ID, lexerRules, languageConfiguration };

View file

@ -17,6 +17,9 @@ import darkTheme from '@elastic/eui/dist/eui_theme_dark.json';
import lightTheme from '@elastic/eui/dist/eui_theme_light.json';
import { useUiSetting } from '../ui_settings';
import { Props } from './code_editor';
import './register_languages';
export * from './languages';
const LazyBaseEditor = React.lazy(() => import('./code_editor'));

View file

@ -6,4 +6,4 @@
* Side Public License, v 1.
*/
export const LANG = 'handlebars_url';
export const LANG = 'css';

View file

@ -0,0 +1,12 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
import { LangModuleType } from '@kbn/monaco';
import { lexerRules, languageConfiguration } from './language';
import { LANG } from './constants';
export const Lang: LangModuleType = { ID: LANG, lexerRules, languageConfiguration };

View file

@ -0,0 +1,12 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
/* eslint-disable @kbn/eslint/module_migration */
import { conf, language } from 'monaco-editor/esm/vs/basic-languages/css/css';
export { conf as languageConfiguration, language as lexerRules };

View file

@ -0,0 +1,9 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
export const LANG = 'handlebars';

View file

@ -0,0 +1,13 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
import { LangModuleType } from '@kbn/monaco';
import { languageConfiguration, lexerRules } from './language';
import { LANG } from './constants';
export const Lang: LangModuleType = { ID: LANG, languageConfiguration, lexerRules };

View file

@ -13,7 +13,7 @@
import { monaco } from '@kbn/monaco';
export const conf: monaco.languages.LanguageConfiguration = {
export const languageConfiguration: monaco.languages.LanguageConfiguration = {
wordPattern: /(-?\d*\.\d\w*)|([^\`\~\!\@\$\^\&\*\(\)\=\+\[\{\]\}\\\|\;\:\'\"\,\.\<\>\/\s]+)/g,
comments: {
@ -42,7 +42,7 @@ export const conf: monaco.languages.LanguageConfiguration = {
],
};
export const language: monaco.languages.IMonarchLanguage = {
export const lexerRules: monaco.languages.IMonarchLanguage = {
// Set defaultToken to invalid to see what you do not tokenize yet.
defaultToken: 'invalid',
tokenPostfix: '',

View file

@ -0,0 +1,13 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
import { Lang as CssLang } from './css';
import { Lang as HandlebarsLang } from './handlebars';
import { Lang as MarkdownLang } from './markdown';
export { CssLang, HandlebarsLang, MarkdownLang };

View file

@ -0,0 +1,9 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
export const LANG = 'markdown';

View file

@ -0,0 +1,12 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
import { LangModuleType } from '@kbn/monaco';
import { languageConfiguration, lexerRules } from './language';
import { LANG } from './constants';
export const Lang: LangModuleType = { ID: LANG, languageConfiguration, lexerRules };

View file

@ -0,0 +1,12 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
/* eslint-disable @kbn/eslint/module_migration */
import { conf, language } from 'monaco-editor/esm/vs/basic-languages/markdown/markdown';
export { conf as languageConfiguration, language as lexerRules };

View file

@ -0,0 +1,13 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
import { registerLanguage } from '@kbn/monaco';
import { CssLang, HandlebarsLang, MarkdownLang } from './languages';
registerLanguage(CssLang);
registerLanguage(HandlebarsLang);
registerLanguage(MarkdownLang);

View file

@ -9,18 +9,10 @@
import * as React from 'react';
import { monaco } from '@kbn/monaco';
import { Props as CodeEditorProps } from '../code_editor/code_editor';
import { CodeEditor } from '../code_editor';
import { LANG } from './constants';
import { language, conf } from './language';
import { CodeEditor, HandlebarsLang } from '../code_editor';
import './styles.scss';
monaco.languages.register({
id: LANG,
});
monaco.languages.setMonarchTokensProvider(LANG, language);
monaco.languages.setLanguageConfiguration(LANG, conf);
export interface UrlTemplateEditorVariable {
label: string;
title?: string;
@ -74,7 +66,7 @@ export const UrlTemplateEditor: React.FC<UrlTemplateEditorProps> = ({
return;
}
const { dispose } = monaco.languages.registerCompletionItemProvider(LANG, {
const { dispose } = monaco.languages.registerCompletionItemProvider(HandlebarsLang.ID, {
triggerCharacters: ['{', '/', '?', '&', '='],
provideCompletionItems(model, position, context, token) {
const { lineNumber } = position;
@ -132,7 +124,7 @@ export const UrlTemplateEditor: React.FC<UrlTemplateEditorProps> = ({
return (
<div className={'urlTemplateEditor__container'} onKeyDown={handleKeyDown}>
<Editor
languageId={LANG}
languageId={HandlebarsLang.ID}
height={height}
value={value}
onChange={onChange}

View file

@ -15,10 +15,9 @@ import React, { Component } from 'react';
import { createTickFormatter } from './lib/tick_formatter';
import { convertSeriesToVars } from './lib/convert_series_to_vars';
import _ from 'lodash';
import 'brace/mode/markdown';
import 'brace/theme/github';
import { CodeEditor, MarkdownLang } from '../../../../kibana_react/public';
import { EuiText, EuiCodeBlock, EuiSpacer, EuiTitle, EuiCodeEditor } from '@elastic/eui';
import { EuiText, EuiCodeBlock, EuiSpacer, EuiTitle } from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n/react';
@ -101,14 +100,13 @@ export class MarkdownEditor extends Component {
return (
<div className="tvbMarkdownEditor">
<div className="tvbMarkdownEditor__editor">
<EuiCodeEditor
onLoad={this.handleOnLoad}
mode="markdown"
theme="github"
width="100%"
height="100%"
name={`ace-${model.id}`}
setOptions={{ wrap: true, fontSize: '14px' }}
<CodeEditor
editorDidMount={this.handleOnLoad}
languageId={MarkdownLang.ID}
options={{
fontSize: '14px',
wordWrap: 'on',
}}
value={model.markdown}
onChange={this.handleChange}
/>

View file

@ -20,7 +20,6 @@ import {
EuiSpacer,
EuiTitle,
EuiHorizontalRule,
EuiCodeEditor,
} from '@elastic/eui';
// @ts-expect-error
import less from 'less/lib/less-browser';
@ -43,6 +42,7 @@ import { getDefaultQueryLanguage } from '../lib/get_default_query_language';
import { VisDataContext } from '../../contexts/vis_data_context';
import { PanelConfigProps, PANEL_CONFIG_TABS } from './types';
import { TimeseriesVisParams } from '../../../types';
import { CodeEditor, CssLang } from '../../../../../kibana_react/public';
const lessC = less(window, { env: 'production' });
@ -281,12 +281,10 @@ export class MarkdownPanelConfig extends Component<
</span>
</EuiTitle>
<EuiSpacer size="s" />
<EuiCodeEditor
mode="less"
theme="github"
width="100%"
name={`ace-css-${model.id}`}
setOptions={{ fontSize: '14px' }}
<CodeEditor
height="500px"
languageId={CssLang.ID}
options={{ fontSize: 14 }}
value={model.markdown_less ?? ''}
onChange={this.handleCSSChange}
/>

View file

@ -132,19 +132,18 @@ export class VisualBuilderPageObject extends FtrService {
}
public async clearMarkdown() {
// Since we use ACE editor and that isn't really storing its value inside
// a textarea we must really select all text and remove it, and cannot use
// clearValue().
await this.retry.waitForWithTimeout('text area is cleared', 20000, async () => {
const editor = await this.testSubjects.find('codeEditorContainer');
const $ = await editor.parseDomContent();
const value = $('.ace_line').text();
if (value.length > 0) {
this.log.debug('Clearing text area input');
this.waitForMarkdownTextAreaCleaned();
}
const input = await this.find.byCssSelector('.tvbMarkdownEditor__editor textarea');
await input.clickMouseButton();
await input.clearValueWithKeyboard();
return value.length === 0;
const linesContainer = await this.find.byCssSelector(
'.tvbMarkdownEditor__editor .view-lines'
);
// lines of code in monaco-editor
// text is not present in textarea
const lines = await linesContainer.findAllByClassName('mtk1');
return lines.length === 0;
});
}

4
typings/index.d.ts vendored
View file

@ -33,3 +33,7 @@ declare module 'axios/lib/adapters/xhr';
// See https://github.com/storybookjs/storybook/issues/11684
declare module 'react-syntax-highlighter/dist/cjs/create-element';
declare module 'react-syntax-highlighter/dist/cjs/prism-light';
// Monaco languages support
declare module 'monaco-editor/esm/vs/basic-languages/markdown/markdown';
declare module 'monaco-editor/esm/vs/basic-languages/css/css';