mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 17:59:23 -04:00
Add EuiCodeEditor to ES UI Shared. (#108318)
* Export EuiCodeEditor from es_ui_shared and consume it in Grok Debugger. Remove warning from EuiCodeEditor. * Lazy-load code editor so it doesn't bloat the EsUiShared plugin bundle. * Refactor mocks into a shared jest_mock.tsx file.
This commit is contained in:
parent
5ef1f95711
commit
bfea4a1c2b
23 changed files with 1200 additions and 94 deletions
|
@ -336,7 +336,7 @@
|
|||
"re-resizable": "^6.1.1",
|
||||
"re2": "^1.15.4",
|
||||
"react": "^16.12.0",
|
||||
"react-ace": "^5.9.0",
|
||||
"react-ace": "^7.0.5",
|
||||
"react-beautiful-dnd": "^13.0.0",
|
||||
"react-color": "^2.13.8",
|
||||
"react-dom": "^16.12.0",
|
||||
|
|
627
src/plugins/es_ui_shared/public/components/code_editor/__snapshots__/code_editor.test.tsx.snap
generated
Normal file
627
src/plugins/es_ui_shared/public/components/code_editor/__snapshots__/code_editor.test.tsx.snap
generated
Normal file
|
@ -0,0 +1,627 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`EuiCodeEditor behavior hint element should be disabled when the ui ace box gains focus 1`] = `
|
||||
<button
|
||||
class="euiCodeEditorKeyboardHint"
|
||||
data-test-subj="codeEditorHint"
|
||||
id="generated-id_codeEditor"
|
||||
>
|
||||
<p
|
||||
class="euiText"
|
||||
>
|
||||
Press Enter to start editing.
|
||||
</p>
|
||||
<p
|
||||
class="euiText"
|
||||
>
|
||||
When you're done, press Escape to stop editing.
|
||||
</p>
|
||||
</button>
|
||||
`;
|
||||
|
||||
exports[`EuiCodeEditor behavior hint element should be enabled when the ui ace box loses focus 1`] = `
|
||||
<button
|
||||
class="euiCodeEditorKeyboardHint"
|
||||
data-test-subj="codeEditorHint"
|
||||
id="generated-id_codeEditor"
|
||||
>
|
||||
<p
|
||||
class="euiText"
|
||||
>
|
||||
Press Enter to start editing.
|
||||
</p>
|
||||
<p
|
||||
class="euiText"
|
||||
>
|
||||
When you're done, press Escape to stop editing.
|
||||
</p>
|
||||
</button>
|
||||
`;
|
||||
|
||||
exports[`EuiCodeEditor behavior hint element should be tabable 1`] = `
|
||||
<button
|
||||
class="euiCodeEditorKeyboardHint"
|
||||
data-test-subj="codeEditorHint"
|
||||
id="generated-id_codeEditor"
|
||||
>
|
||||
<p
|
||||
class="euiText"
|
||||
>
|
||||
Press Enter to start editing.
|
||||
</p>
|
||||
<p
|
||||
class="euiText"
|
||||
>
|
||||
When you're done, press Escape to stop editing.
|
||||
</p>
|
||||
</button>
|
||||
`;
|
||||
|
||||
exports[`EuiCodeEditor is rendered 1`] = `
|
||||
<div
|
||||
class="euiCodeEditorWrapper"
|
||||
data-test-subj="test subject string"
|
||||
>
|
||||
<button
|
||||
class="euiCodeEditorKeyboardHint"
|
||||
data-test-subj="codeEditorHint"
|
||||
id="generated-id_codeEditor"
|
||||
>
|
||||
<p
|
||||
class="euiText"
|
||||
>
|
||||
Press Enter to start editing.
|
||||
</p>
|
||||
<p
|
||||
class="euiText"
|
||||
>
|
||||
When you're done, press Escape to stop editing.
|
||||
</p>
|
||||
</button>
|
||||
<div
|
||||
class=" ace_editor ace-tm testClass1 testClass2"
|
||||
id="generated-id"
|
||||
style="width: 500px; height: 500px;"
|
||||
>
|
||||
<textarea
|
||||
aria-label="aria-label"
|
||||
autocapitalize="off"
|
||||
autocorrect="off"
|
||||
class="ace_text-input"
|
||||
spellcheck="false"
|
||||
style="opacity: 0;"
|
||||
tabindex="-1"
|
||||
wrap="off"
|
||||
/>
|
||||
<div
|
||||
aria-hidden="true"
|
||||
class="ace_gutter"
|
||||
>
|
||||
<div
|
||||
class="ace_layer ace_gutter-layer ace_folding-enabled"
|
||||
/>
|
||||
<div
|
||||
class="ace_gutter-active-line"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="ace_scroller"
|
||||
>
|
||||
<div
|
||||
class="ace_content"
|
||||
>
|
||||
<div
|
||||
class="ace_layer ace_print-margin-layer"
|
||||
>
|
||||
<div
|
||||
class="ace_print-margin"
|
||||
style="left: 4px; visibility: visible;"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="ace_layer ace_marker-layer"
|
||||
/>
|
||||
<div
|
||||
class="ace_layer ace_text-layer"
|
||||
style="padding: 0px 4px;"
|
||||
/>
|
||||
<div
|
||||
class="ace_layer ace_marker-layer"
|
||||
/>
|
||||
<div
|
||||
class="ace_layer ace_cursor-layer ace_hidden-cursors"
|
||||
>
|
||||
<div
|
||||
class="ace_cursor"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="ace_scrollbar ace_scrollbar-v"
|
||||
style="display: none; width: 20px;"
|
||||
>
|
||||
<div
|
||||
class="ace_scrollbar-inner"
|
||||
style="width: 20px;"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="ace_scrollbar ace_scrollbar-h"
|
||||
style="display: none; height: 20px;"
|
||||
>
|
||||
<div
|
||||
class="ace_scrollbar-inner"
|
||||
style="height: 20px;"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
style="height: auto; width: auto; top: 0px; left: 0px; visibility: hidden; position: absolute; white-space: pre; overflow: hidden;"
|
||||
>
|
||||
<div
|
||||
style="height: auto; width: auto; top: 0px; left: 0px; visibility: hidden; position: absolute; white-space: pre; overflow: visible;"
|
||||
/>
|
||||
<div
|
||||
style="height: auto; width: auto; top: 0px; left: 0px; visibility: hidden; position: absolute; white-space: pre; overflow: visible;"
|
||||
>
|
||||
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`EuiCodeEditor props aria attributes allows setting aria-describedby on textbox 1`] = `
|
||||
<div
|
||||
class="euiCodeEditorWrapper"
|
||||
data-test-subj="codeEditorContainer"
|
||||
>
|
||||
<button
|
||||
class="euiCodeEditorKeyboardHint"
|
||||
data-test-subj="codeEditorHint"
|
||||
id="generated-id_codeEditor"
|
||||
>
|
||||
<p
|
||||
class="euiText"
|
||||
>
|
||||
Press Enter to start editing.
|
||||
</p>
|
||||
<p
|
||||
class="euiText"
|
||||
>
|
||||
When you're done, press Escape to stop editing.
|
||||
</p>
|
||||
</button>
|
||||
<div
|
||||
class=" ace_editor ace-tm"
|
||||
id="generated-id"
|
||||
style="width: 500px; height: 500px;"
|
||||
>
|
||||
<textarea
|
||||
aria-describedby="describedbyid"
|
||||
autocapitalize="off"
|
||||
autocorrect="off"
|
||||
class="ace_text-input"
|
||||
spellcheck="false"
|
||||
style="opacity: 0;"
|
||||
tabindex="-1"
|
||||
wrap="off"
|
||||
/>
|
||||
<div
|
||||
aria-hidden="true"
|
||||
class="ace_gutter"
|
||||
>
|
||||
<div
|
||||
class="ace_layer ace_gutter-layer ace_folding-enabled"
|
||||
/>
|
||||
<div
|
||||
class="ace_gutter-active-line"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="ace_scroller"
|
||||
>
|
||||
<div
|
||||
class="ace_content"
|
||||
>
|
||||
<div
|
||||
class="ace_layer ace_print-margin-layer"
|
||||
>
|
||||
<div
|
||||
class="ace_print-margin"
|
||||
style="left: 4px; visibility: visible;"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="ace_layer ace_marker-layer"
|
||||
/>
|
||||
<div
|
||||
class="ace_layer ace_text-layer"
|
||||
style="padding: 0px 4px;"
|
||||
/>
|
||||
<div
|
||||
class="ace_layer ace_marker-layer"
|
||||
/>
|
||||
<div
|
||||
class="ace_layer ace_cursor-layer ace_hidden-cursors"
|
||||
>
|
||||
<div
|
||||
class="ace_cursor"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="ace_scrollbar ace_scrollbar-v"
|
||||
style="display: none; width: 20px;"
|
||||
>
|
||||
<div
|
||||
class="ace_scrollbar-inner"
|
||||
style="width: 20px;"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="ace_scrollbar ace_scrollbar-h"
|
||||
style="display: none; height: 20px;"
|
||||
>
|
||||
<div
|
||||
class="ace_scrollbar-inner"
|
||||
style="height: 20px;"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
style="height: auto; width: auto; top: 0px; left: 0px; visibility: hidden; position: absolute; white-space: pre; overflow: hidden;"
|
||||
>
|
||||
<div
|
||||
style="height: auto; width: auto; top: 0px; left: 0px; visibility: hidden; position: absolute; white-space: pre; overflow: visible;"
|
||||
/>
|
||||
<div
|
||||
style="height: auto; width: auto; top: 0px; left: 0px; visibility: hidden; position: absolute; white-space: pre; overflow: visible;"
|
||||
>
|
||||
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`EuiCodeEditor props aria attributes allows setting aria-labelledby on textbox 1`] = `
|
||||
<div
|
||||
class="euiCodeEditorWrapper"
|
||||
data-test-subj="codeEditorContainer"
|
||||
>
|
||||
<button
|
||||
class="euiCodeEditorKeyboardHint"
|
||||
data-test-subj="codeEditorHint"
|
||||
id="generated-id_codeEditor"
|
||||
>
|
||||
<p
|
||||
class="euiText"
|
||||
>
|
||||
Press Enter to start editing.
|
||||
</p>
|
||||
<p
|
||||
class="euiText"
|
||||
>
|
||||
When you're done, press Escape to stop editing.
|
||||
</p>
|
||||
</button>
|
||||
<div
|
||||
class=" ace_editor ace-tm"
|
||||
id="generated-id"
|
||||
style="width: 500px; height: 500px;"
|
||||
>
|
||||
<textarea
|
||||
aria-labelledby="labelledbyid"
|
||||
autocapitalize="off"
|
||||
autocorrect="off"
|
||||
class="ace_text-input"
|
||||
spellcheck="false"
|
||||
style="opacity: 0;"
|
||||
tabindex="-1"
|
||||
wrap="off"
|
||||
/>
|
||||
<div
|
||||
aria-hidden="true"
|
||||
class="ace_gutter"
|
||||
>
|
||||
<div
|
||||
class="ace_layer ace_gutter-layer ace_folding-enabled"
|
||||
/>
|
||||
<div
|
||||
class="ace_gutter-active-line"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="ace_scroller"
|
||||
>
|
||||
<div
|
||||
class="ace_content"
|
||||
>
|
||||
<div
|
||||
class="ace_layer ace_print-margin-layer"
|
||||
>
|
||||
<div
|
||||
class="ace_print-margin"
|
||||
style="left: 4px; visibility: visible;"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="ace_layer ace_marker-layer"
|
||||
/>
|
||||
<div
|
||||
class="ace_layer ace_text-layer"
|
||||
style="padding: 0px 4px;"
|
||||
/>
|
||||
<div
|
||||
class="ace_layer ace_marker-layer"
|
||||
/>
|
||||
<div
|
||||
class="ace_layer ace_cursor-layer ace_hidden-cursors"
|
||||
>
|
||||
<div
|
||||
class="ace_cursor"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="ace_scrollbar ace_scrollbar-v"
|
||||
style="display: none; width: 20px;"
|
||||
>
|
||||
<div
|
||||
class="ace_scrollbar-inner"
|
||||
style="width: 20px;"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="ace_scrollbar ace_scrollbar-h"
|
||||
style="display: none; height: 20px;"
|
||||
>
|
||||
<div
|
||||
class="ace_scrollbar-inner"
|
||||
style="height: 20px;"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
style="height: auto; width: auto; top: 0px; left: 0px; visibility: hidden; position: absolute; white-space: pre; overflow: hidden;"
|
||||
>
|
||||
<div
|
||||
style="height: auto; width: auto; top: 0px; left: 0px; visibility: hidden; position: absolute; white-space: pre; overflow: visible;"
|
||||
/>
|
||||
<div
|
||||
style="height: auto; width: auto; top: 0px; left: 0px; visibility: hidden; position: absolute; white-space: pre; overflow: visible;"
|
||||
>
|
||||
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`EuiCodeEditor props isReadOnly renders alternate hint text 1`] = `
|
||||
<div
|
||||
class="euiCodeEditorWrapper"
|
||||
data-test-subj="codeEditorContainer"
|
||||
>
|
||||
<button
|
||||
class="euiCodeEditorKeyboardHint"
|
||||
data-test-subj="codeEditorHint"
|
||||
id="generated-id_codeEditor"
|
||||
>
|
||||
<p
|
||||
class="euiText"
|
||||
>
|
||||
Press Enter to start interacting with the code.
|
||||
</p>
|
||||
<p
|
||||
class="euiText"
|
||||
>
|
||||
When you're done, press Escape to stop interacting with the code.
|
||||
</p>
|
||||
</button>
|
||||
<div
|
||||
class=" ace_editor ace-tm"
|
||||
id="generated-id"
|
||||
style="width: 500px; height: 500px;"
|
||||
>
|
||||
<textarea
|
||||
autocapitalize="off"
|
||||
autocorrect="off"
|
||||
class="ace_text-input"
|
||||
spellcheck="false"
|
||||
style="opacity: 0;"
|
||||
tabindex="-1"
|
||||
wrap="off"
|
||||
/>
|
||||
<div
|
||||
aria-hidden="true"
|
||||
class="ace_gutter"
|
||||
>
|
||||
<div
|
||||
class="ace_layer ace_gutter-layer ace_folding-enabled"
|
||||
/>
|
||||
<div
|
||||
class="ace_gutter-active-line"
|
||||
style="display: none;"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="ace_scroller"
|
||||
>
|
||||
<div
|
||||
class="ace_content"
|
||||
>
|
||||
<div
|
||||
class="ace_layer ace_print-margin-layer"
|
||||
>
|
||||
<div
|
||||
class="ace_print-margin"
|
||||
style="left: 4px; visibility: visible;"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="ace_layer ace_marker-layer"
|
||||
/>
|
||||
<div
|
||||
class="ace_layer ace_text-layer"
|
||||
style="padding: 0px 4px;"
|
||||
/>
|
||||
<div
|
||||
class="ace_layer ace_marker-layer"
|
||||
/>
|
||||
<div
|
||||
class="ace_layer ace_cursor-layer ace_hidden-cursors"
|
||||
>
|
||||
<div
|
||||
class="ace_cursor"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="ace_scrollbar ace_scrollbar-v"
|
||||
style="display: none; width: 20px;"
|
||||
>
|
||||
<div
|
||||
class="ace_scrollbar-inner"
|
||||
style="width: 20px;"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="ace_scrollbar ace_scrollbar-h"
|
||||
style="display: none; height: 20px;"
|
||||
>
|
||||
<div
|
||||
class="ace_scrollbar-inner"
|
||||
style="height: 20px;"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
style="height: auto; width: auto; top: 0px; left: 0px; visibility: hidden; position: absolute; white-space: pre; overflow: hidden;"
|
||||
>
|
||||
<div
|
||||
style="height: auto; width: auto; top: 0px; left: 0px; visibility: hidden; position: absolute; white-space: pre; overflow: visible;"
|
||||
/>
|
||||
<div
|
||||
style="height: auto; width: auto; top: 0px; left: 0px; visibility: hidden; position: absolute; white-space: pre; overflow: visible;"
|
||||
>
|
||||
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`EuiCodeEditor props theme renders terminal theme 1`] = `
|
||||
<div
|
||||
class="euiCodeEditorWrapper"
|
||||
data-test-subj="codeEditorContainer"
|
||||
>
|
||||
<button
|
||||
class="euiCodeEditorKeyboardHint"
|
||||
data-test-subj="codeEditorHint"
|
||||
id="generated-id_codeEditor"
|
||||
>
|
||||
<p
|
||||
class="euiText"
|
||||
>
|
||||
Press Enter to start editing.
|
||||
</p>
|
||||
<p
|
||||
class="euiText"
|
||||
>
|
||||
When you're done, press Escape to stop editing.
|
||||
</p>
|
||||
</button>
|
||||
<div
|
||||
class=" ace_editor ace-tm"
|
||||
id="generated-id"
|
||||
style="width: 500px; height: 500px;"
|
||||
>
|
||||
<textarea
|
||||
autocapitalize="off"
|
||||
autocorrect="off"
|
||||
class="ace_text-input"
|
||||
spellcheck="false"
|
||||
style="opacity: 0;"
|
||||
tabindex="-1"
|
||||
wrap="off"
|
||||
/>
|
||||
<div
|
||||
aria-hidden="true"
|
||||
class="ace_gutter"
|
||||
>
|
||||
<div
|
||||
class="ace_layer ace_gutter-layer ace_folding-enabled"
|
||||
/>
|
||||
<div
|
||||
class="ace_gutter-active-line"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="ace_scroller"
|
||||
>
|
||||
<div
|
||||
class="ace_content"
|
||||
>
|
||||
<div
|
||||
class="ace_layer ace_print-margin-layer"
|
||||
>
|
||||
<div
|
||||
class="ace_print-margin"
|
||||
style="left: 4px; visibility: visible;"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="ace_layer ace_marker-layer"
|
||||
/>
|
||||
<div
|
||||
class="ace_layer ace_text-layer"
|
||||
style="padding: 0px 4px;"
|
||||
/>
|
||||
<div
|
||||
class="ace_layer ace_marker-layer"
|
||||
/>
|
||||
<div
|
||||
class="ace_layer ace_cursor-layer ace_hidden-cursors"
|
||||
>
|
||||
<div
|
||||
class="ace_cursor"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="ace_scrollbar ace_scrollbar-v"
|
||||
style="display: none; width: 20px;"
|
||||
>
|
||||
<div
|
||||
class="ace_scrollbar-inner"
|
||||
style="width: 20px;"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="ace_scrollbar ace_scrollbar-h"
|
||||
style="display: none; height: 20px;"
|
||||
>
|
||||
<div
|
||||
class="ace_scrollbar-inner"
|
||||
style="height: 20px;"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
style="height: auto; width: auto; top: 0px; left: 0px; visibility: hidden; position: absolute; white-space: pre; overflow: hidden;"
|
||||
>
|
||||
<div
|
||||
style="height: auto; width: auto; top: 0px; left: 0px; visibility: hidden; position: absolute; white-space: pre; overflow: visible;"
|
||||
/>
|
||||
<div
|
||||
style="height: auto; width: auto; top: 0px; left: 0px; visibility: hidden; position: absolute; white-space: pre; overflow: visible;"
|
||||
>
|
||||
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
|
@ -0,0 +1,38 @@
|
|||
.euiCodeEditorWrapper {
|
||||
position: relative;
|
||||
|
||||
.ace_hidden-cursors {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
&.euiCodeEditorWrapper-isEditing {
|
||||
.ace_hidden-cursors {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.euiCodeEditorKeyboardHint {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
background: transparentize($euiColorGhost, .3);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
opacity: 0;
|
||||
cursor: pointer;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
|
||||
&:focus {
|
||||
opacity: 1;
|
||||
border: 2px solid $euiColorPrimary;
|
||||
z-index: $euiZLevel1;
|
||||
}
|
||||
|
||||
&.euiCodeEditorKeyboardHint-isInactive {
|
||||
display: none;
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
@import 'code_editor';
|
|
@ -0,0 +1,117 @@
|
|||
/*
|
||||
* 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 React from 'react';
|
||||
import { mount, ReactWrapper } from 'enzyme';
|
||||
import EuiCodeEditor from './code_editor';
|
||||
// @ts-ignore
|
||||
import { keys } from '@elastic/eui/lib/services';
|
||||
import { findTestSubject, requiredProps, takeMountedSnapshot } from '@elastic/eui/lib/test';
|
||||
|
||||
describe('EuiCodeEditor', () => {
|
||||
test('is rendered', () => {
|
||||
const component = mount(<EuiCodeEditor {...requiredProps} />);
|
||||
expect(takeMountedSnapshot(component)).toMatchSnapshot();
|
||||
});
|
||||
|
||||
describe('props', () => {
|
||||
describe('isReadOnly', () => {
|
||||
test('renders alternate hint text', () => {
|
||||
const component = mount(<EuiCodeEditor isReadOnly />);
|
||||
expect(takeMountedSnapshot(component)).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
describe('theme', () => {
|
||||
test('renders terminal theme', () => {
|
||||
const component = mount(<EuiCodeEditor theme="terminal" />);
|
||||
expect(takeMountedSnapshot(component)).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
describe('aria attributes', () => {
|
||||
test('allows setting aria-labelledby on textbox', () => {
|
||||
const component = mount(<EuiCodeEditor aria-labelledby="labelledbyid" />);
|
||||
expect(takeMountedSnapshot(component)).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('allows setting aria-describedby on textbox', () => {
|
||||
const component = mount(<EuiCodeEditor aria-describedby="describedbyid" />);
|
||||
expect(takeMountedSnapshot(component)).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('behavior', () => {
|
||||
let component: ReactWrapper;
|
||||
|
||||
beforeEach(() => {
|
||||
// Addresses problems with attaching to document.body.
|
||||
// https://meganesulli.com/blog/managing-focus-with-react-and-jest/
|
||||
const container = document.createElement('div');
|
||||
document.body.appendChild(container);
|
||||
|
||||
// We need to manually attach the element to document.body to assert against
|
||||
// document.activeElement in our focus behavior tests, below.
|
||||
component = mount(<EuiCodeEditor />, { attachTo: container });
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
// We need to clean up after ourselves per https://github.com/enzymejs/enzyme/issues/2337.
|
||||
if (component) {
|
||||
component.unmount();
|
||||
}
|
||||
});
|
||||
|
||||
describe('hint element', () => {
|
||||
test('should be tabable', () => {
|
||||
const hint = findTestSubject(component, 'codeEditorHint').getDOMNode();
|
||||
expect(hint).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('should be disabled when the ui ace box gains focus', () => {
|
||||
const hint = findTestSubject(component, 'codeEditorHint');
|
||||
hint.simulate('keyup', { key: keys.ENTER });
|
||||
expect(findTestSubject(component, 'codeEditorHint').getDOMNode()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('should be enabled when the ui ace box loses focus', () => {
|
||||
const hint = findTestSubject(component, 'codeEditorHint');
|
||||
hint.simulate('keyup', { key: keys.ENTER });
|
||||
// @ts-ignore onBlurAce is known to exist and its params are only passed through to the onBlur callback
|
||||
component.instance().onBlurAce();
|
||||
expect(findTestSubject(component, 'codeEditorHint').getDOMNode()).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
describe('interaction', () => {
|
||||
test('bluring the ace textbox should call a passed onBlur prop', () => {
|
||||
const blurSpy = jest.fn().mockName('blurSpy');
|
||||
const el = mount(<EuiCodeEditor onBlur={blurSpy} />);
|
||||
// @ts-ignore onBlurAce is known to exist and its params are only passed through to the onBlur callback
|
||||
el.instance().onBlurAce();
|
||||
expect(blurSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test('pressing escape in ace textbox will enable overlay', () => {
|
||||
// We cannot simulate the `commands` path, but this interaction still
|
||||
// serves as a fallback in cases where `commands` is unavailable.
|
||||
// @ts-ignore onFocusAce is known to exist
|
||||
component.instance().onFocusAce();
|
||||
// @ts-ignore onKeydownAce is known to exist and its params' values are unimportant
|
||||
component.instance().onKeydownAce({
|
||||
preventDefault: () => {},
|
||||
stopPropagation: () => {},
|
||||
key: keys.ESCAPE,
|
||||
});
|
||||
const hint = findTestSubject(component, 'codeEditorHint').getDOMNode();
|
||||
expect(hint).toBe(document.activeElement);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,308 @@
|
|||
/*
|
||||
* 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 React, { Component, AriaAttributes } from 'react';
|
||||
import classNames from 'classnames';
|
||||
import AceEditor, { IAceEditorProps } from 'react-ace';
|
||||
import { EuiI18n } from '@elastic/eui';
|
||||
// @ts-ignore
|
||||
import { htmlIdGenerator, keys } from '@elastic/eui/lib/services';
|
||||
|
||||
import './_index.scss';
|
||||
|
||||
/**
|
||||
* Wraps Object.keys with proper typescript definition of the resulting array
|
||||
*/
|
||||
function keysOf<T, K extends keyof T>(obj: T): K[] {
|
||||
return Object.keys(obj) as K[];
|
||||
}
|
||||
|
||||
const DEFAULT_MODE = 'text';
|
||||
const DEFAULT_THEME = 'textmate';
|
||||
|
||||
function setOrRemoveAttribute(
|
||||
element: HTMLTextAreaElement,
|
||||
attributeName: SupportedAriaAttribute,
|
||||
value: SupportedAriaAttributes[SupportedAriaAttribute]
|
||||
) {
|
||||
if (value === null || value === undefined) {
|
||||
element.removeAttribute(attributeName);
|
||||
} else {
|
||||
element.setAttribute(attributeName, value);
|
||||
}
|
||||
}
|
||||
|
||||
type SupportedAriaAttribute = 'aria-label' | 'aria-labelledby' | 'aria-describedby';
|
||||
type SupportedAriaAttributes = Pick<AriaAttributes, SupportedAriaAttribute>;
|
||||
|
||||
export interface EuiCodeEditorProps extends SupportedAriaAttributes, Omit<IAceEditorProps, 'mode'> {
|
||||
width?: string;
|
||||
height?: string;
|
||||
onBlur?: IAceEditorProps['onBlur'];
|
||||
onFocus?: IAceEditorProps['onFocus'];
|
||||
isReadOnly?: boolean;
|
||||
setOptions: IAceEditorProps['setOptions'];
|
||||
cursorStart?: number;
|
||||
'data-test-subj'?: string;
|
||||
/**
|
||||
* Select the `brace` theme
|
||||
* The matching theme file must also be imported from `brace` (e.g., `import 'brace/theme/github';`)
|
||||
*/
|
||||
theme?: IAceEditorProps['theme'];
|
||||
|
||||
/**
|
||||
* Use string for a built-in mode or object for a custom mode
|
||||
*/
|
||||
mode?: IAceEditorProps['mode'] | object;
|
||||
id?: string;
|
||||
}
|
||||
|
||||
export interface EuiCodeEditorState {
|
||||
isHintActive: boolean;
|
||||
isEditing: boolean;
|
||||
name: string;
|
||||
}
|
||||
|
||||
class EuiCodeEditor extends Component<EuiCodeEditorProps, EuiCodeEditorState> {
|
||||
static defaultProps = {
|
||||
setOptions: {},
|
||||
};
|
||||
|
||||
state: EuiCodeEditorState = {
|
||||
isHintActive: true,
|
||||
isEditing: false,
|
||||
name: htmlIdGenerator()(),
|
||||
};
|
||||
|
||||
constructor(props: EuiCodeEditorProps) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
idGenerator = htmlIdGenerator();
|
||||
aceEditor: AceEditor | null = null;
|
||||
editorHint: HTMLButtonElement | null = null;
|
||||
|
||||
aceEditorRef = (aceEditor: AceEditor | null) => {
|
||||
if (aceEditor) {
|
||||
this.aceEditor = aceEditor;
|
||||
const textbox = aceEditor.editor.textInput.getElement() as HTMLTextAreaElement;
|
||||
textbox.tabIndex = -1;
|
||||
textbox.addEventListener('keydown', this.onKeydownAce);
|
||||
setOrRemoveAttribute(textbox, 'aria-label', this.props['aria-label']);
|
||||
setOrRemoveAttribute(textbox, 'aria-labelledby', this.props['aria-labelledby']);
|
||||
setOrRemoveAttribute(textbox, 'aria-describedby', this.props['aria-describedby']);
|
||||
}
|
||||
};
|
||||
|
||||
onEscToExit = () => {
|
||||
this.stopEditing();
|
||||
if (this.editorHint) {
|
||||
this.editorHint.focus();
|
||||
}
|
||||
};
|
||||
|
||||
onKeydownAce = (event: KeyboardEvent) => {
|
||||
if (event.key === keys.ESCAPE) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
// Handles exiting edit mode when `isReadOnly` is set.
|
||||
// Other 'esc' cases handled by `stopEditingOnEsc` command.
|
||||
// Would run after `stopEditingOnEsc`.
|
||||
if (this.aceEditor !== null && !this.aceEditor.editor.completer && this.state.isEditing) {
|
||||
this.onEscToExit();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
onFocusAce: IAceEditorProps['onFocus'] = (event, editor) => {
|
||||
this.setState({
|
||||
isEditing: true,
|
||||
});
|
||||
if (this.props.onFocus) {
|
||||
this.props.onFocus(event, editor);
|
||||
}
|
||||
};
|
||||
|
||||
onBlurAce: IAceEditorProps['onBlur'] = (event, editor) => {
|
||||
this.stopEditing();
|
||||
if (this.props.onBlur) {
|
||||
this.props.onBlur(event, editor);
|
||||
}
|
||||
};
|
||||
|
||||
startEditing = () => {
|
||||
this.setState({
|
||||
isHintActive: false,
|
||||
});
|
||||
if (this.aceEditor !== null) {
|
||||
this.aceEditor.editor.textInput.focus();
|
||||
}
|
||||
};
|
||||
|
||||
stopEditing() {
|
||||
this.setState({
|
||||
isHintActive: true,
|
||||
isEditing: false,
|
||||
});
|
||||
}
|
||||
|
||||
isCustomMode() {
|
||||
return typeof this.props.mode === 'object';
|
||||
}
|
||||
|
||||
setCustomMode() {
|
||||
if (this.aceEditor !== null) {
|
||||
this.aceEditor.editor.getSession().setMode(this.props.mode);
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
if (this.isCustomMode()) {
|
||||
this.setCustomMode();
|
||||
}
|
||||
const { isReadOnly, id } = this.props;
|
||||
|
||||
const textareaProps: {
|
||||
id?: string;
|
||||
readOnly?: boolean;
|
||||
} = { id, readOnly: isReadOnly };
|
||||
|
||||
const el = document.getElementById(this.state.name);
|
||||
if (el) {
|
||||
const textarea = el.querySelector('textarea');
|
||||
if (textarea)
|
||||
keysOf(textareaProps).forEach((key) => {
|
||||
if (textareaProps[key]) textarea.setAttribute(`${key}`, textareaProps[key]!.toString());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps: EuiCodeEditorProps) {
|
||||
if (this.props.mode !== prevProps.mode && this.isCustomMode()) {
|
||||
this.setCustomMode();
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
width,
|
||||
height,
|
||||
onBlur,
|
||||
isReadOnly,
|
||||
setOptions,
|
||||
cursorStart,
|
||||
mode = DEFAULT_MODE,
|
||||
'data-test-subj': dataTestSubj = 'codeEditorContainer',
|
||||
theme = DEFAULT_THEME,
|
||||
commands = [],
|
||||
...rest
|
||||
} = this.props;
|
||||
|
||||
const classes = classNames('euiCodeEditorWrapper', {
|
||||
'euiCodeEditorWrapper-isEditing': this.state.isEditing,
|
||||
});
|
||||
|
||||
const promptClasses = classNames('euiCodeEditorKeyboardHint', {
|
||||
'euiCodeEditorKeyboardHint-isInactive': !this.state.isHintActive,
|
||||
});
|
||||
|
||||
let filteredCursorStart;
|
||||
|
||||
const options: IAceEditorProps['setOptions'] = { ...setOptions };
|
||||
|
||||
if (isReadOnly) {
|
||||
// Put the cursor at the beginning of the editor, so that it doesn't look like
|
||||
// a prompt to begin typing.
|
||||
filteredCursorStart = -1;
|
||||
|
||||
Object.assign(options, {
|
||||
readOnly: true,
|
||||
highlightActiveLine: false,
|
||||
highlightGutterLine: false,
|
||||
});
|
||||
} else {
|
||||
filteredCursorStart = cursorStart;
|
||||
}
|
||||
|
||||
const prompt = (
|
||||
<button
|
||||
className={promptClasses}
|
||||
id={this.idGenerator('codeEditor')}
|
||||
ref={(hint) => {
|
||||
this.editorHint = hint;
|
||||
}}
|
||||
onClick={this.startEditing}
|
||||
data-test-subj="codeEditorHint"
|
||||
>
|
||||
<p className="euiText">
|
||||
{isReadOnly ? (
|
||||
<EuiI18n
|
||||
token="euiCodeEditor.startInteracting"
|
||||
default="Press Enter to start interacting with the code."
|
||||
/>
|
||||
) : (
|
||||
<EuiI18n token="euiCodeEditor.startEditing" default="Press Enter to start editing." />
|
||||
)}
|
||||
</p>
|
||||
|
||||
<p className="euiText">
|
||||
{isReadOnly ? (
|
||||
<EuiI18n
|
||||
token="euiCodeEditor.stopInteracting"
|
||||
default="When you're done, press Escape to stop interacting with the code."
|
||||
/>
|
||||
) : (
|
||||
<EuiI18n
|
||||
token="euiCodeEditor.stopEditing"
|
||||
default="When you're done, press Escape to stop editing."
|
||||
/>
|
||||
)}
|
||||
</p>
|
||||
</button>
|
||||
);
|
||||
|
||||
return (
|
||||
<div className={classes} style={{ width, height }} data-test-subj={dataTestSubj}>
|
||||
{prompt}
|
||||
|
||||
<AceEditor
|
||||
// Setting a default, existing `mode` is necessary to properly initialize the editor
|
||||
// prior to dynamically setting a custom mode (https://github.com/elastic/eui/pull/2616)
|
||||
mode={this.isCustomMode() ? DEFAULT_MODE : (mode as string)} // https://github.com/securingsincity/react-ace/pull/771
|
||||
name={this.state.name}
|
||||
theme={theme}
|
||||
ref={this.aceEditorRef}
|
||||
width={width}
|
||||
height={height}
|
||||
onFocus={this.onFocusAce}
|
||||
onBlur={this.onBlurAce}
|
||||
setOptions={options}
|
||||
editorProps={{
|
||||
$blockScrolling: Infinity,
|
||||
}}
|
||||
cursorStart={filteredCursorStart}
|
||||
commands={[
|
||||
// Handles exiting edit mode in all cases except `isReadOnly`
|
||||
// Runs before `onKeydownAce`.
|
||||
{
|
||||
name: 'stopEditingOnEsc',
|
||||
bindKey: { win: 'Esc', mac: 'Esc' },
|
||||
exec: this.onEscToExit,
|
||||
},
|
||||
...commands,
|
||||
]}
|
||||
{...rest}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Needed for React.lazy
|
||||
// eslint-disable-next-line import/no-default-export
|
||||
export default EuiCodeEditor;
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* 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 React from 'react';
|
||||
import { EuiLoadingContentProps, EuiLoadingContent } from '@elastic/eui';
|
||||
import type { EuiCodeEditorProps } from './code_editor';
|
||||
|
||||
const Placeholder = ({ height }: { height?: string }) => {
|
||||
const numericalHeight = height ? parseInt(height, 10) : 0;
|
||||
// The height of one EuiLoadingContent line is 24px.
|
||||
const lineHeight = 24;
|
||||
const calculatedLineCount =
|
||||
numericalHeight < lineHeight ? 1 : Math.floor(numericalHeight / lineHeight);
|
||||
const lines = Math.min(10, calculatedLineCount);
|
||||
|
||||
return <EuiLoadingContent lines={lines as EuiLoadingContentProps['lines']} />;
|
||||
};
|
||||
|
||||
const LazyEuiCodeEditor = React.lazy(() => import('./code_editor'));
|
||||
|
||||
export const EuiCodeEditor = (props: EuiCodeEditorProps) => (
|
||||
<React.Suspense fallback={<Placeholder height={props.height} />}>
|
||||
<LazyEuiCodeEditor {...props} />
|
||||
</React.Suspense>
|
||||
);
|
||||
|
||||
export type { EuiCodeEditorProps } from './code_editor';
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* 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 React from 'react';
|
||||
|
||||
// NOTE: Import this file for its side-effects. You must import it before the code that it mocks
|
||||
// is imported. Typically this means just importing above your other imports.
|
||||
// See https://jestjs.io/docs/manual-mocks for more info.
|
||||
|
||||
// This mocks any direct imports of EuiCodeEditor, e.g. by JsonEditor.
|
||||
jest.mock('.', () => {
|
||||
const original = jest.requireActual('.');
|
||||
|
||||
return {
|
||||
...original,
|
||||
// Mock EuiCodeEditor, which uses React Ace under the hood.
|
||||
EuiCodeEditor: (props: any) => (
|
||||
<input
|
||||
data-test-subj={props['data-test-subj'] || 'mockCodeEditor'}
|
||||
data-currentvalue={props.value}
|
||||
onChange={(syntheticEvent: any) => {
|
||||
props.onChange(syntheticEvent.jsonString);
|
||||
}}
|
||||
/>
|
||||
),
|
||||
};
|
||||
});
|
|
@ -7,9 +7,10 @@
|
|||
*/
|
||||
|
||||
import React, { useCallback, useMemo } from 'react';
|
||||
import { EuiFormRow, EuiCodeEditor } from '@elastic/eui';
|
||||
import { EuiFormRow } from '@elastic/eui';
|
||||
import { debounce } from 'lodash';
|
||||
|
||||
import { EuiCodeEditor } from '../code_editor';
|
||||
import { useJson, OnJsonEditorUpdateHandler } from './use_json';
|
||||
|
||||
interface Props<T extends object = { [key: string]: any }> {
|
||||
|
|
|
@ -20,6 +20,7 @@ export { JsonEditor, OnJsonEditorUpdateHandler, JsonEditorState } from './compon
|
|||
export { PageLoading } from './components/page_loading';
|
||||
export { SectionLoading } from './components/section_loading';
|
||||
|
||||
export { EuiCodeEditor, EuiCodeEditorProps } from './components/code_editor';
|
||||
export { Frequency, CronEditor } from './components/cron_editor';
|
||||
|
||||
export {
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
"ui": true,
|
||||
"configPath": ["xpack", "grokdebugger"],
|
||||
"requiredBundles": [
|
||||
"kibanaReact"
|
||||
"kibanaReact",
|
||||
"esUiShared"
|
||||
]
|
||||
}
|
||||
|
|
|
@ -6,17 +6,12 @@
|
|||
*/
|
||||
|
||||
import React from 'react';
|
||||
import {
|
||||
EuiAccordion,
|
||||
EuiCallOut,
|
||||
EuiCodeBlock,
|
||||
EuiFormRow,
|
||||
EuiCodeEditor,
|
||||
EuiSpacer,
|
||||
} from '@elastic/eui';
|
||||
import { EDITOR } from '../../../common/constants';
|
||||
import { EuiAccordion, EuiCallOut, EuiCodeBlock, EuiFormRow, EuiSpacer } from '@elastic/eui';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
|
||||
import { EDITOR } from '../../../common/constants';
|
||||
import { EuiCodeEditor } from '../../shared_imports';
|
||||
|
||||
export function CustomPatternsInput({ value, onChange }) {
|
||||
const sampleCustomPatterns = `POSTFIX_QUEUEID [0-9A-F]{10,11}
|
||||
MSG message-id=<%{GREEDYDATA}>`;
|
||||
|
|
|
@ -6,10 +6,12 @@
|
|||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { EuiFormRow, EuiCodeEditor } from '@elastic/eui';
|
||||
import { EDITOR } from '../../../common/constants';
|
||||
import { EuiFormRow } from '@elastic/eui';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
|
||||
import { EDITOR } from '../../../common/constants';
|
||||
import { EuiCodeEditor } from '../../shared_imports';
|
||||
|
||||
export function EventInput({ value, onChange }) {
|
||||
return (
|
||||
<EuiFormRow
|
||||
|
|
|
@ -6,9 +6,11 @@
|
|||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { EuiFormRow, EuiCodeEditor } from '@elastic/eui';
|
||||
import { EuiFormRow } from '@elastic/eui';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
|
||||
import { EuiCodeEditor } from '../../shared_imports';
|
||||
|
||||
export function EventOutput({ value }) {
|
||||
return (
|
||||
<EuiFormRow
|
||||
|
|
|
@ -6,11 +6,13 @@
|
|||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { EuiFormRow, EuiCodeEditor } from '@elastic/eui';
|
||||
import { EDITOR } from '../../../common/constants';
|
||||
import { GrokMode } from '../../lib/ace';
|
||||
import { EuiFormRow } from '@elastic/eui';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
|
||||
import { EDITOR } from '../../../common/constants';
|
||||
import { EuiCodeEditor } from '../../shared_imports';
|
||||
import { GrokMode } from '../../lib/ace';
|
||||
|
||||
export function PatternInput({ value, onChange }) {
|
||||
return (
|
||||
<EuiFormRow
|
||||
|
|
8
x-pack/plugins/grokdebugger/public/shared_imports.ts
Normal file
8
x-pack/plugins/grokdebugger/public/shared_imports.ts
Normal file
|
@ -0,0 +1,8 @@
|
|||
/*
|
||||
* 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; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
export { EuiCodeEditor } from '../../../../src/plugins/es_ui_shared/public';
|
|
@ -8,6 +8,7 @@
|
|||
import React from 'react';
|
||||
import { act } from 'react-dom/test-utils';
|
||||
|
||||
import '../../../../../../../../../src/plugins/es_ui_shared/public/components/code_editor/jest_mock';
|
||||
import { setupEnvironment } from './helpers';
|
||||
import { setup, ComponentTemplateCreateTestBed } from './helpers/component_template_create.helpers';
|
||||
|
||||
|
@ -74,7 +75,7 @@ describe('<ComponentTemplateCreate />', () => {
|
|||
|
||||
// Meta editor should be hidden by default
|
||||
// Since the editor itself is mocked, we checked for the mocked element
|
||||
expect(exists('mockCodeEditor')).toBe(false);
|
||||
expect(exists('metaEditor')).toBe(false);
|
||||
|
||||
await act(async () => {
|
||||
actions.toggleMetaSwitch();
|
||||
|
@ -82,7 +83,7 @@ describe('<ComponentTemplateCreate />', () => {
|
|||
|
||||
component.update();
|
||||
|
||||
expect(exists('mockCodeEditor')).toBe(true);
|
||||
expect(exists('metaEditor')).toBe(true);
|
||||
});
|
||||
|
||||
describe('Validation', () => {
|
||||
|
|
|
@ -276,7 +276,7 @@ const createActions = (testBed: TestBed<TestSubjects>) => {
|
|||
};
|
||||
|
||||
const updateJsonEditor = (testSubject: TestSubjects, value: object) => {
|
||||
find(testSubject).simulate('change', { jsonContent: JSON.stringify(value) });
|
||||
find(testSubject).simulate('change', { jsonString: JSON.stringify(value) });
|
||||
};
|
||||
|
||||
const getJsonEditorValue = (testSubject: TestSubjects) => {
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
*/
|
||||
|
||||
import React from 'react';
|
||||
/* eslint-disable-next-line @kbn/eslint/no-restricted-paths */
|
||||
import '../../../../../../../../../../src/plugins/es_ui_shared/public/components/code_editor/jest_mock';
|
||||
import { GlobalFlyout } from '../../../../../../../../../../src/plugins/es_ui_shared/public';
|
||||
import {
|
||||
docLinksServiceMock,
|
||||
|
@ -30,16 +32,6 @@ jest.mock('@elastic/eui', () => {
|
|||
}}
|
||||
/>
|
||||
),
|
||||
// Mocking EuiCodeEditor, which uses React Ace under the hood
|
||||
EuiCodeEditor: (props: any) => (
|
||||
<input
|
||||
data-test-subj={props['data-test-subj'] || 'mockCodeEditor'}
|
||||
data-currentvalue={props.value}
|
||||
onChange={(e: any) => {
|
||||
props.onChange(e.jsonContent);
|
||||
}}
|
||||
/>
|
||||
),
|
||||
// Mocking EuiSuperSelect to be able to easily change its value
|
||||
// with a `myWrapper.simulate('change', { target: { value: 'someValue' } })`
|
||||
EuiSuperSelect: (props: any) => (
|
||||
|
|
|
@ -7,23 +7,7 @@
|
|||
|
||||
import React from 'react';
|
||||
import { act } from 'react-dom/test-utils';
|
||||
|
||||
jest.mock('@elastic/eui', () => {
|
||||
const original = jest.requireActual('@elastic/eui');
|
||||
|
||||
return {
|
||||
...original,
|
||||
// Mocking EuiCodeEditor, which uses React Ace under the hood
|
||||
EuiCodeEditor: (props: any) => (
|
||||
<input
|
||||
data-test-subj="mockCodeEditor"
|
||||
onChange={(syntheticEvent: any) => {
|
||||
props.onChange(syntheticEvent.jsonString);
|
||||
}}
|
||||
/>
|
||||
),
|
||||
};
|
||||
});
|
||||
import '../../../../../../../../../src/plugins/es_ui_shared/public/components/code_editor/jest_mock';
|
||||
|
||||
jest.mock('lodash', () => {
|
||||
const original = jest.requireActual('lodash');
|
||||
|
|
|
@ -10,11 +10,14 @@ import React from 'react';
|
|||
import axios from 'axios';
|
||||
import axiosXhrAdapter from 'axios/lib/adapters/xhr';
|
||||
|
||||
/* eslint-disable @kbn/eslint/no-restricted-paths */
|
||||
/* eslint-disable-next-line @kbn/eslint/no-restricted-paths */
|
||||
import { usageCollectionPluginMock } from 'src/plugins/usage_collection/public/mocks';
|
||||
|
||||
import { registerTestBed, TestBed } from '@kbn/test/jest';
|
||||
import { stubWebWorker } from '@kbn/test/jest';
|
||||
|
||||
/* eslint-disable-next-line @kbn/eslint/no-restricted-paths */
|
||||
import '../../../../../../../../src/plugins/es_ui_shared/public/components/code_editor/jest_mock';
|
||||
import { uiMetricService, apiService } from '../../../services';
|
||||
import { Props } from '../';
|
||||
import { initHttpRequests } from './http_requests.helpers';
|
||||
|
@ -24,6 +27,7 @@ stubWebWorker();
|
|||
|
||||
jest.mock('../../../../../../../../src/plugins/kibana_react/public', () => {
|
||||
const original = jest.requireActual('../../../../../../../../src/plugins/kibana_react/public');
|
||||
|
||||
return {
|
||||
...original,
|
||||
// Mocking CodeEditor, which uses React Monaco under the hood
|
||||
|
@ -39,22 +43,6 @@ jest.mock('../../../../../../../../src/plugins/kibana_react/public', () => {
|
|||
};
|
||||
});
|
||||
|
||||
jest.mock('@elastic/eui', () => {
|
||||
const original = jest.requireActual('@elastic/eui');
|
||||
return {
|
||||
...original,
|
||||
// Mocking EuiCodeEditor, which uses React Ace under the hood
|
||||
EuiCodeEditor: (props: any) => (
|
||||
<input
|
||||
data-test-subj={props['data-test-subj']}
|
||||
onChange={(syntheticEvent: any) => {
|
||||
props.onChange(syntheticEvent.jsonString);
|
||||
}}
|
||||
/>
|
||||
),
|
||||
};
|
||||
});
|
||||
|
||||
jest.mock('react-virtualized', () => {
|
||||
const original = jest.requireActual('react-virtualized');
|
||||
|
||||
|
|
|
@ -6,25 +6,9 @@
|
|||
*/
|
||||
|
||||
import React from 'react';
|
||||
import '../../../../../../../../../src/plugins/es_ui_shared/public/components/code_editor/jest_mock';
|
||||
import { ModalProvider, OnDoneLoadJsonHandler } from './modal_provider';
|
||||
|
||||
jest.mock('@elastic/eui', () => {
|
||||
const original = jest.requireActual('@elastic/eui');
|
||||
|
||||
return {
|
||||
...original,
|
||||
// Mocking EuiCodeEditor, which uses React Ace under the hood
|
||||
EuiCodeEditor: (props: any) => (
|
||||
<input
|
||||
data-test-subj="mockCodeEditor"
|
||||
onChange={(syntheticEvent: any) => {
|
||||
props.onChange(syntheticEvent.jsonString);
|
||||
}}
|
||||
/>
|
||||
),
|
||||
};
|
||||
});
|
||||
|
||||
jest.mock('lodash', () => {
|
||||
const original = jest.requireActual('lodash');
|
||||
|
||||
|
|
14
yarn.lock
14
yarn.lock
|
@ -8500,7 +8500,7 @@ brace-expansion@^1.1.7:
|
|||
balanced-match "^1.0.0"
|
||||
concat-map "0.0.1"
|
||||
|
||||
brace@0.11.1, brace@^0.11.0, brace@^0.11.1:
|
||||
brace@0.11.1, brace@^0.11.1:
|
||||
version "0.11.1"
|
||||
resolved "https://registry.yarnpkg.com/brace/-/brace-0.11.1.tgz#4896fcc9d544eef45f4bb7660db320d3b379fe58"
|
||||
integrity sha1-SJb8ydVE7vRfS7dmDbMg07N5/lg=
|
||||
|
@ -18684,7 +18684,7 @@ lodash.isempty@^4.4.0:
|
|||
resolved "https://registry.yarnpkg.com/lodash.isempty/-/lodash.isempty-4.4.0.tgz#6f86cbedd8be4ec987be9aaf33c9684db1b31e7e"
|
||||
integrity sha1-b4bL7di+TsmHvpqvM8loTbGzHn4=
|
||||
|
||||
lodash.isequal@^4.0.0, lodash.isequal@^4.1.1, lodash.isequal@^4.5.0:
|
||||
lodash.isequal@^4.0.0, lodash.isequal@^4.5.0:
|
||||
version "4.5.0"
|
||||
resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0"
|
||||
integrity sha1-QVxEePK8wwEgwizhDtMib30+GOA=
|
||||
|
@ -22865,16 +22865,6 @@ re2@^1.15.4:
|
|||
nan "^2.14.1"
|
||||
node-gyp "^7.0.0"
|
||||
|
||||
react-ace@^5.9.0:
|
||||
version "5.9.0"
|
||||
resolved "https://registry.yarnpkg.com/react-ace/-/react-ace-5.9.0.tgz#427a1cc4869b960a6f9748aa7eb169a9269fc336"
|
||||
integrity sha512-r6Tuce6seG05g9kT2Tio6DWohy06knG7e5u9OfhvMquZL+Cyu4eqPf60K1Vi2RXlS3+FWrdG8Rinwu4+oQjjgw==
|
||||
dependencies:
|
||||
brace "^0.11.0"
|
||||
lodash.get "^4.4.2"
|
||||
lodash.isequal "^4.1.1"
|
||||
prop-types "^15.5.8"
|
||||
|
||||
react-ace@^7.0.5:
|
||||
version "7.0.5"
|
||||
resolved "https://registry.yarnpkg.com/react-ace/-/react-ace-7.0.5.tgz#798299fd52ddf3a3dcc92afc5865538463544f01"
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue