Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
7e6cac1
Make the links clickable within Dev Console
saikatsarkar056 Nov 5, 2025
0a1da76
Merge branch 'main' of github.com:elastic/kibana into clickable-links…
saikatsarkar056 Nov 5, 2025
8ba2336
Make the links clickable within Dev Console
saikatsarkar056 Nov 5, 2025
a694a38
Merge branch 'main' of github.com:elastic/kibana into clickable-links…
saikatsarkar056 Nov 5, 2025
9956b79
Make the links clickable within Dev Console
saikatsarkar056 Nov 5, 2025
6b63c51
Added FTR test
saikatsarkar056 Nov 5, 2025
4105824
Added FTR test
saikatsarkar056 Nov 5, 2025
6b98c1c
Merge branch 'main' of github.com:elastic/kibana into clickable-links…
saikatsarkar056 Nov 6, 2025
7187942
Disable the links by default for all editors
saikatsarkar056 Nov 6, 2025
34f594f
Enable the links option for console only
saikatsarkar056 Nov 6, 2025
b48ebe8
Merge branch 'main' of github.com:elastic/kibana into clickable-links…
saikatsarkar056 Nov 6, 2025
d44ddd6
Update the FTR tests
saikatsarkar056 Nov 6, 2025
97af2d3
Update the FTR tests
saikatsarkar056 Nov 6, 2025
55fb519
Update the FTR tests
saikatsarkar056 Nov 6, 2025
a1a5042
Update the FTR tests
saikatsarkar056 Nov 6, 2025
53df6b8
Update the FTR tests
saikatsarkar056 Nov 6, 2025
5afa5cc
Update the FTR tests
saikatsarkar056 Nov 6, 2025
510df50
Update the FTR tests
saikatsarkar056 Nov 6, 2025
c0a847e
Update the FTR tests
saikatsarkar056 Nov 6, 2025
d2f8c73
Update the FTR tests
saikatsarkar056 Nov 7, 2025
ffdc7d7
Update the FTR tests
saikatsarkar056 Nov 7, 2025
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
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import 'monaco-editor/esm/vs/editor/contrib/suggest/browser/suggestController.js
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/editor/contrib/links/browser/links.js'; // Needed for clickable links with Cmd/Ctrl+Click

import 'monaco-editor/esm/vs/editor/contrib/codeAction/browser/codeAction.js';
import 'monaco-editor/esm/vs/editor/contrib/codeAction/browser/codeActionCommands.js';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,12 @@ export interface CodeEditorProps {
*/
htmlId?: string;

/**
* Enables clickable links in the editor. URLs will be underlined and can be opened
* in a new tab using Cmd/Ctrl+Click. Disabled by default.
*/
links?: boolean;

/**
* Callbacks for when editor is focused/blurred
*/
Expand Down Expand Up @@ -239,6 +245,7 @@ export const CodeEditor: React.FC<CodeEditorProps> = ({
enableCustomContextMenu = false,
customContextMenuActions = [],
htmlId,
links = false,
onFocus,
onBlur,
}) => {
Expand Down Expand Up @@ -649,6 +656,8 @@ export const CodeEditor: React.FC<CodeEditorProps> = ({
// @ts-expect-error, see https://github.com/microsoft/monaco-editor/issues/3829
'bracketPairColorization.enabled': false,
...options,
// Explicit links prop always takes precedence over any value passed in options
links,
}}
/>
</UseBug223981FixRepositionSuggestWidget>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,7 @@ export const MonacoEditor = ({
accessibilityOverlayEnabled={settings.isAccessibilityOverlayEnabled}
editorDidMount={editorDidMountCallback}
editorWillUnmount={editorWillUnmountCallback}
links={true}
options={{
fontSize: settings.fontSize,
wordWrap: settings.wrapMode === true ? 'on' : 'off',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
const retry = getService('retry');
const browser = getService('browser');
const PageObjects = getPageObjects(['common', 'console', 'header']);
const testSubjects = getService('testSubjects');
const toasts = getService('toasts');

describe('misc console behavior', function testMiscConsoleBehavior() {
Expand Down Expand Up @@ -261,6 +262,65 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
});
});

describe('clickable links', () => {
let initialWindowHandles: string[];

beforeEach(async () => {
initialWindowHandles = await browser.getAllWindowHandles();
});

afterEach(async () => {
// Close any new tabs that were opened
const currentHandles = await browser.getAllWindowHandles();
if (currentHandles.length > initialWindowHandles.length) {
// Close all new tabs
for (let i = initialWindowHandles.length; i < currentHandles.length; i++) {
await browser.switchToWindow(currentHandles[i]);
await browser.closeCurrentWindow();
}
// Switch back to the original tab
await browser.switchToWindow(initialWindowHandles[0]);
}
});

it('should open URL in new tab when clicking on a link in the input editor', async () => {
await PageObjects.console.clearEditorText();
await PageObjects.console.enterText('# https://www.elastic.co');

// Wait for Monaco to detect and decorate the link
await retry.waitFor('link to be detected by Monaco', async () => {
const inputEditor = await testSubjects.find('consoleMonacoEditor');
const detectedLinks = await inputEditor.findAllByCssSelector('.detected-link');
return detectedLinks.length > 0;
});

const inputEditor = await testSubjects.find('consoleMonacoEditor');
const detectedLink = await inputEditor.findByCssSelector('.detected-link');

// Perform Cmd/Ctrl+Click on the detected link
const modifierKey = browser.keys[process.platform === 'darwin' ? 'COMMAND' : 'CONTROL'];
await browser
.getActions()
.keyDown(modifierKey)
.click(detectedLink._webElement)
.keyUp(modifierKey)
.perform();

// Wait for a new tab to open
await retry.waitFor('new tab to open after clicking link', async () => {
const handles = await browser.getAllWindowHandles();
return handles.length > initialWindowHandles.length;
});

const windowHandles = await browser.getAllWindowHandles();
expect(windowHandles.length).to.be.greaterThan(initialWindowHandles.length);

await browser.switchToWindow(windowHandles[windowHandles.length - 1]);
const currentUrl = await browser.getCurrentUrl();
expect(currentUrl).to.contain('elastic.co');
});
});

it('should work fine with a large content', async () => {
await PageObjects.console.clearEditorText();

Expand Down