Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
000c615
Upgrade Monaco Editor to 0.54.0 and adapt Kibana integration
paulinashakirova May 4, 2026
b1ecede
Remove Prettier dependency from package.json
paulinashakirova May 4, 2026
ff77a0a
Throw an error if the Monaco editor is not found in the KibanaCodeEdi…
paulinashakirova May 4, 2026
287295a
Changes from node scripts/lint.js --fix
kibanamachine May 4, 2026
6f75e4a
Revert "Remove Prettier dependency from package.json"
paulinashakirova May 4, 2026
e3085a9
Changes from node scripts/lint.js --fix
kibanamachine May 5, 2026
78c0dc1
Remove **/prettier resolution and relock yarn.lock
paulinashakirova May 5, 2026
4a16010
Refactor imports in ESQL editor and workflow decorations to use @kbn/…
paulinashakirova May 5, 2026
07ec1ec
Implement retry logic in addColumn method of IndexEditorObject
paulinashakirova May 6, 2026
90cb96f
Enhance addColumn method in IndexEditorObject
paulinashakirova May 6, 2026
373fa49
Improve addColumn method in IndexEditorObject
paulinashakirova May 6, 2026
dfb7717
Refactor Monaco environment access in WorkflowEditorPage and improve …
paulinashakirova May 7, 2026
edf2102
resolve issue resulting from conflict resolution
eokoneyo May 19, 2026
c0eb8f0
TO FIX: Run node 'scripts/yarn_deduplicate && yarn kbn bootstrap' loc…
kibanamachine May 19, 2026
fbd8c40
Merge branch 'main' into update-monaco-latest
elasticmachine May 21, 2026
90bab5d
Changes from node scripts/lint_ts_projects --fix
kibanamachine May 21, 2026
2d27c03
Changes from node scripts/regenerate_moon_projects.js --update
kibanamachine May 21, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .buildkite/scripts/steps/security/third_party_packages.txt
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ json-stable-stringify
apache-arrow
oxlint
react-element-to-jsx-string
@babel/plugin-transform-class-static-block
@swc/core
lightningcss
tar-fs
Expand All @@ -48,3 +49,4 @@ jszip
@opentelemetry/exporter-logs-otlp-grpc
@opentelemetry/exporter-logs-otlp-proto
@opentelemetry/otlp-transformer
monaco-marker-data-provider
7 changes: 5 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@
"**/cheerio": "1.0.0-rc.12",
"**/chokidar": "3.5.3",
"**/d3-scale/**/d3-color": "npm:@elastic/kibana-d3-color@2.0.1",
"**/dompurify": "3.4.1",
"**/esbuild": "0.27.2",
"**/express-rate-limit": "8.5.2",
"**/fast-xml-parser": "5.5.7",
Expand Down Expand Up @@ -130,6 +131,7 @@
"@atlaskit/pragmatic-drag-and-drop": "1.7.7",
"@atlaskit/pragmatic-drag-and-drop-hitbox": "1.1.0",
"@aws-sdk/client-bedrock-runtime": "3.994.0",
"@babel/plugin-transform-class-static-block": "7.28.3",
"@babel/runtime": "7.28.4",
"@dagrejs/dagre": "1.1.8",
"@dnd-kit/core": "6.3.1",
Expand Down Expand Up @@ -1459,9 +1461,10 @@
"moment": "2.30.1",
"moment-duration-format": "2.3.2",
"moment-timezone": "0.6.1",
"monaco-editor": "0.44.0",
"monaco-editor": "0.54.0",
"monaco-marker-data-provider": "1.2.5",
"monaco-promql": "1.8.0",
"monaco-yaml": "5.1.0",
"monaco-yaml": "5.4.0",
"murmurhash": "2.0.1",
"mustache": "4.2.0",
"node-diff3": "3.1.2",
Expand Down
9 changes: 9 additions & 0 deletions packages/kbn-babel-preset/common_preset.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,15 @@ module.exports = (api) => ({
plugins: [
require.resolve('@kbn/lazy-object/src/plugin/lazy_babel_plugin'),
require.resolve('babel-plugin-add-module-exports'),

/**
* The static class features proposal https://github.com/tc39/proposal-static-class-features
* has been merged with the class fields proposal and is now stage 4.
* We include this here because Monaco needs this and
* this transform has to run before the transform class properties transform.
*/
require.resolve('@babel/plugin-transform-class-static-block'),

// The class properties proposal was merged with the private fields proposal
// into the "class fields" proposal. Babel doesn't support this combined
// proposal yet, which includes private field, so this transform is
Expand Down
7 changes: 7 additions & 0 deletions packages/kbn-babel-preset/webpack_preset.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,13 @@ module.exports = (
[require('./common_preset'), options],
],
plugins: [
// monaco-editor 0.54.0+ uses ES2022 class static block syntax. @babel/preset-env may skip
// this transform when the browserslist target includes browsers that natively support it,
// so we add the plugin explicitly to guarantee transformation for all targets.
// Must appear here (top-level plugins) so it runs before common_preset's class-properties
// transform, which is a hard ordering requirement from the spec implementation.
require.resolve('@babel/plugin-transform-class-static-block'),

// Conditionally include babel-plugin-transform-require-default
//
// We need to include this plugin in the main worker webpack config that handles our
Expand Down
7 changes: 6 additions & 1 deletion renovate.json
Original file line number Diff line number Diff line change
Expand Up @@ -414,7 +414,12 @@
},
{
"groupName": "monaco",
"matchDepNames": ["monaco-yaml", "monaco-editor", "monaco-promql"],
"matchDepNames": [
"monaco-yaml",
"monaco-editor",
"monaco-promql",
"monaco-marker-data-provider"
],
"reviewers": ["team:appex-sharedux"],
"matchBaseBranches": ["main"],
"addLabels": ["Team:SharedUX"],
Expand Down
61 changes: 61 additions & 0 deletions src/platform/packages/private/kbn-esql-editor/setup_tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,64 @@

// eslint-disable-next-line import/no-extraneous-dependencies
import '@testing-library/jest-dom';

// Monaco 0.54.0 Delayer.cancel() rejects its completionPromise with CancellationError when
// WordHighlighter disposes during model disposal. WordHighlighter doesn't attach .catch() to
// the Delayer promise, so the rejection surfaces as unhandled and fails tests.
//
// Jest-circus registers its 'unhandledRejection' listener AFTER setupFilesAfterFramework runs,
// so any listener-based filtering is bypassed. The correct fix is to patch Delayer.prototype.cancel
// to leave the promise pending (do not reject) instead of rejecting with CancellationError.
// This eliminates the unhandled rejection at the source without affecting Monaco's public API.
//
// This is a workaround for an upstream Monaco bug. No tracking issue exists in the Monaco repo
// as of the time of this upgrade; check https://github.com/microsoft/monaco-editor/issues when
// upgrading Monaco again to see if a fix has landed.
beforeAll(() => {
const monacoAsync = jest.requireActual('monaco-editor/esm/vs/base/common/async') as {
Delayer?: { prototype?: any };
};
if (monacoAsync?.Delayer?.prototype) {
monacoAsync.Delayer.prototype.cancel = function () {
this.cancelTimeout();
if (this.completionPromise) {
// Leave the promise pending rather than rejecting — the promise object is
// no longer reachable (refs nulled), so it will be GC'd. No rejection = no
// unhandled CancellationError from WordHighlighter cleanup during test teardown.
this.completionPromise = null;
this.doReject = null;
this.doResolve = null;
}
};
}
});

// Monaco 0.54.0 Safari clipboard workaround cancels internal DeferredPromises, which surface as
// unhandled rejections in Jest. Mock the clipboard API and swallow expected Canceled errors.
Object.defineProperty(navigator, 'clipboard', {
value: {
writeText: jest.fn().mockResolvedValue(undefined),
readText: jest.fn().mockResolvedValue(''),
write: jest.fn((items?: ClipboardItem[]) => {
// ClipboardItem data values may be cancelled DeferredPromises — attach .catch() so their
// rejection doesn't propagate, but rethrow anything that isn't an expected cancellation.
items?.forEach((item: any) => {
if (item?.data) {
Object.values(item.data).forEach((value: any) => {
if (value?.catch) {
value.catch((error: any) => {
// Only suppress expected cancellations; let real errors fail tests
if (error?.message !== 'Canceled' && error?.name !== 'Canceled') {
throw error;
}
});
}
});
}
});
return Promise.resolve();
}),
read: jest.fn().mockResolvedValue([]),
},
configurable: true,
});
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,7 @@ import { dataPluginMock } from '@kbn/data-plugin/public/mocks';
import { kqlPluginMock } from '@kbn/kql/public/mocks';
import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public';
import { renderWithI18n } from '@kbn/test-jest-helpers';
import { waitFor } from '@testing-library/dom';
import { act, screen } from '@testing-library/react';
import { act, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import React from 'react';
import { BehaviorSubject } from 'rxjs';
Expand Down Expand Up @@ -169,14 +168,21 @@ describe('ESQLEditor', () => {
});

it('should render correctly if editorIsInline prop is set to true', async () => {
const onTextLangQuerySubmit = jest.fn();
const newProps = {
...props,
editorIsInline: true,
onTextLangQuerySubmit,
};
const { queryByTestId } = renderWithI18n(renderESQLEditorComponent({ ...newProps }));

const runQueryButton = queryByTestId('ESQLEditor-run-query-button');
expect(runQueryButton).toBeInTheDocument(); // Assert it exists

if (runQueryButton) {
await userEvent.click(runQueryButton);
expect(onTextLangQuerySubmit).toHaveBeenCalledTimes(1);
}
});

it('should not render the run query button if the hideRunQueryButton prop is set to true and editorIsInline prop is set to true', async () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import {
ESQL_LANG_ID,
type CodeEditorProps,
type MonacoMessage,
type monaco,
monaco,
} from '@kbn/code-editor';
import type { EsqlLanguageDeps } from '../types';

Expand Down Expand Up @@ -199,7 +199,7 @@ export const useEditorConfig = ({
fontSize: 14,
hideCursorInOverviewRuler: true,
lightbulb: {
enabled: false,
enabled: monaco.editor.ShowLightbulbIconMode.Off,
},
lineDecorationsWidth: 20,
lineNumbers: 'on',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,17 +86,18 @@ json-schema-traverse@1.0.0
jsonc-parser@3.2.0
loader-runner@4.3.0
locate-path@7.2.0
marked@14.0.0
mdn-data@2.0.14
merge-stream@2.0.0
mime-db@1.52.0
mime-types@2.1.35
mini-css-extract-plugin@2.9.1
monaco-editor@0.44.0
monaco-languageserver-types@0.2.3
monaco-marker-data-provider@1.1.1
monaco-editor@0.54.0
monaco-languageserver-types@0.4.0
monaco-marker-data-provider@1.2.5
monaco-types@0.1.0
monaco-worker-manager@2.0.1
monaco-yaml@5.1.0
monaco-yaml@5.4.0
nano-css@5.6.2
nanoid@3.3.11
neo-async@2.6.2
Expand All @@ -114,7 +115,7 @@ postcss-modules-values@4.0.0
postcss-selector-parser@6.1.2
postcss-value-parser@4.2.0
postcss@8.5.14
prettier@2.8.8
prettier@3.8.1
punycode@2.3.1
react-universal-interface@0.6.2
react-use@17.6.0
Expand Down
1 change: 1 addition & 0 deletions src/platform/packages/shared/kbn-monaco/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,4 @@ export {

export { getUndoRedoService } from './src/undo_redo_service';
export type { UndoRedoService, UndoRedoElement } from './src/undo_redo_service';
export { getWorker } from './src/worker_factory';
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
* License v3.0 only", or the "Server Side Public License, v 1".
*/

import { apm } from '@elastic/apm-rum';
import { BehaviorSubject } from 'rxjs';

import { monaco } from '../monaco_imports';
Expand Down Expand Up @@ -68,7 +69,11 @@ export class DiagnosticsAdapter {
});
// Every time a new change is made, wait 500ms before validating
handle = setTimeout(() => {
this.validate(model.uri, idx);
this.validate(model.uri, idx).catch((e) => {
apm.captureError(e instanceof Error ? e : new Error(String(e)), {
labels: { langId: this.langId },
});
});
}, 500);
});

Expand Down Expand Up @@ -98,21 +103,32 @@ export class DiagnosticsAdapter {
return;
}

const worker = await this.worker(resource);
const errorMarkers = await worker.getSyntaxErrors(resource.toString());
let errorMarkers: MonacoEditorError[] | undefined;
try {
const worker = await this.worker(resource);
errorMarkers = await worker.getSyntaxErrors(resource.toString());
} catch (e) {
// Gracefully handle worker errors by disabling validation
apm.captureError(e instanceof Error ? e : new Error(String(e)), {
labels: { langId: this.langId },
});
errorMarkers = [];
}

if (idx !== this.validateIdx) {
return;
}

if (errorMarkers) {
const model = monaco.editor.getModel(resource);
this.errors = {
...this.errors,
[model!.id]: errorMarkers,
};
// Set the error markers and underline them with "Error" severity
monaco.editor.setModelMarkers(model!, this.langId, errorMarkers.map(toDiagnostics));
if (model !== null) {
this.errors = {
...this.errors,
[model.id]: errorMarkers,
};
// Set the error markers and underline them with "Error" severity
monaco.editor.setModelMarkers(model, this.langId, errorMarkers.map(toDiagnostics));
}
}

const isValid = errorMarkers === undefined || errorMarkers.length === 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

import { monaco } from '../monaco_imports';
import type { BaseWorkerDefinition } from '../types';
import { getWorker } from '../worker_factory';

export class WorkerProxyService<IWorker extends BaseWorkerDefinition> {
private worker: monaco.editor.MonacoWebWorker<IWorker> | undefined;
Expand All @@ -23,7 +24,7 @@ export class WorkerProxyService<IWorker extends BaseWorkerDefinition> {
}

public setup(langId: string) {
this.worker = monaco.editor.createWebWorker({ label: langId, moduleId: '' });
this.worker = monaco.editor.createWebWorker({ worker: Promise.resolve(getWorker(langId)) });
}

public stop() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@
* License v3.0 only", or the "Server Side Public License, v 1".
*/

import { apm } from '@elastic/apm-rum';
import { monaco } from '../../monaco_imports';
import { getWorker } from '../../worker_factory';
import { CONSOLE_LANG_ID } from './constants';
import type { ConsoleParserResult, ConsoleWorkerDefinition } from './types';

Expand All @@ -23,13 +25,23 @@ export class ConsoleWorkerProxyService {
if (!this.worker) {
throw new Error('Worker Proxy Service has not been setup!');
}
await this.worker.withSyncedResources([modelUri]);
const parser = await this.worker.getProxy();
return parser.getParserResult(modelUri.toString());
try {
await this.worker.withSyncedResources([modelUri]);
const parser = await this.worker.getProxy();
return parser.getParserResult(modelUri.toString());
} catch (e) {
// Gracefully handle worker errors
apm.captureError(e instanceof Error ? e : new Error(String(e)), {
labels: { worker: 'console' },
});
return undefined;
}
}

public setup() {
this.worker = monaco.editor.createWebWorker({ label: CONSOLE_LANG_ID, moduleId: '' });
this.worker = monaco.editor.createWebWorker({
worker: Promise.resolve(getWorker(CONSOLE_LANG_ID)),
});
}

public stop() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,14 @@
/* eslint-disable @kbn/eslint/module_migration */

import '@babel/runtime/regenerator';
// @ts-ignore
import * as worker from 'monaco-editor/esm/vs/editor/editor.worker';
// @ts-expect-error — no type declarations for this internal Monaco entry point
// Monaco 0.54.0: Use editor.worker.start directly instead of editor.worker's initialize()
// wrapper, which no longer supports the SimpleWorkerServer pattern used in 0.44.0
import * as worker from 'monaco-editor/esm/vs/editor/editor.worker.start';
import { ConsoleWorker } from './console_worker';

self.onmessage = () => {
worker.initialize((ctx: any, createData: any) => {
worker.start((ctx: any) => {
return new ConsoleWorker(ctx);
});
};
Loading
Loading