Grafana-UI: Switch CodeEditor to UMD @monao-editor/react (#33204)

* Grafana-UI: Switch CodeEditor to @monao-editor/react

* update copy script and paths

* hide context menu

* use __grafana_public_path__

* Fix value and language not updating

* update jaeger tsconfig

* update tsconfig

Co-authored-by: Ryan McKinley <ryantxu@gmail.com>
This commit is contained in:
Josh Hunt 2021-04-27 17:34:56 +01:00 committed by GitHub
parent ea3d3a2218
commit a13c5380a7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 173 additions and 122 deletions

View File

@ -172,8 +172,6 @@
"mini-css-extract-plugin": "0.9.0",
"mocha": "7.0.1",
"module-alias": "2.2.2",
"monaco-editor": "0.20.0",
"monaco-editor-webpack-plugin": "1.9.0",
"mutationobserver-shim": "0.3.3",
"ngtemplate-loader": "2.0.1",
"optimize-css-assets-webpack-plugin": "5.0.4",
@ -242,6 +240,7 @@
"classnames": "2.2.6",
"clipboard": "2.0.4",
"common-tags": "^1.8.0",
"copy-webpack-plugin": "6.4.1",
"core-js": "3.10.0",
"d3": "5.15.0",
"d3-force": "^2.1.1",

View File

@ -11,10 +11,5 @@
},
"exclude": ["dist", "node_modules"],
"extends": "@grafana/tsconfig",
"include": [
"src/**/*.ts*",
"../../public/app/types/jquery/*.ts",
"../../public/app/types/sanitize-url.d.ts",
"../../public/app/types/svg.d.ts"
]
"include": ["src/**/*.ts*", "../../public/app/types/jquery/*.ts", "../../public/app/types/*.d.ts"]
}

View File

@ -57,7 +57,8 @@
"jquery": "3.5.1",
"lodash": "4.17.21",
"moment": "2.24.0",
"monaco-editor": "0.20.0",
"@monaco-editor/react": "4.1.1",
"monaco-editor": "0.21.2",
"papaparse": "5.3.0",
"rc-cascader": "1.0.1",
"rc-drawer": "3.1.3",
@ -71,7 +72,6 @@
"react-dom": "17.0.1",
"react-highlight-words": "0.16.0",
"react-hook-form": "5.1.3",
"react-monaco-editor": "0.36.0",
"react-popper": "2.2.4",
"react-storybook-addon-props-combinations": "1.1.0",
"react-table": "7.0.0",

View File

@ -1,15 +1,36 @@
import React from 'react';
import { withTheme } from '../../themes';
import { Themeable } from '../../types';
import { CodeEditorProps } from './types';
import { Monaco, MonacoEditor as MonacoEditorType, CodeEditorProps, MonacoOptions } from './types';
import { registerSuggestions } from './suggestions';
import ReactMonaco from 'react-monaco-editor';
import * as monaco from 'monaco-editor/esm/vs/editor/editor.api';
import MonacoEditor, { loader as monacoEditorLoader } from '@monaco-editor/react';
import type * as monacoType from 'monaco-editor/esm/vs/editor/editor.api';
type Props = CodeEditorProps & Themeable;
let initalized = false;
function initMonoco() {
if (initalized) {
return;
}
monacoEditorLoader.config({
paths: {
vs: (window.__grafana_public_path__ ?? 'public/') + 'lib/monaco/min/vs',
},
});
initalized = true;
}
class UnthemedCodeEditor extends React.PureComponent<Props> {
completionCancel?: monaco.IDisposable;
completionCancel?: monacoType.IDisposable;
monaco?: Monaco;
constructor(props: Props) {
super(props);
initMonoco();
}
componentWillUnmount() {
if (this.completionCancel) {
@ -19,13 +40,19 @@ class UnthemedCodeEditor extends React.PureComponent<Props> {
componentDidUpdate(oldProps: Props) {
const { getSuggestions, language } = this.props;
if (getSuggestions) {
// Language changed
if (language !== oldProps.language) {
if (this.completionCancel) {
this.completionCancel.dispose();
}
this.completionCancel = registerSuggestions(language, getSuggestions);
if (language !== oldProps.language) {
if (this.completionCancel) {
this.completionCancel.dispose();
}
if (!this.monaco) {
console.warn('Monaco instance not loaded yet');
return;
}
if (getSuggestions) {
this.completionCancel = registerSuggestions(this.monaco, language, getSuggestions);
}
}
}
@ -40,14 +67,16 @@ class UnthemedCodeEditor extends React.PureComponent<Props> {
}
};
editorWillMount = (m: typeof monaco) => {
handleBeforeMount = (monaco: Monaco) => {
this.monaco = monaco;
const { language, getSuggestions } = this.props;
if (getSuggestions) {
this.completionCancel = registerSuggestions(language, getSuggestions);
this.completionCancel = registerSuggestions(monaco, language, getSuggestions);
}
};
editorDidMount = (editor: monaco.editor.IStandaloneCodeEditor) => {
handleOnMount = (editor: MonacoEditorType, monaco: Monaco) => {
const { onSave, onEditorDidMount } = this.props;
this.getEditorValue = () => editor.getValue();
@ -68,19 +97,24 @@ class UnthemedCodeEditor extends React.PureComponent<Props> {
const value = this.props.value ?? '';
const longText = value.length > 100;
const options: monaco.editor.IEditorConstructionOptions = {
const options: MonacoOptions = {
wordWrap: 'off',
codeLens: false, // not included in the bundle
tabSize: 2,
codeLens: false,
contextmenu: false,
minimap: {
enabled: longText && showMiniMap,
renderCharacters: false,
},
readOnly,
lineNumbersMinChars: 4,
lineDecorationsWidth: 0,
overviewRulerBorder: false,
automaticLayout: true,
};
if (!showLineNumbers) {
options.glyphMargin = false;
options.folding = false;
@ -91,7 +125,7 @@ class UnthemedCodeEditor extends React.PureComponent<Props> {
return (
<div onBlur={this.onBlur}>
<ReactMonaco
<MonacoEditor
width={width}
height={height}
language={language}
@ -101,8 +135,8 @@ class UnthemedCodeEditor extends React.PureComponent<Props> {
...options,
...(monacoOptions ?? {}),
}}
editorWillMount={this.editorWillMount}
editorDidMount={this.editorDidMount}
beforeMount={this.handleBeforeMount}
onMount={this.handleOnMount}
/>
</div>
);

View File

@ -1,6 +1,6 @@
import * as monaco from 'monaco-editor/esm/vs/editor/editor.api';
import type * as monacoType from 'monaco-editor/esm/vs/editor/editor.api';
import { CodeEditorSuggestionItem, CodeEditorSuggestionItemKind, CodeEditorSuggestionProvider } from './types';
import { CodeEditorSuggestionItem, CodeEditorSuggestionItemKind, CodeEditorSuggestionProvider, Monaco } from './types';
/**
* @internal -- only exported for tests
@ -30,11 +30,12 @@ export function findInsertIndex(line: string): { index: number; prefix: string }
}
function getCompletionItems(
monaco: Monaco,
prefix: string,
suggestions: CodeEditorSuggestionItem[],
range: monaco.IRange
): monaco.languages.CompletionItem[] {
const items: monaco.languages.CompletionItem[] = [];
range: monacoType.IRange
): monacoType.languages.CompletionItem[] {
const items: monacoType.languages.CompletionItem[] = [];
for (const suggestion of suggestions) {
if (prefix && !suggestion.label.startsWith(prefix)) {
continue; // skip non-matching suggestions
@ -42,7 +43,7 @@ function getCompletionItems(
items.push({
...suggestion,
kind: mapKinds(suggestion.kind),
kind: mapKinds(monaco, suggestion.kind),
range,
insertText: suggestion.insertText ?? suggestion.label,
});
@ -50,7 +51,7 @@ function getCompletionItems(
return items;
}
function mapKinds(sug?: CodeEditorSuggestionItemKind): monaco.languages.CompletionItemKind {
function mapKinds(monaco: Monaco, sug?: CodeEditorSuggestionItemKind): monacoType.languages.CompletionItemKind {
switch (sug) {
case CodeEditorSuggestionItemKind.Method:
return monaco.languages.CompletionItemKind.Method;
@ -70,9 +71,10 @@ function mapKinds(sug?: CodeEditorSuggestionItemKind): monaco.languages.Completi
* @alpha
*/
export function registerSuggestions(
monaco: Monaco,
language: string,
getSuggestions: CodeEditorSuggestionProvider
): monaco.IDisposable | undefined {
): monacoType.IDisposable | undefined {
if (!language || !getSuggestions) {
return undefined;
}
@ -91,7 +93,7 @@ export function registerSuggestions(
if (context.triggerCharacter === '$') {
range.startColumn = position.column - 1;
return {
suggestions: getCompletionItems('$', getSuggestions(), range),
suggestions: getCompletionItems(monaco, '$', getSuggestions(), range),
};
}
@ -106,7 +108,7 @@ export function registerSuggestions(
const { index, prefix } = findInsertIndex(currentLine);
range.startColumn = index + 1;
const suggestions = getCompletionItems(prefix, getSuggestions(), range);
const suggestions = getCompletionItems(monaco, prefix, getSuggestions(), range);
if (suggestions.length) {
// NOTE, this will replace any language provided suggestions
return { suggestions };

View File

@ -1,10 +1,12 @@
// We use `import type` to guarentee it'll be erased from the JS and it doesnt accidently bundle monaco
import type * as monaco from 'monaco-editor/esm/vs/editor/editor.api';
import type * as monacoType from 'monaco-editor/esm/vs/editor/editor.api';
export type CodeEditorChangeHandler = (value: string) => void;
export type CodeEditorSuggestionProvider = () => CodeEditorSuggestionItem[];
export type MonacoEditor = monaco.editor.IStandaloneCodeEditor;
export type Monaco = typeof monacoType;
export type MonacoEditor = monacoType.editor.IStandaloneCodeEditor;
export type MonacoOptions = monacoType.editor.IStandaloneEditorConstructionOptions;
export interface CodeEditorProps {
value: string;
@ -15,14 +17,14 @@ export interface CodeEditorProps {
readOnly?: boolean;
showMiniMap?: boolean;
showLineNumbers?: boolean;
monacoOptions?: monaco.editor.IEditorConstructionOptions;
monacoOptions?: MonacoOptions;
/**
* Callback after the editor has mounted that gives you raw access to monaco
*
* @alpha -- experimental
*/
onEditorDidMount?: (editor: monaco.editor.IStandaloneCodeEditor) => void;
onEditorDidMount?: (editor: monacoType.editor.IStandaloneCodeEditor) => void;
/** Handler to be performed when editor is blurred */
onBlur?: CodeEditorChangeHandler;

View File

@ -12,5 +12,5 @@
},
"exclude": ["dist", "node_modules"],
"extends": "@grafana/tsconfig",
"include": ["src/**/*.ts*", "../../public/app/types/sanitize-url.d.ts", "../../public/app/types/svg.d.ts"]
"include": ["src/**/*.ts*", "../../public/app/types/*.d.ts"]
}

View File

@ -7,5 +7,5 @@
"typeRoots": ["node_modules/@types"]
},
"extends": "@grafana/tsconfig",
"include": ["src/**/*.ts*", "typings", "../../public/app/types/jquery/*.ts", "../../public/app/types/svg.d.ts"]
"include": ["src/**/*.ts*", "typings", "../../public/app/types/jquery/*.ts", "../../public/app/types/*.d.ts"]
}

View File

@ -4,12 +4,12 @@ declare let __webpack_nonce__: string;
/**
* Check if we are hosting files on cdn and set webpack public path
*/
if ((window as any).public_cdn_path) {
__webpack_public_path__ = (window as any).public_cdn_path;
if (window.public_cdn_path) {
__webpack_public_path__ = window.public_cdn_path;
}
// This is a path to the public folder without '/build'
(window as any).__grafana_public_path__ =
window.__grafana_public_path__ =
__webpack_public_path__.substring(0, __webpack_public_path__.lastIndexOf('build/')) || __webpack_public_path__;
if ((window as any).nonce) {

6
public/app/types/window.d.ts vendored Normal file
View File

@ -0,0 +1,6 @@
export declare global {
interface Window {
__grafana_public_path__: string;
public_cdn_path: string;
}
}

1
public/lib/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
monaco/

View File

@ -1,7 +1,7 @@
const fs = require('fs-extra');
const path = require('path');
const MonacoWebpackPlugin = require('monaco-editor-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const getBabelConfig = require('./babel.config');
class CopyUniconsPlugin {
@ -75,51 +75,23 @@ module.exports = {
},
plugins: [
new CopyUniconsPlugin(),
new MonacoWebpackPlugin({
// available options are documented at https://github.com/Microsoft/monaco-editor-webpack-plugin#options
filename: 'monaco-[name].worker.js',
languages: ['json', 'markdown', 'html', 'sql', 'mysql', 'pgsql', 'javascript'],
features: [
'!accessibilityHelp',
'bracketMatching',
'caretOperations',
'!clipboard',
'!codeAction',
'!codelens',
'!colorDetector',
'!comment',
'!contextmenu',
'!coreCommands',
'!cursorUndo',
'!dnd',
'!find',
'folding',
'!fontZoom',
'!format',
'!gotoError',
'!gotoLine',
'!gotoSymbol',
'!hover',
'!iPadShowKeyboard',
'!inPlaceReplace',
'!inspectTokens',
'!linesOperations',
'!links',
'!multicursor',
'parameterHints',
'!quickCommand',
'!quickOutline',
'!referenceSearch',
'!rename',
'!smartSelect',
'!snippets',
'suggest',
'!toggleHighContrast',
'!toggleTabFocusMode',
'!transpose',
'!wordHighlighter',
'!wordOperations',
'!wordPartOperations',
new CopyWebpackPlugin({
patterns: [
{
context: path.resolve(__dirname, '../../node_modules/monaco-editor/'),
from: 'min/vs/**',
to: '../lib/monaco/', // inside the public/build folder
globOptions: {
ignore: [
'**/language/typescript/**', // 10mb
'**/*.map', // debug files
],
},
},
// {
// from: './node_modules/@kusto/monaco-kusto/release/min/',
// to: 'monaco/min/vs/language/kusto/',
// },
],
}),
],

View File

@ -3648,6 +3648,22 @@
resolved "https://registry.yarnpkg.com/@mochajs/json-file-reporter/-/json-file-reporter-1.2.0.tgz#036917c90c0291dab5dd4e14323da813108295c8"
integrity sha512-uAxHLKG+x0qkYnyQRBoHhXJCF7r2BS87Sdz3VKj19QB6Cxjs25yjIgO4X0PJpfa6CawA4BST+V2Q6y9iiNrWqg==
"@monaco-editor/loader@^1.0.1":
version "1.0.1"
resolved "https://registry.yarnpkg.com/@monaco-editor/loader/-/loader-1.0.1.tgz#7068c9b07bbc65387c0e7a4df6dac0a326155905"
integrity sha512-hycGOhLqLYjnD0A/FHs56covEQWnDFrSnm/qLKkB/yoeayQ7ju+Vaj4SdTojGrXeY6jhMDx59map0+Jqwquh1Q==
dependencies:
state-local "^1.0.6"
"@monaco-editor/react@4.1.1":
version "4.1.1"
resolved "https://registry.yarnpkg.com/@monaco-editor/react/-/react-4.1.1.tgz#c5579c09e9a06a68eae56ebd2b5df67cdd2d3867"
integrity sha512-A9aZAb4fa81unRfwo63dHJpX5hgppYdMTdQVk2RAT7viiFwdfSfxz+k4WHiFdAdhFWYH/99VSec0vpZbQd0yng==
dependencies:
"@monaco-editor/loader" "^1.0.1"
prop-types "^15.7.2"
state-local "^1.0.7"
"@mrmlnc/readdir-enhanced@^2.2.1":
version "2.2.1"
resolved "https://registry.yarnpkg.com/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz#524af240d1a360527b730475ecfa1344aa540dde"
@ -6010,14 +6026,6 @@
"@types/prop-types" "*"
csstype "^2.2.0"
"@types/react@^16.x":
version "16.9.35"
resolved "https://registry.yarnpkg.com/@types/react/-/react-16.9.35.tgz#a0830d172e8aadd9bd41709ba2281a3124bbd368"
integrity sha512-q0n0SsWcGc8nDqH2GJfWQWUOmZSJhXV64CjVN5SvcNti3TdEaA3AH0D8DwNmMdzjMAC/78tB8nAZIlV8yTz+zQ==
dependencies:
"@types/prop-types" "*"
csstype "^2.2.0"
"@types/recompose@^0.30.7":
version "0.30.7"
resolved "https://registry.yarnpkg.com/@types/recompose/-/recompose-0.30.7.tgz#0d47f3da3bdf889a4f36d4ca7531fac1eee1c6bd"
@ -9464,6 +9472,23 @@ copy-webpack-plugin@5.1.2:
serialize-javascript "^4.0.0"
webpack-log "^2.0.0"
copy-webpack-plugin@6.4.1:
version "6.4.1"
resolved "https://registry.yarnpkg.com/copy-webpack-plugin/-/copy-webpack-plugin-6.4.1.tgz#138cd9b436dbca0a6d071720d5414848992ec47e"
integrity sha512-MXyPCjdPVx5iiWyl40Va3JGh27bKzOTNY3NjUTrosD2q7dR/cLD0013uqJ3BpFbUjyONINjb6qI7nDIJujrMbA==
dependencies:
cacache "^15.0.5"
fast-glob "^3.2.4"
find-cache-dir "^3.3.1"
glob-parent "^5.1.1"
globby "^11.0.1"
loader-utils "^2.0.0"
normalize-path "^3.0.0"
p-limit "^3.0.2"
schema-utils "^3.0.0"
serialize-javascript "^5.0.1"
webpack-sources "^1.4.3"
core-js-compat@^3.1.1:
version "3.3.2"
resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.3.2.tgz#1096c989c1b929ede06b5b6b4768dc4439078c03"
@ -12339,6 +12364,18 @@ fast-glob@^3.1.1:
micromatch "^4.0.2"
picomatch "^2.2.1"
fast-glob@^3.2.4:
version "3.2.5"
resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.5.tgz#7939af2a656de79a4f1901903ee8adcaa7cb9661"
integrity sha512-2DtFcgT68wiTTiwZ2hNdJfcHNke9XOfnwmBRWXhmeKM8rF0TGwmC/Qto3S7RoZKp5cilZbxzO5iTNTQsJ+EeDg==
dependencies:
"@nodelib/fs.stat" "^2.0.2"
"@nodelib/fs.walk" "^1.2.3"
glob-parent "^5.1.0"
merge2 "^1.3.0"
micromatch "^4.0.2"
picomatch "^2.2.1"
fast-json-parse@^1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/fast-json-parse/-/fast-json-parse-1.0.3.tgz#43e5c61ee4efa9265633046b770fb682a7577c4d"
@ -13235,6 +13272,13 @@ glob-parent@^5.0.0, glob-parent@^5.1.0, glob-parent@~5.1.0:
dependencies:
is-glob "^4.0.1"
glob-parent@^5.1.1:
version "5.1.2"
resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4"
integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==
dependencies:
is-glob "^4.0.1"
glob-promise@^3.4.0:
version "3.4.0"
resolved "https://registry.yarnpkg.com/glob-promise/-/glob-promise-3.4.0.tgz#b6b8f084504216f702dc2ce8c9bc9ac8866fdb20"
@ -17400,17 +17444,10 @@ moment@^2.27.0:
resolved "https://registry.yarnpkg.com/moment/-/moment-2.27.0.tgz#8bff4e3e26a236220dfe3e36de756b6ebaa0105d"
integrity sha512-al0MUK7cpIcglMv3YF13qSgdAIqxHTO7brRtaz3DlSULbqfazqkc5kEjNrLDOM7fsjshoFIihnU8snrP7zUvhQ==
monaco-editor-webpack-plugin@1.9.0:
version "1.9.0"
resolved "https://registry.yarnpkg.com/monaco-editor-webpack-plugin/-/monaco-editor-webpack-plugin-1.9.0.tgz#5b547281b9f404057dc5d8c5722390df9ac90be6"
integrity sha512-tOiiToc94E1sb50BgZ8q8WK/bxus77SRrwCqIpAB5er3cpX78SULbEBY4YPOB8kDolOzKRt30WIHG/D6gz69Ww==
dependencies:
loader-utils "^1.2.3"
monaco-editor@*, monaco-editor@0.20.0:
version "0.20.0"
resolved "https://registry.yarnpkg.com/monaco-editor/-/monaco-editor-0.20.0.tgz#5d5009343a550124426cb4d965a4d27a348b4dea"
integrity sha512-hkvf4EtPJRMQlPC3UbMoRs0vTAFAYdzFQ+gpMb8A+9znae1c43q8Mab9iVsgTcg/4PNiLGGn3SlDIa8uvK1FIQ==
monaco-editor@0.21.2:
version "0.21.2"
resolved "https://registry.yarnpkg.com/monaco-editor/-/monaco-editor-0.21.2.tgz#37054e63e480d51a2dd17d609dcfb192304d5605"
integrity sha512-jS51RLuzMaoJpYbu7F6TPuWpnWTLD4kjRW0+AZzcryvbxrTwhNy1KC9yboyKpgMTahpUbDUsuQULoo0GV1EPqg==
moo-color@^1.0.2:
version "1.0.2"
@ -20808,15 +20845,6 @@ react-loadable@5.5.0:
dependencies:
prop-types "^15.5.0"
react-monaco-editor@0.36.0:
version "0.36.0"
resolved "https://registry.yarnpkg.com/react-monaco-editor/-/react-monaco-editor-0.36.0.tgz#ac085c14f25fb072514c925596f6a06a711ee078"
integrity sha512-JVA5SZhOoYZ0DCdTwYgagtRb3jHo4KN7TVFiJauG+ZBAJWfDSTzavPIrwzWbgu8ahhDqDk4jUcYlOJL2BC/0UA==
dependencies:
"@types/react" "^16.x"
monaco-editor "*"
prop-types "^15.7.2"
react-popper-tooltip@^3.1.1:
version "3.1.1"
resolved "https://registry.yarnpkg.com/react-popper-tooltip/-/react-popper-tooltip-3.1.1.tgz#329569eb7b287008f04fcbddb6370452ad3f9eac"
@ -22516,6 +22544,13 @@ serialize-javascript@^4.0.0:
dependencies:
randombytes "^2.1.0"
serialize-javascript@^5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-5.0.1.tgz#7886ec848049a462467a97d3d918ebb2aaf934f4"
integrity sha512-SaaNal9imEO737H2c05Og0/8LUXG7EnsZyMa8MzkmuHoELfT6txuj0cMqRj6zfPKnmQ1yasR4PCJc8x+M4JSPA==
dependencies:
randombytes "^2.1.0"
serve-favicon@^2.5.0:
version "2.5.0"
resolved "https://registry.yarnpkg.com/serve-favicon/-/serve-favicon-2.5.0.tgz#935d240cdfe0f5805307fdfe967d88942a2cbcf0"
@ -23137,6 +23172,11 @@ stacktrace-js@^2.0.0:
stack-generator "^2.0.4"
stacktrace-gps "^3.0.3"
state-local@^1.0.6, state-local@^1.0.7:
version "1.0.7"
resolved "https://registry.yarnpkg.com/state-local/-/state-local-1.0.7.tgz#da50211d07f05748d53009bee46307a37db386d5"
integrity sha512-HTEHMNieakEnoe33shBYcZ7NX83ACUjCu8c40iOGEZsngj9zRnkqS9j1pqQPXwobB0ZcVTk27REb7COQ0UR59w==
state-toggle@^1.0.0:
version "1.0.3"
resolved "https://registry.yarnpkg.com/state-toggle/-/state-toggle-1.0.3.tgz#e123b16a88e143139b09c6852221bc9815917dfe"