This commit is contained in:
parent
31c8f0c821
commit
860f7e4b30
|
@ -202,6 +202,7 @@
|
|||
"minimatch": "^3.0.4",
|
||||
"moment": "^2.24.0",
|
||||
"moment-timezone": "^0.5.27",
|
||||
"monaco-editor": "~0.17.0",
|
||||
"mustache": "2.3.2",
|
||||
"ngreact": "0.5.1",
|
||||
"node-fetch": "1.7.3",
|
||||
|
@ -220,7 +221,9 @@
|
|||
"react-grid-layout": "^0.16.2",
|
||||
"react-input-range": "^1.3.0",
|
||||
"react-markdown": "^3.4.1",
|
||||
"react-monaco-editor": "~0.27.0",
|
||||
"react-redux": "^5.1.2",
|
||||
"react-resize-detector": "^4.2.0",
|
||||
"react-router-dom": "^4.3.1",
|
||||
"react-sizeme": "^2.3.6",
|
||||
"reactcss": "1.2.3",
|
||||
|
@ -331,6 +334,7 @@
|
|||
"@types/react": "^16.9.11",
|
||||
"@types/react-dom": "^16.9.4",
|
||||
"@types/react-redux": "^6.0.6",
|
||||
"@types/react-resize-detector": "^4.0.1",
|
||||
"@types/react-router-dom": "^4.3.1",
|
||||
"@types/react-virtualized": "^9.18.7",
|
||||
"@types/redux": "^3.6.31",
|
||||
|
|
|
@ -98,8 +98,9 @@ export default {
|
|||
'^.+\\.html?$': 'jest-raw-loader',
|
||||
},
|
||||
transformIgnorePatterns: [
|
||||
// ignore all node_modules except @elastic/eui which requires babel transforms to handle dynamic import()
|
||||
'[/\\\\]node_modules(?![\\/\\\\]@elastic[\\/\\\\]eui)[/\\\\].+\\.js$',
|
||||
// ignore all node_modules except @elastic/eui and monaco-editor which both require babel transforms to handle dynamic import()
|
||||
// since ESM modules are not natively supported in Jest yet (https://github.com/facebook/jest/issues/4842)
|
||||
'[/\\\\]node_modules(?![\\/\\\\]@elastic[\\/\\\\]eui)(?![\\/\\\\]monaco-editor)[/\\\\].+\\.js$',
|
||||
'packages/kbn-pm/dist/index.js'
|
||||
],
|
||||
snapshotSerializers: [
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# Editor Component
|
||||
# Code Editor Component
|
||||
|
||||
This re-usable code editor component was built as a layer of abstraction on top of the [Monaco Code Editor](https://microsoft.github.io/monaco-editor/) (and the [React Monaco Editor component](https://github.com/react-monaco-editor/react-monaco-editor)). The goal of this component is to expose a set of the most-used, most-helpful features from Monaco in a way that's easy to use out of the box. If a use case requires additional features, this component still allows access to all other Monaco features.
|
||||
|
33
src/plugins/kibana_react/public/code_editor/__snapshots__/code_editor.test.tsx.snap
generated
Normal file
33
src/plugins/kibana_react/public/code_editor/__snapshots__/code_editor.test.tsx.snap
generated
Normal file
|
@ -0,0 +1,33 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`is rendered 1`] = `
|
||||
<Fragment>
|
||||
<MonacoEditor
|
||||
defaultValue=""
|
||||
editorDidMount={[Function]}
|
||||
editorWillMount={[Function]}
|
||||
height={250}
|
||||
language="loglang"
|
||||
onChange={[Function]}
|
||||
options={Object {}}
|
||||
overrideServices={Object {}}
|
||||
theme="euiColors"
|
||||
value="
|
||||
[Sun Mar 7 20:54:27 2004] [notice] [client xx.xx.xx.xx] This is a notice!
|
||||
[Sun Mar 7 20:58:27 2004] [info] [client xx.xx.xx.xx] (104)Connection reset by peer: client stopped connection before send body completed
|
||||
[Sun Mar 7 21:16:17 2004] [error] [client xx.xx.xx.xx] File does not exist: /home/httpd/twiki/view/Main/WebHome
|
||||
"
|
||||
width="100%"
|
||||
/>
|
||||
<ResizeDetector
|
||||
handleHeight={true}
|
||||
handleWidth={true}
|
||||
nodeType="div"
|
||||
onResize={[Function]}
|
||||
querySelector={null}
|
||||
refreshRate={1000}
|
||||
skipOnMount={false}
|
||||
targetDomEl={null}
|
||||
/>
|
||||
</Fragment>
|
||||
`;
|
118
src/plugins/kibana_react/public/code_editor/code_editor.test.tsx
Normal file
118
src/plugins/kibana_react/public/code_editor/code_editor.test.tsx
Normal file
|
@ -0,0 +1,118 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { CodeEditor } from './code_editor';
|
||||
import * as monacoEditor from 'monaco-editor/esm/vs/editor/editor.api';
|
||||
import { shallow } from 'enzyme';
|
||||
|
||||
import 'monaco-editor/esm/vs/basic-languages/html/html.contribution.js';
|
||||
|
||||
// A sample language definition with a few example tokens
|
||||
const simpleLogLang: monacoEditor.languages.IMonarchLanguage = {
|
||||
tokenizer: {
|
||||
root: [
|
||||
[/\[error.*/, 'constant'],
|
||||
[/\[notice.*/, 'variable'],
|
||||
[/\[info.*/, 'string'],
|
||||
[/\[[a-zA-Z 0-9:]+\]/, 'tag'],
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
monacoEditor.languages.register({ id: 'loglang' });
|
||||
monacoEditor.languages.setMonarchTokensProvider('loglang', simpleLogLang);
|
||||
|
||||
const logs = `
|
||||
[Sun Mar 7 20:54:27 2004] [notice] [client xx.xx.xx.xx] This is a notice!
|
||||
[Sun Mar 7 20:58:27 2004] [info] [client xx.xx.xx.xx] (104)Connection reset by peer: client stopped connection before send body completed
|
||||
[Sun Mar 7 21:16:17 2004] [error] [client xx.xx.xx.xx] File does not exist: /home/httpd/twiki/view/Main/WebHome
|
||||
`;
|
||||
|
||||
test('is rendered', () => {
|
||||
const component = shallow(
|
||||
<CodeEditor languageId="loglang" height={250} value={logs} onChange={() => {}} />
|
||||
);
|
||||
|
||||
expect(component).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('editor mount setup', () => {
|
||||
const suggestionProvider = {
|
||||
provideCompletionItems: (
|
||||
model: monacoEditor.editor.ITextModel,
|
||||
position: monacoEditor.Position
|
||||
) => ({ suggestions: [] }),
|
||||
};
|
||||
const signatureProvider = {
|
||||
provideSignatureHelp: () => ({ signatures: [], activeParameter: 0, activeSignature: 0 }),
|
||||
};
|
||||
const hoverProvider = {
|
||||
provideHover: (model: monacoEditor.editor.ITextModel, position: monacoEditor.Position) => ({
|
||||
contents: [],
|
||||
}),
|
||||
};
|
||||
|
||||
const editorWillMount = jest.fn();
|
||||
|
||||
monacoEditor.languages.onLanguage = jest.fn((languageId, func) => {
|
||||
expect(languageId).toBe('loglang');
|
||||
|
||||
// Call the function immediately so we can see our providers
|
||||
// get setup without a monaco editor setting up completely
|
||||
func();
|
||||
}) as any;
|
||||
|
||||
monacoEditor.languages.registerCompletionItemProvider = jest.fn();
|
||||
monacoEditor.languages.registerSignatureHelpProvider = jest.fn();
|
||||
monacoEditor.languages.registerHoverProvider = jest.fn();
|
||||
|
||||
monacoEditor.editor.defineTheme = jest.fn();
|
||||
|
||||
const wrapper = shallow(
|
||||
<CodeEditor
|
||||
languageId="loglang"
|
||||
value={logs}
|
||||
onChange={() => {}}
|
||||
editorWillMount={editorWillMount}
|
||||
suggestionProvider={suggestionProvider}
|
||||
signatureProvider={signatureProvider}
|
||||
hoverProvider={hoverProvider}
|
||||
/>
|
||||
);
|
||||
|
||||
const instance = wrapper.instance() as CodeEditor;
|
||||
instance._editorWillMount(monacoEditor);
|
||||
|
||||
// Verify our mount callback will be called
|
||||
expect(editorWillMount.mock.calls.length).toBe(1);
|
||||
|
||||
// Verify our theme will be setup
|
||||
expect((monacoEditor.editor.defineTheme as jest.Mock).mock.calls.length).toBe(1);
|
||||
|
||||
// Verify our language features have been registered
|
||||
expect((monacoEditor.languages.onLanguage as jest.Mock).mock.calls.length).toBe(1);
|
||||
expect(
|
||||
(monacoEditor.languages.registerCompletionItemProvider as jest.Mock).mock.calls.length
|
||||
).toBe(1);
|
||||
expect(
|
||||
(monacoEditor.languages.registerSignatureHelpProvider as jest.Mock).mock.calls.length
|
||||
).toBe(1);
|
||||
expect((monacoEditor.languages.registerHoverProvider as jest.Mock).mock.calls.length).toBe(1);
|
||||
});
|
|
@ -1,7 +1,20 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
|
@ -86,7 +99,7 @@ export interface Props {
|
|||
useDarkTheme?: boolean;
|
||||
}
|
||||
|
||||
export class Editor extends React.Component<Props, {}> {
|
||||
export class CodeEditor extends React.Component<Props, {}> {
|
||||
_editor: monacoEditor.editor.IStandaloneCodeEditor | null = null;
|
||||
|
||||
_editorWillMount = (monaco: typeof monacoEditor) => {
|
|
@ -1,7 +1,20 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import * as monacoEditor from 'monaco-editor/esm/vs/editor/editor.api';
|
||||
|
27
src/plugins/kibana_react/public/code_editor/index.tsx
Normal file
27
src/plugins/kibana_react/public/code_editor/index.tsx
Normal file
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import React from 'react';
|
||||
import { useUiSetting } from '../ui_settings';
|
||||
import { CodeEditor as BaseEditor, Props } from './code_editor';
|
||||
|
||||
export const CodeEditor: React.FunctionComponent<Props> = props => {
|
||||
const darkMode = useUiSetting<boolean>('theme:darkMode');
|
||||
|
||||
return <BaseEditor {...props} useDarkTheme={darkMode} />;
|
||||
};
|
|
@ -17,6 +17,7 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
export * from './code_editor';
|
||||
export * from './saved_objects';
|
||||
export * from './exit_full_screen_button';
|
||||
export * from './context';
|
||||
|
|
|
@ -1,46 +0,0 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Storyshots components/Editor custom log language 1`] = `
|
||||
<div>
|
||||
<div
|
||||
className="react-monaco-editor-container"
|
||||
style={
|
||||
Object {
|
||||
"height": "250px",
|
||||
"width": "100%",
|
||||
}
|
||||
}
|
||||
/>
|
||||
<div />
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`Storyshots components/Editor default 1`] = `
|
||||
<div>
|
||||
<div
|
||||
className="react-monaco-editor-container"
|
||||
style={
|
||||
Object {
|
||||
"height": "250px",
|
||||
"width": "100%",
|
||||
}
|
||||
}
|
||||
/>
|
||||
<div />
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`Storyshots components/Editor html 1`] = `
|
||||
<div>
|
||||
<div
|
||||
className="react-monaco-editor-container"
|
||||
style={
|
||||
Object {
|
||||
"height": "250px",
|
||||
"width": "100%",
|
||||
}
|
||||
}
|
||||
/>
|
||||
<div />
|
||||
</div>
|
||||
`;
|
|
@ -1,55 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { action } from '@storybook/addon-actions';
|
||||
import { storiesOf } from '@storybook/react';
|
||||
import React from 'react';
|
||||
import * as monacoEditor from 'monaco-editor/esm/vs/editor/editor.api';
|
||||
import { Editor } from '../editor';
|
||||
|
||||
import 'monaco-editor/esm/vs/basic-languages/html/html.contribution.js';
|
||||
|
||||
// A sample language definition with a few example tokens
|
||||
const simpleLogLang: monacoEditor.languages.IMonarchLanguage = {
|
||||
tokenizer: {
|
||||
root: [
|
||||
[/\[error.*/, 'constant'],
|
||||
[/\[notice.*/, 'variable'],
|
||||
[/\[info.*/, 'string'],
|
||||
[/\[[a-zA-Z 0-9:]+\]/, 'tag'],
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
monacoEditor.languages.register({ id: 'loglang' });
|
||||
monacoEditor.languages.setMonarchTokensProvider('loglang', simpleLogLang);
|
||||
|
||||
const logs = `
|
||||
[Sun Mar 7 20:54:27 2004] [notice] [client xx.xx.xx.xx] This is a notice!
|
||||
[Sun Mar 7 20:58:27 2004] [info] [client xx.xx.xx.xx] (104)Connection reset by peer: client stopped connection before send body completed
|
||||
[Sun Mar 7 21:16:17 2004] [error] [client xx.xx.xx.xx] File does not exist: /home/httpd/twiki/view/Main/WebHome
|
||||
`;
|
||||
|
||||
const html = `<section>
|
||||
<span>Hello World!</span>
|
||||
</section>`;
|
||||
|
||||
storiesOf('components/Editor', module)
|
||||
.add('default', () => (
|
||||
<div>
|
||||
<Editor languageId="plaintext" height={250} value="Hello!" onChange={action('onChange')} />
|
||||
</div>
|
||||
))
|
||||
.add('html', () => (
|
||||
<div>
|
||||
<Editor languageId="html" height={250} value={html} onChange={action('onChange')} />
|
||||
</div>
|
||||
))
|
||||
.add('custom log language', () => (
|
||||
<div>
|
||||
<Editor languageId="loglang" height={250} value={logs} onChange={action('onChange')} />
|
||||
</div>
|
||||
));
|
|
@ -1,14 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
import React from 'react';
|
||||
import { useUiSetting } from '../../../../../../../src/plugins/kibana_react/public';
|
||||
import { Editor as BaseEditor, Props } from './editor';
|
||||
|
||||
export const Editor: React.FunctionComponent<Props> = props => {
|
||||
const darkMode = useUiSetting<boolean>('theme:darkMode');
|
||||
|
||||
return <BaseEditor {...props} useDarkTheme={darkMode} />;
|
||||
};
|
|
@ -10,7 +10,7 @@ import { EuiFormRow } from '@elastic/eui';
|
|||
import { debounce } from 'lodash';
|
||||
import * as monacoEditor from 'monaco-editor/esm/vs/editor/editor.api';
|
||||
|
||||
import { Editor } from '../editor';
|
||||
import { CodeEditor } from '../../../../../../../src/plugins/kibana_react/public';
|
||||
|
||||
import { CanvasFunction } from '../../../types';
|
||||
import {
|
||||
|
@ -268,7 +268,7 @@ export class ExpressionInput extends React.Component<Props> {
|
|||
error={error}
|
||||
>
|
||||
<div className="canvasExpressionInput__editor">
|
||||
<Editor
|
||||
<CodeEditor
|
||||
languageId={LANGUAGE_ID}
|
||||
value={value}
|
||||
onChange={this.onChange}
|
||||
|
|
|
@ -30,7 +30,6 @@
|
|||
@import '../components/debug/debug';
|
||||
@import '../components/dom_preview/dom_preview';
|
||||
@import '../components/dragbox_annotation/dragbox_annotation';
|
||||
@import '../components/editor/editor';
|
||||
@import '../components/element_card/element_card';
|
||||
@import '../components/element_content/element_content';
|
||||
@import '../components/expression/expression';
|
||||
|
|
|
@ -91,7 +91,6 @@
|
|||
"@types/react": "^16.9.11",
|
||||
"@types/react-dom": "^16.9.4",
|
||||
"@types/react-redux": "^6.0.6",
|
||||
"@types/react-resize-detector": "^4.0.1",
|
||||
"@types/react-router-dom": "^4.3.1",
|
||||
"@types/react-sticky": "^6.0.3",
|
||||
"@types/react-test-renderer": "^16.9.1",
|
||||
|
@ -272,7 +271,6 @@
|
|||
"moment": "^2.24.0",
|
||||
"moment-duration-format": "^2.3.2",
|
||||
"moment-timezone": "^0.5.27",
|
||||
"monaco-editor": "~0.17.0",
|
||||
"ngreact": "^0.5.1",
|
||||
"nock": "10.0.6",
|
||||
"node-fetch": "^2.6.0",
|
||||
|
@ -301,10 +299,8 @@
|
|||
"react-fast-compare": "^2.0.4",
|
||||
"react-markdown": "^3.4.1",
|
||||
"react-moment-proptypes": "^1.7.0",
|
||||
"react-monaco-editor": "~0.27.0",
|
||||
"react-portal": "^3.2.0",
|
||||
"react-redux": "^5.1.2",
|
||||
"react-resize-detector": "^4.2.0",
|
||||
"react-reverse-portal": "^1.0.4",
|
||||
"react-router-dom": "^4.3.1",
|
||||
"react-shortcuts": "^2.0.0",
|
||||
|
|
Loading…
Reference in a new issue