Update Kibana code editor dependencies (#171720)

## Summary

This PR started out as an attempt to resolve
https://github.com/elastic/kibana/issues/166559; which it does, the
appropriate colours for the message prompt displayed when an edit
attempt on read only content is made in the code editor for both dark
and light mode are now set;

 ### Light mode
<img width="412" alt="Screenshot 2023-11-22 at 11 30 17"
src="8675dd9f-b413-4098-a903-7ac63dc367fb">

### Dark mode
<img width="843" alt="Screenshot 2023-11-22 at 11 29 31"
src="64fd39e0-d5dd-4556-b6ca-75ba8fc55c94">

#### Noteworthy**

- See https://code.visualstudio.com/api/references/theme-color for more
clarification on the style definitions added to this PR
- There's also been accommodation made for consumers of the code editor
to provide their own custom message through the prop `readOnlyMessage`.
- That been said it's worth pointing out that this PR updates
react-monaco-editor and monaco-editor packages to their latest version,
primarily because the functionality that provides support to provide
customization for the providing a color scheme that would support in our
use case for setting colors for dark mode and light mode appropriately,
shipped in version 0.40.0 of monaco editor, also for react-monaco-editor
prior to it's current latest the pinned version of monaco editor was
0.38.0.
- Monaco-yaml is also updated in the PR, matching the change in
expectation of the underlying monaco-editor api.
~- Updates to the packages referenced above, in turn caused the
installed version of prettier to be updated to the latest minor version
2.8.8. This change caused some lint changes to the project files where
parentheses were added to types with Index Access on another type
created using the typeof operator (more context
[here](https://github.com/prettier/prettier/issues/14990)), for this
reason I've opted to lockdown prettier version, so that this PR only
contains the changes required for updating the code editor. A subsequent
PR will be created to revert the package lockdown so that PR contains
only the lint changes that will occur.~

### Checklist
<!--
Delete any items that are not applicable to this PR. -->

- [x] Any text added follows [EUI's writing
guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses
sentence case text and includes [i18n
support](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md)
<!-- - [ ]
[Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html)
was added for features that require explanation or tutorials
- [ ] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios -->
- [x] Any UI touched in this PR is usable by keyboard only (learn more
about [keyboard accessibility](https://webaim.org/techniques/keyboard/))
<!-- - [ ] Any UI touched in this PR does not create any new axe
failures (run axe in browser:
[FF](https://addons.mozilla.org/en-US/firefox/addon/axe-devtools/),
[Chrome](https://chrome.google.com/webstore/detail/axe-web-accessibility-tes/lhdoppojpmngadmnindnejefpokejbdd?hl=en-US))
- [ ] If a plugin configuration key changed, check if it needs to be
allowlisted in the cloud and added to the [docker
list](https://github.com/elastic/kibana/blob/main/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker)
- [ ] This renders correctly on smaller devices using a responsive
layout. (You can test this [in your
browser](https://www.browserstack.com/guide/responsive-testing-on-local-server))
- [ ] This was checked for [cross-browser
compatibility](https://www.elastic.co/support/matrix#matrix_browsers)


### Risk Matrix

Delete this section if it is not applicable to this PR.

Before closing this PR, invite QA, stakeholders, and other developers to
identify risks that should be tested prior to the change/feature
release.

When forming the risk matrix, consider some of the following examples
and how they may potentially impact the change:

| Risk | Probability | Severity | Mitigation/Notes |

|---------------------------|-------------|----------|-------------------------|
| Multiple Spaces&mdash;unexpected behavior in non-default Kibana Space.
| Low | High | Integration tests will verify that all features are still
supported in non-default Kibana Space and when user switches between
spaces. |
| Multiple nodes&mdash;Elasticsearch polling might have race conditions
when multiple Kibana nodes are polling for the same tasks. | High | Low
| Tasks are idempotent, so executing them multiple times will not result
in logical error, but will degrade performance. To test for this case we
add plenty of unit tests around this logic and document manual testing
procedure. |
| Code should gracefully handle cases when feature X or plugin Y are
disabled. | Medium | High | Unit tests will verify that any feature flag
or plugin combination still results in our service operational. |
| [See more potential risk
examples](https://github.com/elastic/kibana/blob/main/RISK_MATRIX.mdx) |


### For maintainers

- [ ] This was checked for breaking API changes and was [labeled
appropriately](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)
-->

---------

Co-authored-by: Aleh Zasypkin <aleh.zasypkin@elastic.co>
Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
Eyo O. Eyo 2024-01-25 10:30:02 +01:00 committed by GitHub
parent c5d4ffd8b7
commit b25407edba
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
43 changed files with 426 additions and 178 deletions

View file

@ -34,6 +34,7 @@ export class ExampleCurrencyFormat extends FieldFormat {
return new Intl.NumberFormat(undefined, {
style: 'currency',
currency: this.param('currency'),
currencyDisplay: 'narrowSymbol',
}).format(val);
};
}

View file

@ -1012,8 +1012,8 @@
"moment": "^2.29.4",
"moment-duration-format": "^2.3.2",
"moment-timezone": "^0.5.43",
"monaco-editor": "^0.24.0",
"monaco-yaml": "3.2.1",
"monaco-editor": "^0.44.0",
"monaco-yaml": "^5.1.0",
"mustache": "^2.3.2",
"node-fetch": "^2.6.7",
"node-forge": "^1.3.1",
@ -1057,7 +1057,7 @@
"react-is": "^17.0.2",
"react-markdown": "^6.0.3",
"react-moment-proptypes": "^1.7.0",
"react-monaco-editor": "^0.41.2",
"react-monaco-editor": "^0.54.0",
"react-popper-tooltip": "^3.1.1",
"react-redux": "^7.2.8",
"react-resizable": "^3.0.4",
@ -1139,12 +1139,13 @@
"@babel/generator": "^7.23.6",
"@babel/helper-plugin-utils": "^7.22.5",
"@babel/parser": "^7.23.6",
"@babel/plugin-proposal-class-properties": "^7.18.6",
"@babel/plugin-proposal-export-namespace-from": "^7.18.9",
"@babel/plugin-proposal-nullish-coalescing-operator": "^7.18.6",
"@babel/plugin-proposal-object-rest-spread": "^7.20.7",
"@babel/plugin-proposal-optional-chaining": "^7.21.0",
"@babel/plugin-proposal-private-methods": "^7.18.6",
"@babel/plugin-transform-class-properties": "^7.23.3",
"@babel/plugin-transform-numeric-separator": "^7.23.4",
"@babel/plugin-transform-runtime": "^7.23.6",
"@babel/preset-env": "^7.23.6",
"@babel/preset-react": "^7.23.3",

View file

@ -25,7 +25,7 @@ NPM_MODULE_EXTRA_FILES = [
]
RUNTIME_DEPS = [
"@npm//@babel/plugin-proposal-class-properties",
"@npm//@babel/plugin-transform-class-properties",
"@npm//@babel/plugin-proposal-export-namespace-from",
"@npm//@babel/plugin-proposal-nullish-coalescing-operator",
"@npm//@babel/plugin-proposal-optional-chaining",

View file

@ -21,7 +21,7 @@ module.exports = () => ({
// TECHNICALLY stage 2, but for all intents and purposes it's stage 3
//
// See https://github.com/babel/proposals/issues/12 for progress
require.resolve('@babel/plugin-proposal-class-properties'),
require.resolve('@babel/plugin-transform-class-properties'),
// Optional Chaining proposal is stage 4 (https://github.com/tc39/proposal-optional-chaining)
// Need this since we are using TypeScript 3.7+

View file

@ -36,6 +36,7 @@ webpack_cli(
data = SRCS + SHARED_DEPS + [
"//:.browserslistrc",
"//packages/kbn-babel-preset",
"@npm//terser-webpack-plugin",
"@npm//@babel/runtime",
"@npm//babel-loader",
"@npm//raw-loader",

View file

@ -25,6 +25,7 @@ export type { ESQLCallbacks } from './src/esql';
export * from './src/painless';
/* eslint-disable-next-line @kbn/eslint/module_migration */
import * as BarePluginApi from 'monaco-editor/esm/vs/editor/editor.api';
export { YAML_LANG_ID, configureMonacoYamlSchema } from './src/yaml';
import { registerLanguage } from './src/helpers';

View file

@ -13,7 +13,7 @@ const createMockModel = (ID: string) => {
uri: '',
id: 'mockModel',
value: '',
getModeId: () => ID,
getLanguageId: () => ID,
changeContentListeners: [],
setValue(newValue) {
this.value = newValue;

View file

@ -11,7 +11,7 @@ export interface MockIModel {
id: string;
value: string;
changeContentListeners: Array<() => void>;
getModeId: () => string;
getLanguageId: () => string;
setValue: (value: string) => void;
getValue: () => string;
onDidChangeContent: (handler: () => void) => void;

View file

@ -36,10 +36,10 @@ export class DiagnosticsAdapter {
const onModelAdd = (model: monaco.editor.IModel): void => {
let handle: any;
if (model.getModeId() === this.langId) {
if (model.getLanguageId() === this.langId) {
model.onDidChangeContent(() => {
// Do not validate if the language ID has changed
if (model.getModeId() !== this.langId) {
if (model.getLanguageId() !== this.langId) {
return;
}

View file

@ -10,18 +10,18 @@
import * as monaco from 'monaco-editor/esm/vs/editor/editor.api';
import 'monaco-editor/esm/vs/base/common/worker/simpleWorker';
import 'monaco-editor/esm/vs/base/worker/defaultWorkerFactory';
import 'monaco-editor/esm/vs/base/browser/defaultWorkerFactory';
import 'monaco-editor/esm/vs/editor/browser/controller/coreCommands.js';
import 'monaco-editor/esm/vs/editor/browser/coreCommands.js';
import 'monaco-editor/esm/vs/editor/browser/widget/codeEditorWidget.js';
import 'monaco-editor/esm/vs/editor/contrib/wordOperations/wordOperations.js'; // Needed for word-wise char navigation
import 'monaco-editor/esm/vs/editor/contrib/linesOperations/linesOperations.js'; // Needed for enabling shortcuts of removing/joining/moving lines
import 'monaco-editor/esm/vs/editor/contrib/folding/folding.js'; // Needed for folding
import 'monaco-editor/esm/vs/editor/contrib/suggest/suggestController.js'; // Needed for suggestions
import 'monaco-editor/esm/vs/editor/contrib/hover/hover.js'; // Needed for hover
import 'monaco-editor/esm/vs/editor/contrib/parameterHints/parameterHints.js'; // Needed for signature
import 'monaco-editor/esm/vs/editor/contrib/bracketMatching/bracketMatching.js'; // Needed for brackets matching highlight
import 'monaco-editor/esm/vs/editor/contrib/wordOperations/browser/wordOperations.js'; // Needed for word-wise char navigation
import 'monaco-editor/esm/vs/editor/contrib/linesOperations/browser/linesOperations.js'; // Needed for enabling shortcuts of removing/joining/moving lines
import 'monaco-editor/esm/vs/editor/contrib/folding/browser/folding.js'; // Needed for folding
import 'monaco-editor/esm/vs/editor/contrib/suggest/browser/suggestController.js'; // Needed for suggestions
import 'monaco-editor/esm/vs/editor/contrib/hover/browser/hover.js'; // Needed for hover
import 'monaco-editor/esm/vs/editor/contrib/parameterHints/browser/parameterHints.js'; // Needed for signature
import 'monaco-editor/esm/vs/editor/contrib/bracketMatching/browser/bracketMatching.js'; // Needed for brackets matching highlight
import 'monaco-editor/esm/vs/language/json/monaco.contribution.js';
import 'monaco-editor/esm/vs/basic-languages/javascript/javascript.contribution.js'; // Needed for basic javascript support

View file

@ -11,6 +11,7 @@ import { PainlessLang } from './painless';
import { SQLLang } from './sql';
import { monaco } from './monaco_imports';
import { ESQL_THEME_ID, ESQLLang, buildESQlTheme } from './esql';
import { YAML_LANG_ID } from './yaml';
import { registerLanguage, registerTheme } from './helpers';
export const DEFAULT_WORKER_ID = 'default';
@ -19,7 +20,7 @@ const langSpecificWorkerIds = [
PainlessLang.ID,
ESQLLang.ID,
monaco.languages.json.jsonDefaults.languageId,
'yaml',
YAML_LANG_ID,
];
/**
@ -37,9 +38,8 @@ registerTheme(ESQL_THEME_ID, buildESQlTheme());
const monacoBundleDir = (window as any).__kbnPublicPath__?.['kbn-monaco'];
// @ts-ignore
window.MonacoEnvironment = {
// needed for functional tests so that we can get value from 'editor'
// @ts-expect-error needed for functional tests so that we can get value from 'editor'
monaco,
getWorkerUrl: monacoBundleDir
? (_: string, languageId: string) => {
@ -48,5 +48,5 @@ window.MonacoEnvironment = {
: DEFAULT_WORKER_ID;
return `${monacoBundleDir}${workerId}.editor.worker.js`;
}
: () => undefined,
: () => '',
};

View file

@ -46,7 +46,7 @@ monaco.languages.onLanguage(ID, async () => {
};
const onModelAdd = (model: monaco.editor.IModel) => {
if (model.getModeId() !== ID) {
if (model.getLanguageId() !== ID) {
return;
}

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 ID = 'yaml';

View file

@ -0,0 +1,27 @@
/*
* 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 { type MonacoYamlOptions } from 'monaco-yaml';
import { monaco } from '../monaco_imports';
export { ID as YAML_LANG_ID } from './constants';
const monacoYamlDefaultOptions: MonacoYamlOptions = {
completion: true,
hover: true,
validate: true,
};
export const configureMonacoYamlSchema = async (schemas: MonacoYamlOptions['schemas']) => {
const { configureMonacoYaml } = await import(/* webpackChunkName: "monaco-yaml" */ 'monaco-yaml');
return configureMonacoYaml(monaco, {
...monacoYamlDefaultOptions,
schemas,
});
};

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.
*/
import 'monaco-yaml/yaml.worker.js';

View file

@ -14,23 +14,32 @@ const getWorkerEntry = (language) => {
return 'monaco-editor/esm/vs/editor/editor.worker.js';
case 'json':
return 'monaco-editor/esm/vs/language/json/json.worker.js';
case 'yaml':
return 'monaco-yaml/lib/esm/yaml.worker.js';
default:
return path.resolve(__dirname, 'src', language, 'worker', `${language}.worker.ts`);
}
};
const getWorkerConfig = (language) => ({
/**
* @param {string[]} languages - list of supported languages to build workers for
* @returns {import('webpack').Configuration}
*/
const workerConfig = (languages) => ({
mode: process.env.NODE_ENV || 'development',
entry: getWorkerEntry(language),
entry: languages.reduce((entries, language) => {
entries[language] = getWorkerEntry(language);
return entries;
}, {}),
devtool: process.env.NODE_ENV === 'production' ? false : '#cheap-source-map',
output: {
path: path.resolve(__dirname, 'target_workers'),
filename: `${language}.editor.worker.js`,
filename: ({ chunk }) => `${chunk.name}.editor.worker.js`,
},
resolve: {
extensions: ['.js', '.ts', '.tsx'],
alias: {
// swap default umd import for the esm one provided in vscode-uri package
'vscode-uri$': require.resolve('vscode-uri').replace(/\/umd\/index.js/, '/esm/index.mjs'),
},
},
stats: 'errors-only',
module: {
@ -47,8 +56,35 @@ const getWorkerConfig = (language) => ({
},
},
},
{
/**
* further process the modules exported by monaco-editor and monaco-yaml
* because their exports leverage some none-standard language APIs at this time.
*/
test: /(monaco-editor\/esm\/vs\/language|monaco-yaml|vscode-uri)\/.*m?(t|j)sx?$/,
use: {
loader: 'babel-loader',
options: {
babelrc: false,
envName: process.env.NODE_ENV || 'development',
presets: [require.resolve('@kbn/babel-preset/webpack_preset')],
},
},
},
],
},
optimization: {
minimizer: [
(compiler) => {
const TerserPlugin = require('terser-webpack-plugin');
new TerserPlugin({
// exclude this file from being processed by terser,
// because attempts at tree shaking actually botches up the file
exclude: /monaco-editor[\\/]esm[\\/]vs[\\/]base[\\/]common[\\/]map.js/,
}).apply(compiler);
},
],
},
});
module.exports = ['default', 'json', 'painless', 'xjson', 'esql', 'yaml'].map(getWorkerConfig);
module.exports = workerConfig(['default', 'json', 'painless', 'xjson', 'esql', 'yaml']);

View file

@ -103,9 +103,9 @@ module.exports = {
// An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation
transformIgnorePatterns: [
// ignore all node_modules except monaco-editor and react-monaco-editor which requires babel transforms to handle dynamic import()
// ignore all node_modules except monaco-editor, monaco-yaml and react-monaco-editor which requires 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(?![\\/\\\\](byte-size|monaco-editor|monaco-yaml|vscode-languageserver-types|react-monaco-editor|d3-interpolate|d3-color|langchain|langsmith|@cfworker|gpt-tokenizer))[/\\\\].+\\.js$',
'[/\\\\]node_modules(?![\\/\\\\](byte-size|monaco-editor|monaco-yaml|monaco-languageserver-types|monaco-marker-data-provider|monaco-worker-manager|vscode-languageserver-types|react-monaco-editor|d3-interpolate|d3-color|langchain|langsmith|@cfworker|gpt-tokenizer))[/\\\\].+\\.js$',
'packages/kbn-pm/dist/index.js',
'[/\\\\]node_modules(?![\\/\\\\](langchain|langsmith))/dist/[/\\\\].+\\.js$',
'[/\\\\]node_modules(?![\\/\\\\](langchain|langsmith))/dist/util/[/\\\\].+\\.js$',

View file

@ -16,6 +16,7 @@ webpack_cli(
"@npm//babel-loader",
"@npm//css-loader",
"@npm//url-loader",
"@npm//@babel/plugin-transform-numeric-separator",
"//packages/kbn-ui-shared-deps-npm",
"//packages/kbn-babel-register",
"//packages/kbn-babel-preset",

View file

@ -84,6 +84,23 @@ module.exports = {
presets: [require.resolve('@kbn/babel-preset/webpack_preset')],
},
},
{
/**
* further process the modules exported by both monaco-editor and monaco-yaml, because;
* 1). they both use non-standard language APIs
* 2). monaco-yaml exports it's src as is see, https://www.npmjs.com/package/monaco-yaml#does-it-work-without-a-bundler
*/
test: /(monaco-editor\/esm\/vs\/|monaco-languageserver-types|monaco-marker-data-provider|monaco-worker-manager).*(t|j)sx?$/,
use: {
loader: 'babel-loader',
options: {
babelrc: false,
envName: process.env.NODE_ENV || 'development',
presets: [require.resolve('@kbn/babel-preset/webpack_preset')],
plugins: [require.resolve('@babel/plugin-transform-numeric-separator')],
},
},
},
],
},

View file

@ -293,11 +293,13 @@ exports[`<CodeEditor /> is rendered 1`] = `
<MockedMonacoEditor
editorDidMount={[Function]}
editorWillMount={[Function]}
editorWillUnmount={[Function]}
height={250}
language="loglang"
onChange={[Function]}
options={
Object {
"bracketPairColorization.enabled": false,
"fontFamily": "Roboto Mono",
"fontSize": 12,
"lineHeight": 21,
@ -328,12 +330,14 @@ exports[`<CodeEditor /> is rendered 1`] = `
<div />
<textarea
data-test-subj="monacoEditorTextarea"
editorWillUnmount={[Function]}
height={250}
language="loglang"
onChange={[Function]}
onKeyDown={[Function]}
options={
Object {
"bracketPairColorization.enabled": false,
"fontFamily": "Roboto Mono",
"fontSize": 12,
"lineHeight": 21,

View file

@ -8,7 +8,9 @@
import React, { useState, useRef, useCallback, useMemo, useEffect, KeyboardEvent } from 'react';
import { useResizeDetector } from 'react-resize-detector';
import ReactMonacoEditor from 'react-monaco-editor';
import ReactMonacoEditor, {
type MonacoEditorProps as ReactMonacoEditorProps,
} from 'react-monaco-editor';
import {
htmlIdGenerator,
EuiToolTip,
@ -57,35 +59,35 @@ export interface CodeEditorProps {
/**
* Options for the Monaco Code Editor
* Documentation of options can be found here:
* https://microsoft.github.io/monaco-editor/api/interfaces/monaco.editor.istandaloneeditorconstructionoptions.html
* https://microsoft.github.io/monaco-editor/docs.html#interfaces/editor.IStandaloneEditorConstructionOptions.html
*/
options?: monaco.editor.IStandaloneEditorConstructionOptions;
/**
* Suggestion provider for autocompletion
* Documentation for the provider can be found here:
* https://microsoft.github.io/monaco-editor/api/interfaces/monaco.languages.completionitemprovider.html
* https://microsoft.github.io/monaco-editor/docs.html#interfaces/languages.CompletionItemProvider.html
*/
suggestionProvider?: monaco.languages.CompletionItemProvider;
/**
* Signature provider for function parameter info
* Documentation for the provider can be found here:
* https://microsoft.github.io/monaco-editor/api/interfaces/monaco.languages.signaturehelpprovider.html
* https://microsoft.github.io/monaco-editor/docs.html#interfaces/languages.SignatureHelpProvider.html
*/
signatureProvider?: monaco.languages.SignatureHelpProvider;
/**
* Hover provider for hover documentation
* Documentation for the provider can be found here:
* https://microsoft.github.io/monaco-editor/api/interfaces/monaco.languages.hoverprovider.html
* https://microsoft.github.io/monaco-editor/docs.html#interfaces/languages.HoverProvider.html
*/
hoverProvider?: monaco.languages.HoverProvider;
/**
* Language config provider for bracket
* Documentation for the provider can be found here:
* https://microsoft.github.io/monaco-editor/api/interfaces/monaco.languages.languageconfiguration.html
* https://microsoft.github.io/monaco-editor/docs.html#interfaces/languages.LanguageConfiguration.html
*/
languageConfiguration?: monaco.languages.LanguageConfiguration;
@ -127,6 +129,10 @@ export interface CodeEditorProps {
isCopyable?: boolean;
allowFullScreen?: boolean;
/**
* Alternate text to display, when an attempt is made to edit read only content. (Defaults to "Cannot edit in read-only editor")
*/
readOnlyMessage?: string;
}
export const CodeEditor: React.FC<CodeEditorProps> = ({
@ -151,6 +157,9 @@ export const CodeEditor: React.FC<CodeEditorProps> = ({
}),
isCopyable = false,
allowFullScreen = false,
readOnlyMessage = i18n.translate('sharedUXPackages.codeEditor.readOnlyMessage', {
defaultMessage: 'Cannot edit in read-only editor',
}),
}) => {
const { colorMode, euiTheme } = useEuiTheme();
const useDarkTheme = useDarkThemeProp ?? colorMode === 'DARK';
@ -311,8 +320,8 @@ export const CodeEditor: React.FC<CodeEditorProps> = ({
);
}, [isHintActive, isReadOnly, euiTheme, startEditing, onKeyDownHint, ariaLabel]);
const _editorWillMount = useCallback(
(__monaco: unknown) => {
const _editorWillMount = useCallback<NonNullable<ReactMonacoEditorProps['editorWillMount']>>(
(__monaco) => {
if (__monaco !== monaco) {
throw new Error('react-monaco-editor is using a different version of monaco');
}
@ -361,8 +370,8 @@ export const CodeEditor: React.FC<CodeEditorProps> = ({
]
);
const _editorDidMount = useCallback(
(editor: monaco.editor.IStandaloneCodeEditor, __monaco: unknown) => {
const _editorDidMount = useCallback<NonNullable<ReactMonacoEditorProps['editorDidMount']>>(
(editor, __monaco) => {
if (__monaco !== monaco) {
throw new Error('react-monaco-editor is using a different version of monaco');
}
@ -373,7 +382,7 @@ export const CodeEditor: React.FC<CodeEditorProps> = ({
const textbox = editor.getDomNode()?.getElementsByTagName('textarea')[0];
if (textbox) {
// Make sure the textarea is not directly accesible with TAB
// Make sure the textarea is not directly accessible with TAB
textbox.tabIndex = -1;
// The Monaco editor seems to override the tabindex and set it back to "0"
@ -389,6 +398,13 @@ export const CodeEditor: React.FC<CodeEditorProps> = ({
editor.onKeyDown(onKeydownMonaco);
editor.onDidBlurEditorText(onBlurMonaco);
const messageContribution = editor.getContribution('editor.contrib.messageController');
editor.onDidAttemptReadOnlyEdit(() => {
// @ts-expect-error the show message API does exist and is documented here
// https://github.com/microsoft/vscode/commit/052f02175f4752c36024c18cfbca4e13403e10c3
messageContribution?.showMessage(readOnlyMessage, editor.getPosition());
});
// "widget" is not part of the TS interface but does exist
// @ts-expect-errors
const suggestionWidget = editor.getContribution('editor.contrib.suggestController')?.widget
@ -407,7 +423,15 @@ export const CodeEditor: React.FC<CodeEditorProps> = ({
editorDidMount?.(editor);
},
[editorDidMount, onBlurMonaco, onKeydownMonaco]
[editorDidMount, onBlurMonaco, onKeydownMonaco, readOnlyMessage]
);
const _editorWillUnmount = useCallback<NonNullable<ReactMonacoEditorProps['editorWillUnmount']>>(
(editor) => {
const model = editor.getModel();
model?.dispose();
},
[]
);
useEffect(() => {
@ -431,7 +455,7 @@ export const CodeEditor: React.FC<CodeEditorProps> = ({
const { CopyButton } = useCopy({ isCopyable, value });
useEffect(() => {
// Register themes when 'useDarkThem' changes
// Register themes when 'useDarkTheme' changes
monaco.editor.defineTheme('euiColors', useDarkTheme ? DARK_THEME : LIGHT_THEME);
monaco.editor.defineTheme(
'euiColorsTransparent',
@ -478,6 +502,7 @@ export const CodeEditor: React.FC<CodeEditorProps> = ({
height={isFullScreen ? '100vh' : height}
editorWillMount={_editorWillMount}
editorDidMount={_editorDidMount}
editorWillUnmount={_editorWillUnmount}
options={{
padding: allowFullScreen || isCopyable ? { top: 24 } : {},
renderLineHighlight: 'none',
@ -499,6 +524,8 @@ export const CodeEditor: React.FC<CodeEditorProps> = ({
fontFamily: 'Roboto Mono',
fontSize: isFullScreen ? 16 : 12,
lineHeight: isFullScreen ? 24 : 21,
// @ts-expect-error, see https://github.com/microsoft/monaco-editor/issues/3829
'bracketPairColorization.enabled': false,
...options,
}}
/>

View file

@ -132,10 +132,14 @@ export function createTheme(
'editorWidget.border': euiTheme.euiColorLightShade,
'editorWidget.background': euiTheme.euiColorLightestShade,
'editorCursor.foreground': euiTheme.euiColorDarkestShade,
'editorSuggestWidget.selectedForeground': euiTheme.euiColorDarkestShade,
'editorSuggestWidget.focusHighlightForeground': euiTheme.euiColorPrimary,
'editorSuggestWidget.selectedBackground': euiTheme.euiColorLightShade,
'list.hoverBackground': euiTheme.euiColorLightShade,
'list.highlightForeground': euiTheme.euiColorPrimary,
'editor.lineHighlightBorder': euiTheme.euiColorLightestShade,
'editorHoverWidget.foreground': euiTheme.euiColorDarkestShade,
'editorHoverWidget.background': euiTheme.euiFormBackgroundColor,
},
};
}

View file

@ -30,83 +30,107 @@ beforeAll(() => {
};
registerLanguage(Lang);
// trigger tokenizer creation by instantiating a model,
// see https://github.com/microsoft/monaco-editor/commit/3a58c2a6ba2ffa1f3f34ed52204bc53c8b522afc
const model = monaco.editor.createModel('', Lang.ID);
model.dispose();
});
test('lang', () => {
expect(monaco.editor.tokenize('\\[(?:-|%{NUMBER:bytes:int})\\]', 'grok')).toMatchInlineSnapshot(`
test(`lang (${Lang.ID})`, () => {
expect(monaco.languages.getLanguages()).toEqual(
expect.arrayContaining([expect.objectContaining({ id: Lang.ID })])
);
expect(monaco.editor.tokenize('\\[(?:-|%{NUMBER:bytes:int})\\]', Lang.ID)).toMatchInlineSnapshot(`
Array [
Array [
Token {
"_tokenBrand": undefined,
"language": "grok",
"offset": 0,
"type": "string.escape.grokEscape.grok",
},
Token {
"_tokenBrand": undefined,
"language": "grok",
"offset": 1,
"type": "source.grokEscaped.grok",
},
Token {
"_tokenBrand": undefined,
"language": "grok",
"offset": 2,
"type": "regexp.grokRegex.grok",
},
Token {
"_tokenBrand": undefined,
"language": "grok",
"offset": 5,
"type": "source.grok",
},
Token {
"_tokenBrand": undefined,
"language": "grok",
"offset": 6,
"type": "regexp.grokRegex.grok",
},
Token {
"_tokenBrand": undefined,
"language": "grok",
"offset": 7,
"type": "string.openGrok.grok",
},
Token {
"_tokenBrand": undefined,
"language": "grok",
"offset": 9,
"type": "variable.syntax.grok",
},
Token {
"_tokenBrand": undefined,
"language": "grok",
"offset": 15,
"type": "string.separator.grok",
},
Token {
"_tokenBrand": undefined,
"language": "grok",
"offset": 16,
"type": "variable.id.grok",
},
Token {
"_tokenBrand": undefined,
"language": "grok",
"offset": 21,
"type": "string.separator.grok",
},
Token {
"_tokenBrand": undefined,
"language": "grok",
"offset": 22,
"type": "variable.type.grok",
},
Token {
"_tokenBrand": undefined,
"language": "grok",
"offset": 25,
"type": "string.closeGrok.grok",
},
Token {
"_tokenBrand": undefined,
"language": "grok",
"offset": 26,
"type": "regexp.grokRegex.grok",
},
Token {
"_tokenBrand": undefined,
"language": "grok",
"offset": 27,
"type": "string.escape.grokEscape.grok",
},
Token {
"_tokenBrand": undefined,
"language": "grok",
"offset": 28,
"type": "source.grokEscaped.grok",

View file

@ -57,6 +57,7 @@ function createEditorInstance() {
onKeyDown: jest.fn((listener) => {
keyDownListeners.push(listener);
}),
onDidAttemptReadOnlyEdit: jest.fn(),
onDidBlurEditorText: jest.fn(),
onDidChangeModelContent: jest.fn((cb) => cb()),
onDidFocusEditorText: jest.fn((cb) => cb()),
@ -101,7 +102,8 @@ export const MockedMonacoEditor = ({
onChange,
value,
...rest
}: MonacoEditorProps & {
}: Omit<MonacoEditorProps, 'className'> & {
className?: string;
['data-test-subj']?: string;
}) => {
editorWillMount?.(monaco);

View file

@ -133,7 +133,6 @@ export const UrlTemplateEditor: React.FC<UrlTemplateEditorProps> = ({
placeholder={placeholder}
options={{
fontSize: 14,
highlightActiveIndentGuide: false,
renderLineHighlight: 'none',
lineNumbers: 'off',
glyphMargin: false,
@ -148,6 +147,9 @@ export const UrlTemplateEditor: React.FC<UrlTemplateEditorProps> = ({
minimap: {
enabled: false,
},
guides: {
highlightActiveIndentation: false,
},
wordWrap: 'on',
wrappingIndent: 'none',
}}

View file

@ -8,13 +8,15 @@ exports[`Inspect component renders correctly 1`] = `
Object {
"automaticLayout": false,
"fontSize": 12,
"guides": Object {
"indentation": false,
},
"lineNumbers": "on",
"minimap": Object {
"enabled": false,
},
"overviewRulerBorder": false,
"readOnly": true,
"renderIndentGuides": false,
"scrollBeyondLastLine": false,
"scrollbar": Object {
"alwaysConsumeMouseWheel": false,

View file

@ -70,7 +70,9 @@ export const Inspect: FC<InspectProps> = ({ object }) => {
scrollBeyondLastLine: false,
wordWrap: 'on',
wrappingIndent: 'indent',
renderIndentGuides: false,
guides: {
indentation: false,
},
}}
/>
</EuiFlexItem>

View file

@ -245,9 +245,9 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) {
expect(value).to.eql('.e');
const suggestions = await timelion.getSuggestionItemsText();
expect(suggestions.length).to.eql(2);
expect(suggestions[0].includes('es')).to.eql(true);
expect(suggestions[1].includes('elasticsearch')).to.eql(true);
await timelion.clickSuggestion(0);
expect(suggestions[0].includes('elasticsearch')).to.eql(true);
expect(suggestions[1].includes('es')).to.eql(true);
await timelion.clickSuggestion(1);
// wait for monaco editor model will be updated with new value
await common.sleep(300);
value = await monacoEditor.getCodeEditorValue(0);

View file

@ -6,6 +6,7 @@
* Side Public License, v 1.
*/
import { type monaco } from '@kbn/monaco';
import { FtrService } from '../ftr_provider_context';
export class MonacoEditorService extends FtrService {
@ -25,7 +26,8 @@ export class MonacoEditorService extends FtrService {
await this.retry.try(async () => {
values = await this.browser.execute(
() =>
(window as any).MonacoEnvironment.monaco.editor
// @ts-expect-error this value is provided in @kbn/monaco for this specific purpose, see {@link packages/kbn-monaco/src/register_globals.ts}
(window.MonacoEnvironment?.monaco.editor as typeof monaco.editor)
.getModels()
.map((model: any) => model.getValue()) as string[]
);
@ -40,13 +42,20 @@ export class MonacoEditorService extends FtrService {
await textarea.type(value);
}
public async setCodeEditorValue(value: string, nthIndex = 0) {
public async setCodeEditorValue(value: string, nthIndex?: number) {
await this.retry.try(async () => {
await this.browser.execute(
(editorIndex, codeEditorValue) => {
const editor = (window as any).MonacoEnvironment.monaco.editor;
const instance = editor.getModels()[editorIndex];
instance.setValue(codeEditorValue);
// @ts-expect-error this value is provided in @kbn/monaco for this specific purpose, see {@link packages/kbn-monaco/src/register_globals.ts}
const editor = window.MonacoEnvironment?.monaco.editor as typeof monaco.editor;
const textModels = editor.getModels();
if (editorIndex) {
textModels[editorIndex].setValue(codeEditorValue);
} else {
// when specific model instance is unknown, update all models returned
textModels.forEach((model) => model.setValue(codeEditorValue));
}
},
nthIndex,
value

View file

@ -72,5 +72,6 @@
"@kbn/event-annotation-common",
"@kbn/links-plugin",
"@kbn/ftr-common-functional-ui-services",
"@kbn/monaco",
]
}

View file

@ -13,6 +13,8 @@ window.matchMedia = jest.fn().mockImplementation((query) => ({
matches: false,
media: query,
onchange: null,
addListener: jest.fn(),
removeListener: jest.fn(),
addListener: jest.fn(), // deprecated
removeListener: jest.fn(), // deprecated
addEventListener: jest.fn(),
removeEventListener: jest.fn(),
}));

View file

@ -4,13 +4,12 @@
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { useMemo } from 'react';
import { setDiagnosticsOptions } from 'monaco-yaml';
import { monaco } from '@kbn/monaco';
import { useMemo, useState, useEffect } from 'react';
import { monaco, configureMonacoYamlSchema, YAML_LANG_ID } from '@kbn/monaco';
import { getSelectorsAndResponsesFromYaml } from '../../../../common/utils/helpers';
/**
* In order to keep this json in sync with https://github.com/elastic/cloud-defend/blob/main/modules/service/policy-schema.json
* In order to keep this json in sync with https://github.com/elastic/cloud-defend/blob/main/modules/config/policy-schema.json
* Do NOT commit edits to policy_schema.json as part of a PR. Please make the changes in the cloud-defend repo.
* Buildkite will take care of creating a PR in kibana.
*/
@ -22,13 +21,15 @@ const SCHEMA_URI = 'http://elastic.co/cloud_defend.json';
const modelUri = Uri.parse(SCHEMA_URI);
export const useConfigModel = (configuration: string) => {
return useMemo(() => {
const [configModel, setConfigModel] = useState<monaco.editor.ITextModel | null>(null);
const schema = useMemo(() => {
const _schema: any = { ...policySchemaJson };
const { selectors } = getSelectorsAndResponsesFromYaml(configuration);
const schema: any = { ...policySchemaJson };
// dynamically setting enum values for response match and exclude properties.
if (schema.$defs.fileResponse.properties.match.items) {
const responseProps = schema.$defs.fileResponse.properties;
if (_schema.$defs.fileResponse.properties.match.items) {
const responseProps = _schema.$defs.fileResponse.properties;
const selectorEnum = {
enum: selectors
.filter((selector) => selector.type === 'file')
@ -38,8 +39,8 @@ export const useConfigModel = (configuration: string) => {
responseProps.exclude.items = selectorEnum;
}
if (schema.$defs.processResponse.properties.match.items) {
const responseProps = schema.$defs.processResponse.properties;
if (_schema.$defs.processResponse.properties.match.items) {
const responseProps = _schema.$defs.processResponse.properties;
const selectorEnum = {
enum: selectors
.filter((selector) => selector.type === 'process')
@ -49,25 +50,32 @@ export const useConfigModel = (configuration: string) => {
responseProps.exclude.items = selectorEnum;
}
setDiagnosticsOptions({
validate: true,
completion: true,
hover: true,
schemas: [
{
uri: SCHEMA_URI,
fileMatch: [String(modelUri)],
schema,
},
],
});
return _schema;
}, [configuration]);
let model = editor.getModel(modelUri);
useEffect(() => {
async function configureMonacoYaml(...args: Parameters<typeof configureMonacoYamlSchema>) {
const { dispose } = await configureMonacoYamlSchema(...args);
if (model === null) {
model = editor.createModel('', 'yaml', modelUri);
let model = editor.getModel(modelUri);
if (model === null) {
model = editor.createModel('', YAML_LANG_ID, modelUri);
}
setConfigModel(model);
return () => dispose();
}
return model;
}, [configuration]);
configureMonacoYaml([
{
uri: SCHEMA_URI,
fileMatch: [String(modelUri)],
schema,
},
]);
}, [schema]);
return configModel;
};

View file

@ -35,6 +35,10 @@ import { login } from '../tasks/login';
import { visit } from '../tasks/common';
export const fillYamlConfigBox = (query: string) => {
cy.get('[data-test-subj="kibanaCodeEditor"] textarea').type(query, { force: true });
};
describe('Outputs', () => {
beforeEach(() => {
login();
@ -51,7 +55,7 @@ describe('Outputs', () => {
it('forces custom when reserved key is included in config YAML box', () => {
selectESOutput();
cy.getBySel('kibanaCodeEditor').click().focused().type('bulk_max_size: 1000');
fillYamlConfigBox('bulk_max_size: 1000');
cy.getBySel(SETTINGS_OUTPUTS.PRESET_INPUT)
.should('have.value', 'custom')
@ -61,7 +65,7 @@ describe('Outputs', () => {
it('allows balanced when reserved key is not included in config yaml box', () => {
selectESOutput();
cy.getBySel('kibanaCodeEditor').click().focused().type('some_random_key: foo');
fillYamlConfigBox('some_random_key: foo');
cy.getBySel(SETTINGS_OUTPUTS.PRESET_INPUT)
.should('have.value', 'balanced')

View file

@ -122,7 +122,7 @@ export function PromptEditorFunction({
fontSize: 12,
formatOnPaste: true,
formatOnType: true,
inlineHints: { enabled: true },
inlayHints: { enabled: 'on' },
lineNumbers: 'on',
minimap: { enabled: false },
model,

View file

@ -14,7 +14,9 @@ window.matchMedia = jest.fn().mockImplementation((query) => {
matches: false,
media: query,
onchange: null,
addListener: jest.fn(),
removeListener: jest.fn(),
addListener: jest.fn(), // deprecated
removeListener: jest.fn(), // deprecated
addEventListener: jest.fn(),
removeEventListener: jest.fn(),
};
});

View file

@ -81,6 +81,7 @@ const TinesParamsFields: React.FunctionComponent<ActionParamsProps<TinesExecuteA
const [selectedWebhookOption, setSelectedWebhookOption] = useState<
WebhookOption | null | undefined
>();
const [bodyOption, setBodyOption] = useState<string>('');
const isTest = useMemo(() => executionMode === ActionConnectorMode.Test, [executionMode]);
@ -88,8 +89,7 @@ const TinesParamsFields: React.FunctionComponent<ActionParamsProps<TinesExecuteA
if (!subAction) {
editAction('subAction', isTest ? SUB_ACTION.TEST : SUB_ACTION.RUN, index);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [isTest, subAction]);
}, [editAction, index, isTest, subAction]);
if (connectorId !== actionConnector?.id) {
// Story (and webhook) reset needed before requesting with a different connectorId
@ -198,6 +198,12 @@ const TinesParamsFields: React.FunctionComponent<ActionParamsProps<TinesExecuteA
}
}, [selectedWebhookOption, webhook, webhooks, toasts, editSubActionParams]);
useEffect(() => {
if (body !== bodyOption) {
editSubActionParams({ body: bodyOption });
}
}, [body, bodyOption, editSubActionParams]);
const selectedStoryOptions = useMemo(
() => (selectedStoryOption ? [selectedStoryOption] : []),
[selectedStoryOption]
@ -309,14 +315,7 @@ const TinesParamsFields: React.FunctionComponent<ActionParamsProps<TinesExecuteA
label={i18n.BODY_LABEL}
ariaLabel={i18n.BODY_ARIA_LABEL}
errors={errors.body as string[]}
onDocumentsChange={(json: string) => {
editSubActionParams({ body: json });
}}
onBlur={() => {
if (!body) {
editSubActionParams({ body: '' });
}
}}
onDocumentsChange={setBodyOption}
dataTestSubj="tines-bodyJsonEditor"
/>
</EuiFlexItem>

View file

@ -192,7 +192,10 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
// Toggle metadata switch so the code editor shows up
await apiKeyMetadataSwitch.click();
// Check default value of metadata and set value
// wait for monaco editor model to be updated
await pageObjects.common.sleep(300);
// Check default value of restrict privileges and set value
const restrictPrivilegesCodeEditorValue =
await pageObjects.apiKeys.getCodeEditorValueByIndex(0);
expect(restrictPrivilegesCodeEditorValue).to.be('{}');

View file

@ -20,6 +20,9 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
const kibanaServer = getService('kibanaServer');
describe('dls', function () {
const customUserName = 'userEast';
const customRole = 'myroleEast';
before('initialize tests', async () => {
await kibanaServer.savedObjects.cleanStandardList();
await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/security/dlstest');
@ -33,8 +36,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
await PageObjects.security.clickElasticsearchRoles();
});
it('should add new role myroleEast', async function () {
await PageObjects.security.addRole('myroleEast', {
it(`should add new role ${customRole}`, async function () {
await PageObjects.security.addRole(customRole, {
elasticsearch: {
indices: [
{
@ -47,29 +50,29 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
});
const roles = keyBy(await PageObjects.security.getElasticsearchRoles(), 'rolename');
log.debug('actualRoles = %j', roles);
expect(roles).to.have.key('myroleEast');
expect(roles.myroleEast.reserved).to.be(false);
expect(roles).to.have.key(customRole);
expect(roles[customRole].reserved).to.be(false);
await screenshot.take('Security_Roles');
});
it('should add new user userEAST ', async function () {
it(`should add new user ${customUserName}`, async function () {
await PageObjects.security.createUser({
username: 'userEast',
username: customUserName,
password: 'changeme',
confirm_password: 'changeme',
full_name: 'dls EAST',
email: 'dlstest@elastic.com',
roles: ['kibana_admin', 'myroleEast'],
roles: ['kibana_admin', customRole],
});
const users = keyBy(await PageObjects.security.getElasticsearchUsers(), 'username');
log.debug('actualUsers = %j', users);
expect(users.userEast.roles).to.eql(['kibana_admin', 'myroleEast']);
expect(users.userEast.reserved).to.be(false);
expect(users[customUserName].roles).to.eql(['kibana_admin', customRole]);
expect(users[customUserName].reserved).to.be(false);
});
it('user East should only see EAST doc', async function () {
await PageObjects.security.forceLogout();
await PageObjects.security.login('userEast', 'changeme');
await PageObjects.security.login(customUserName, 'changeme');
await PageObjects.common.navigateToApp('discover');
await retry.try(async () => {
const hitCount = await PageObjects.discover.getHitCount();
@ -82,8 +85,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
after('logout', async () => {
// NOTE: Logout needs to happen before anything else to avoid flaky behavior
await PageObjects.security.forceLogout();
await security.user.delete('userEast');
await security.role.delete('myroleEast');
await security.user.delete(customUserName);
await security.role.delete(customRole);
await security.testUser.restoreDefaults();
});
});

View file

@ -616,7 +616,11 @@ export class SecurityPageObject extends FtrService {
if (roleObj.elasticsearch.indices[0].query) {
await this.testSubjects.click('restrictDocumentsQuery0');
await this.monacoEditor.setCodeEditorValue(roleObj.elasticsearch.indices[0].query);
await this.monacoEditor.typeCodeEditorValue(
roleObj.elasticsearch.indices[0].query,
'kibanaCodeEditor'
);
}
await this.testSubjects.click('addSpacePrivilegeButton');

View file

@ -21,7 +21,7 @@ export function ActionsTinesServiceProvider(
common: ActionsCommon
) {
const testSubjects = getService('testSubjects');
const find = getService('find');
const monacoEditor = getService('monacoEditor');
return {
async createNewConnector(fields: ConnectorFormFields) {
@ -51,10 +51,7 @@ export function ActionsTinesServiceProvider(
async setJsonEditor(value: object) {
const stringified = JSON.stringify(value);
await find.clickByCssSelector('.monaco-editor');
const input = await find.activeElement();
await input.clearValueWithKeyboard({ charByChar: true });
await input.type(stringified);
await monacoEditor.setCodeEditorValue(stringified);
},
};
}

View file

@ -553,15 +553,16 @@ export const fillDefineNewTermsRuleAndContinue = (rule: NewTermsRuleCreateProps)
cy.get(DEFINE_CONTINUE_BUTTON).should('exist').click({ force: true });
};
export const fillEsqlQueryBar = (query: string) => {
// eslint-disable-next-line cypress/no-force
cy.get(ESQL_QUERY_BAR_INPUT_AREA).type(query, { force: true });
};
export const clearEsqlQueryBar = () => {
// monaco editor under the hood is quite complex in matter to clear it
// underlying textarea holds just the last character of query displayed in search bar
// in order to clear it - it requires to select all text within editor and type in it
cy.get(ESQL_QUERY_BAR_INPUT_AREA).type(Cypress.platform === 'darwin' ? '{cmd}a' : '{ctrl}a');
};
export const fillEsqlQueryBar = (query: string) => {
cy.get(ESQL_QUERY_BAR_INPUT_AREA).type(query);
fillEsqlQueryBar(Cypress.platform === 'darwin' ? '{cmd}a' : '{ctrl}a');
};
/**

View file

@ -10,7 +10,6 @@ import {
DISCOVER_CONTAINER,
DISCOVER_DATA_GRID_UPDATING,
DISCOVER_DATA_VIEW_SWITCHER,
DISCOVER_ESQL_INPUT,
GET_DISCOVER_COLUMN_TOGGLE_BTN,
DISCOVER_FIELD_SEARCH,
DISCOVER_DATA_VIEW_EDITOR_FLYOUT,
@ -46,19 +45,26 @@ export const waitForDiscoverGridToLoad = () => {
cy.get(DISCOVER_FIELD_LIST_LOADING).should('not.exist');
};
export const fillEsqlQueryBar = (query: string) => {
// eslint-disable-next-line cypress/no-force
cy.get(DISCOVER_ESQL_EDITABLE_INPUT).type(query, { force: true });
};
export const selectCurrentDiscoverEsqlQuery = (
discoverEsqlInput = DISCOVER_ESQL_EDITABLE_INPUT
) => {
goToEsqlTab();
cy.get(discoverEsqlInput).should('be.visible').click();
cy.get(DISCOVER_ESQL_INPUT_EXPAND).click();
cy.get(discoverEsqlInput).type(Cypress.platform === 'darwin' ? '{cmd+a}' : '{ctrl+a}');
// eslint-disable-next-line cypress/no-force
cy.get(discoverEsqlInput).click({ force: true });
// eslint-disable-next-line cypress/no-force
cy.get(DISCOVER_ESQL_INPUT_EXPAND).click({ force: true });
fillEsqlQueryBar(Cypress.platform === 'darwin' ? '{cmd+a}' : '{ctrl+a}');
};
export const addDiscoverEsqlQuery = (esqlQuery: string) => {
// ESQL input uses the monaco editor which doesn't allow for traditional input updates
selectCurrentDiscoverEsqlQuery(DISCOVER_ESQL_EDITABLE_INPUT);
cy.get(DISCOVER_ESQL_EDITABLE_INPUT).type(`${esqlQuery}`);
fillEsqlQueryBar(esqlQuery);
cy.get(DISCOVER_ESQL_EDITABLE_INPUT).blur();
cy.get(GET_LOCAL_SEARCH_BAR_SUBMIT_BUTTON(DISCOVER_CONTAINER)).click();
};
@ -76,7 +82,7 @@ export const verifyDiscoverEsqlQuery = (esqlQueryToVerify: string) => {
* https://github.com/cypress-io/cypress/issues/15863#issuecomment-816746693
*/
const unicodeReplacedQuery = esqlQueryToVerify.replaceAll(' ', '\u00b7');
cy.get(DISCOVER_ESQL_INPUT).should('include.text', unicodeReplacedQuery);
cy.get(DISCOVER_ESQL_EDITABLE_INPUT).should(($input) => $input.val() === unicodeReplacedQuery);
};
export const submitDiscoverSearchBar = () => {

129
yarn.lock
View file

@ -262,7 +262,7 @@
"@babel/helper-split-export-declaration" "^7.22.6"
semver "^6.3.1"
"@babel/helper-create-regexp-features-plugin@^7.18.6", "@babel/helper-create-regexp-features-plugin@^7.22.15", "@babel/helper-create-regexp-features-plugin@^7.22.5":
"@babel/helper-create-regexp-features-plugin@^7.22.15", "@babel/helper-create-regexp-features-plugin@^7.22.5":
version "7.22.15"
resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.22.15.tgz#5ee90093914ea09639b01c711db0d6775e558be1"
integrity sha512-29FkPLFjn4TPEa3RE7GpW+qbE8tlsu3jntNYNfcGsc49LphF1PQIiD+vMZ1z1xVOKt+93khA9tc2JBs3kBjA7w==
@ -468,7 +468,7 @@
"@babel/helper-environment-visitor" "^7.22.20"
"@babel/helper-plugin-utils" "^7.22.5"
"@babel/plugin-proposal-class-properties@^7.12.1", "@babel/plugin-proposal-class-properties@^7.18.6":
"@babel/plugin-proposal-class-properties@^7.12.1":
version "7.18.6"
resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.18.6.tgz#b110f59741895f7ec21a6fff696ec46265c446a3"
integrity sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ==
@ -733,10 +733,9 @@
"@babel/plugin-syntax-unicode-sets-regex@^7.18.6":
version "7.18.6"
resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz#d49a3b3e6b52e5be6740022317580234a6a47357"
integrity sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.18.6.tgz#19063fcf8771ec7b31d742339dac62433d0611fe"
integrity sha512-9S9X9RUefzrsHZmKMbDXxweEH+YlE8JJEuat9FdvW9Qh1cw7W64jELCtWNkPBPX5En45uy28KGvA/AySqUh8CQ==
dependencies:
"@babel/helper-create-regexp-features-plugin" "^7.18.6"
"@babel/helper-plugin-utils" "^7.18.6"
"@babel/plugin-transform-arrow-functions@^7.12.1", "@babel/plugin-transform-arrow-functions@^7.23.3":
@ -20700,7 +20699,7 @@ js-yaml@3.14.1, js-yaml@^3.13.1, js-yaml@^3.14.1:
argparse "^1.0.7"
esprima "^4.0.0"
js-yaml@4.1.0, js-yaml@^4.0.0, js-yaml@^4.1.0:
js-yaml@4.1.0, js-yaml@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602"
integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==
@ -20851,6 +20850,11 @@ json5@^1.0.1, json5@^1.0.2:
dependencies:
minimist "^1.2.0"
jsonc-parser@^3.0.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-3.2.0.tgz#31ff3f4c2b9793f89c67212627c51c6394f88e76"
integrity sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==
jsondiffpatch@0.4.1:
version "0.4.1"
resolved "https://registry.yarnpkg.com/jsondiffpatch/-/jsondiffpatch-0.4.1.tgz#9fb085036767f03534ebd46dcd841df6070c5773"
@ -22789,23 +22793,51 @@ moment@>=1.6.0, moment@>=2.14.0, moment@^2.10.6, moment@^2.29.4:
resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.4.tgz#3dbe052889fe7c1b2ed966fcb3a77328964ef108"
integrity sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==
monaco-editor@*, monaco-editor@^0.24.0:
version "0.24.0"
resolved "https://registry.yarnpkg.com/monaco-editor/-/monaco-editor-0.24.0.tgz#990b55096bcc95d08d8d28e55264c6eb17707269"
integrity sha512-o1f0Lz6ABFNTtnEqqqvlY9qzNx24rQZx1RgYNQ8SkWkE+Ka63keHH/RqxQ4QhN4fs/UYOnvAtEUZsPrzccH++A==
monaco-editor@^0.44.0:
version "0.44.0"
resolved "https://registry.yarnpkg.com/monaco-editor/-/monaco-editor-0.44.0.tgz#3c0fe3655923bbf7dd647057302070b5095b6c59"
integrity sha512-5SmjNStN6bSuSE5WPT2ZV+iYn1/yI9sd4Igtk23ChvqB7kDk9lZbB9F5frsuvpB+2njdIeGGFf2G4gbE6rCC9Q==
monaco-yaml@3.2.1:
version "3.2.1"
resolved "https://registry.yarnpkg.com/monaco-yaml/-/monaco-yaml-3.2.1.tgz#45ce9f7f8140dc26249ac99eb0a9e5a9ab9beb87"
integrity sha512-2geAd5I7H1SMgwTHBuyPAPK9WTAzxbl9XwDl5h6NY6n9j4qnlLLQKK1i0P9cAmUiV2uaiViz69RLNWqVU5BVsg==
monaco-languageserver-types@^0.2.0:
version "0.2.3"
resolved "https://registry.yarnpkg.com/monaco-languageserver-types/-/monaco-languageserver-types-0.2.3.tgz#1f98324c5b9f1ac7356ef529bd25e53a5fa97943"
integrity sha512-QyV5R7s+rJ87bX1sRioMJZULWiTnMp0Vm+RLILgMEL0SqWuBsQBSW0EZunr4xMZhv6Qun3UZNCN4JrCCLURcgQ==
dependencies:
monaco-types "^0.1.0"
vscode-languageserver-protocol "^3.0.0"
monaco-marker-data-provider@^1.0.0:
version "1.1.1"
resolved "https://registry.yarnpkg.com/monaco-marker-data-provider/-/monaco-marker-data-provider-1.1.1.tgz#0ca69f367152f5aa12cec2bda95f32b7403e876f"
integrity sha512-PGB7TJSZE5tmHzkxv/OEwK2RGNC2A7dcq4JRJnnj31CUAsfmw0Gl+1QTrH0W0deKhcQmQM0YVPaqgQ+0wCt8Mg==
monaco-types@^0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/monaco-types/-/monaco-types-0.1.0.tgz#3a3066aba499cb5923cd60efc736f3f14a169e10"
integrity sha512-aWK7SN9hAqNYi0WosPoMjenMeXJjwCxDibOqWffyQ/qXdzB/86xshGQobRferfmNz7BSNQ8GB0MD0oby9/5fTQ==
monaco-worker-manager@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/monaco-worker-manager/-/monaco-worker-manager-2.0.1.tgz#f67c54dfca34ed4b225d5de84e77b24b4e36de8a"
integrity sha512-kdPL0yvg5qjhKPNVjJoym331PY/5JC11aPJXtCZNwWRvBr6jhkIamvYAyiY5P1AWFmNOy0aRDRoMdZfa71h8kg==
monaco-yaml@^5.1.0:
version "5.1.0"
resolved "https://registry.yarnpkg.com/monaco-yaml/-/monaco-yaml-5.1.0.tgz#ba3445b4f683328cb43bc31dc52bc06e66a95b81"
integrity sha512-DU+cgXSJdOFKQ4I4oLg0V+mHKq1dJX+7hbIE4fJsgegUf1zEHW3PNlGj6qabUU2HZIPJ5NmXEf005GU9YDzTYQ==
dependencies:
"@types/json-schema" "^7.0.0"
js-yaml "^4.0.0"
jsonc-parser "^3.0.0"
monaco-languageserver-types "^0.2.0"
monaco-marker-data-provider "^1.0.0"
monaco-types "^0.1.0"
monaco-worker-manager "^2.0.0"
path-browserify "^1.0.0"
prettier "2.0.5"
prettier "^2.0.0"
vscode-languageserver-textdocument "^1.0.0"
vscode-languageserver-types "^3.0.0"
yaml-language-server-parser "^0.1.0"
vscode-uri "^3.0.0"
yaml "^2.0.0"
monitor-event-loop-delay@^1.0.0:
version "1.0.0"
@ -25017,17 +25049,12 @@ prettier-linter-helpers@^1.0.0:
dependencies:
fast-diff "^1.1.2"
prettier@2.0.5:
version "2.0.5"
resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.0.5.tgz#d6d56282455243f2f92cc1716692c08aa31522d4"
integrity sha512-7PtVymN48hGcO4fGjybyBSIWDsLU4H4XlvOHfq91pz9kkGlonzwTfYkaIEwiRg/dAJF9YlbsduBAgtYLi+8cFg==
"prettier@>=2.2.1 <=2.3.0":
version "2.2.1"
resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.2.1.tgz#795a1a78dd52f073da0cd42b21f9c91381923ff5"
integrity sha512-PqyhM2yCjg/oKkFPtTGUojv7gnZAoG80ttl45O6x2Ug/rMJw4wcc9k6aaf2hibP7BGVCCM33gZoGjyvt9mm16Q==
version "2.3.0"
resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.3.0.tgz#b6a5bf1284026ae640f17f7ff5658a7567fc0d18"
integrity sha512-kXtO4s0Lz/DW/IJ9QdWhAf7/NmPWQXkFr/r/WkR3vyI+0v8amTDxiaQSLzs8NBlytfLWX/7uQUMIW677yLKl4w==
prettier@^2.7.1:
prettier@^2.0.0, prettier@^2.7.1:
version "2.7.1"
resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.7.1.tgz#e235806850d057f97bb08368a4f7d899f7760c64"
integrity sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==
@ -25902,13 +25929,12 @@ react-moment-proptypes@^1.7.0:
dependencies:
moment ">=1.6.0"
react-monaco-editor@^0.41.2:
version "0.41.2"
resolved "https://registry.yarnpkg.com/react-monaco-editor/-/react-monaco-editor-0.41.2.tgz#7ec9cadc101d73003a908fca61c50011f237d2b5"
integrity sha512-0nNqkkSLtUQDHtcCASv3ccYukD+P2uvFzcFZGh6iWg9RZF3Rj9/+jqsTNo2cl4avkX8JVGC/qnZr/g7hxXTBTQ==
react-monaco-editor@^0.54.0:
version "0.54.0"
resolved "https://registry.yarnpkg.com/react-monaco-editor/-/react-monaco-editor-0.54.0.tgz#ec9293249a991b08264be723c1ec0ca3a6d480d8"
integrity sha512-9JwO69851mfpuhYLHlKbae7omQWJ/2ICE2lbL0VHyNyZR8rCOH7440u+zAtDgiOMpLwmYdY1sEZCdRefywX6GQ==
dependencies:
monaco-editor "*"
prop-types "^15.7.2"
prop-types "^15.8.1"
react-popper-tooltip@^3.1.1:
version "3.1.1"
@ -31036,15 +31062,33 @@ vm-browserify@^1.0.1:
resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-1.1.2.tgz#78641c488b8e6ca91a75f511e7a3b32a86e5dda0"
integrity sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==
vscode-jsonrpc@8.2.0:
version "8.2.0"
resolved "https://registry.yarnpkg.com/vscode-jsonrpc/-/vscode-jsonrpc-8.2.0.tgz#f43dfa35fb51e763d17cd94dcca0c9458f35abf9"
integrity sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==
vscode-languageserver-protocol@^3.0.0:
version "3.17.5"
resolved "https://registry.yarnpkg.com/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.5.tgz#864a8b8f390835572f4e13bd9f8313d0e3ac4bea"
integrity sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg==
dependencies:
vscode-jsonrpc "8.2.0"
vscode-languageserver-types "3.17.5"
vscode-languageserver-textdocument@^1.0.0:
version "1.0.7"
resolved "https://registry.yarnpkg.com/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.7.tgz#16df468d5c2606103c90554ae05f9f3d335b771b"
integrity sha512-bFJH7UQxlXT8kKeyiyu41r22jCZXG8kuuVVA33OEJn1diWOZK5n8zBSPZFHVBOu8kXZ6h0LIRhf5UnCo61J4Hg==
vscode-languageserver-types@^3.0.0:
version "3.17.2"
resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.17.2.tgz#b2c2e7de405ad3d73a883e91989b850170ffc4f2"
integrity sha512-zHhCWatviizPIq9B7Vh9uvrH6x3sK8itC84HkamnBWoDFJtzBf7SWlpLCZUit72b3os45h6RWQNC9xHRDF8dRA==
vscode-languageserver-types@3.17.5, vscode-languageserver-types@^3.0.0:
version "3.17.5"
resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.17.5.tgz#3273676f0cf2eab40b3f44d085acbb7f08a39d8a"
integrity sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==
vscode-uri@^3.0.0:
version "3.0.8"
resolved "https://registry.yarnpkg.com/vscode-uri/-/vscode-uri-3.0.8.tgz#1770938d3e72588659a172d0fd4642780083ff9f"
integrity sha512-AyFQ0EVmsOZOlAnxoFOGOq1SQDWAB7C6aqMGS23svWAllfOaxbuFvcT8D1i8z3Gyn8fraVeZNNmN6e9bxxXkKw==
vt-pbf@^3.1.3:
version "3.1.3"
@ -31796,20 +31840,15 @@ yaml-ast-parser@0.0.43:
resolved "https://registry.yarnpkg.com/yaml-ast-parser/-/yaml-ast-parser-0.0.43.tgz#e8a23e6fb4c38076ab92995c5dca33f3d3d7c9bb"
integrity sha512-2PTINUwsRqSd+s8XxKaJWQlUuEMHJQyEuh2edBbW8KNJz0SJPwUSD2zRWqezFEdN7IzAgeuYHFUCF7o8zRdZ0A==
yaml-language-server-parser@^0.1.0:
version "0.1.3"
resolved "https://registry.yarnpkg.com/yaml-language-server-parser/-/yaml-language-server-parser-0.1.3.tgz#f0e9082068291c7c330eefa1f3c9f1b4c3c54183"
integrity sha512-xD2I+6M/vqQvcy4ded8JpXUaDHXmZMdhIO3OpuiFxstutwnW4whrfDzNcrsfXVdgMWqOUpdv3747Q081PFN1+g==
yaml@^1.10.0, yaml@^1.10.2, yaml@^1.7.2:
version "1.10.2"
resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b"
integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==
yaml@^2.2.1, yaml@^2.2.2:
version "2.3.1"
resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.3.1.tgz#02fe0975d23cd441242aa7204e09fc28ac2ac33b"
integrity sha512-2eHWfjaoXgTBC2jNM1LRef62VQa0umtvRiDSk6HSzW7RvS5YtkabJrwYLLEKWBc8a5U2PTSCs+dJjUTJdlHsWQ==
yaml@^2.0.0, yaml@^2.2.1, yaml@^2.2.2:
version "2.3.4"
resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.3.4.tgz#53fc1d514be80aabf386dc6001eb29bf3b7523b2"
integrity sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA==
yargs-parser@20.2.4, yargs-parser@^20.2.2, yargs-parser@^20.2.3:
version "20.2.4"