-
Notifications
You must be signed in to change notification settings - Fork 8.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[Console] Monaco migration: send request and copy as curl buttons (#1…
…79808) ## Summary Closes #178990 This PR adds the actions buttons to the monaco editor and the functionality for the buttons to send a request and copy the request as a curl command. When the cursor or user selection doesn't overlap or contain any requests on the selected line, the actions buttons are hidden. When the cursor or selection changes, the buttons are displayed on the 1st line of the 1st selected request. Several requests can be sent at once. Only the 1st request is copied as a curl command. There are also some minor UI and copy changes (see screenshots below) as suggested by @MichaelMarcialis in the review. ### Screenshot #### Before <img width="882" alt="Screenshot 2024-04-15 at 15 16 59" src="https://github.com/elastic/kibana/assets/6585477/8fa95a5b-51c6-4220-8837-38adc4696602"> <img width="296" alt="Screenshot 2024-04-15 at 15 17 07" src="https://github.com/elastic/kibana/assets/6585477/6c99a4db-f7a6-4872-a24a-cddb56e0ec3d"> #### After <img width="916" alt="Screenshot 2024-04-15 at 15 18 08" src="https://github.com/elastic/kibana/assets/6585477/1ae0b161-c731-42e1-90af-69468e9f0905"> <img width="367" alt="Screenshot 2024-04-15 at 15 18 14" src="https://github.com/elastic/kibana/assets/6585477/bb8818bd-38d4-4ec3-8bf4-30e24afd3664"> ### How to test - Check that the actions buttons are not displayed when there are no requests in the input - Check that the actions buttons are not displayed when no requests are selected by the cursor or the selection - Check that the selected requests are highlighted - Check that the buttons are displayed on the 1st line of the 1st selected request - Check that the position of the buttons is updated when the editor is scrolled up or down ### Follow up issues - The functionality for the button to open a documentation for the 1st selected request - The functionality for the button to auto-indent input - The input highlighting is temporarily reset when sending a request - Sent requests need to be saved to history - After sending a request, the autocomplete polling needs to be restarted - Add more unit tests
- Loading branch information
Showing
18 changed files
with
994 additions
and
42 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
63 changes: 63 additions & 0 deletions
63
packages/kbn-monaco/src/console/console_errors_provider.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
/* | ||
* 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 { ConsoleWorkerProxyService } from './console_worker_proxy'; | ||
import { CONSOLE_LANG_ID } from './constants'; | ||
import { monaco } from '../monaco_imports'; | ||
|
||
/* | ||
* This setup function runs when the Console language is registered into the Monaco editor. | ||
* It adds a listener that is attached to the editor input when the Monaco editor is used | ||
* with the Console language. | ||
* The Console parser that runs in a web worker analyzes the editor input when it changes and | ||
* if any errors are found, they are added as "error markers" to the Monaco editor. | ||
*/ | ||
export const setupConsoleErrorsProvider = (workerProxyService: ConsoleWorkerProxyService) => { | ||
const updateErrorMarkers = async (model: monaco.editor.IModel): Promise<void> => { | ||
if (model.isDisposed()) { | ||
return; | ||
} | ||
const parserResult = await workerProxyService.getParserResult(model.uri); | ||
|
||
if (!parserResult) { | ||
return; | ||
} | ||
const { errors } = parserResult; | ||
monaco.editor.setModelMarkers( | ||
model, | ||
CONSOLE_LANG_ID, | ||
errors.map(({ offset, text }) => { | ||
const { column, lineNumber } = model.getPositionAt(offset); | ||
return { | ||
startLineNumber: lineNumber, | ||
startColumn: column, | ||
endLineNumber: lineNumber, | ||
endColumn: column, | ||
message: text, | ||
severity: monaco.MarkerSeverity.Error, | ||
}; | ||
}) | ||
); | ||
}; | ||
const onModelAdd = (model: monaco.editor.IModel) => { | ||
if (model.getLanguageId() !== CONSOLE_LANG_ID) { | ||
return; | ||
} | ||
|
||
const { dispose } = model.onDidChangeContent(async () => { | ||
await updateErrorMarkers(model); | ||
}); | ||
|
||
model.onWillDispose(() => { | ||
dispose(); | ||
}); | ||
|
||
updateErrorMarkers(model); | ||
}; | ||
monaco.editor.onDidCreateModel(onModelAdd); | ||
}; |
31 changes: 31 additions & 0 deletions
31
packages/kbn-monaco/src/console/console_parsed_requests_provider.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
/* | ||
* 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 { ConsoleWorkerProxyService } from './console_worker_proxy'; | ||
import { ParsedRequest } from './types'; | ||
import { monaco } from '../monaco_imports'; | ||
|
||
/* | ||
* This class is a helper interface that is used in the Console plugin. | ||
* The provider access the Console parser that runs in a web worker and analyzes the editor input | ||
* when it changes. | ||
* The parsed result contains the requests and errors which are used in the Console plugin. | ||
*/ | ||
export class ConsoleParsedRequestsProvider { | ||
constructor( | ||
private workerProxyService: ConsoleWorkerProxyService, | ||
private model: monaco.editor.ITextModel | null | ||
) {} | ||
public async getRequests(): Promise<ParsedRequest[]> { | ||
if (!this.model) { | ||
return []; | ||
} | ||
const parserResult = await this.workerProxyService.getParserResult(this.model.uri); | ||
return parserResult?.requests ?? []; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
/* | ||
* 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 } from '../monaco_imports'; | ||
import { CONSOLE_LANG_ID } from './constants'; | ||
import { ConsoleParserResult, ConsoleWorkerDefinition } from './types'; | ||
|
||
/* | ||
* This class contains logic to create a web worker where the code for the Console parser can | ||
* execute without blocking the main thread. The parser only runs when the Monaco editor | ||
* is used with the Console language. The parser can only be accessed via this proxy service class. | ||
*/ | ||
export class ConsoleWorkerProxyService { | ||
private worker: monaco.editor.MonacoWebWorker<ConsoleWorkerDefinition> | undefined; | ||
|
||
public async getParserResult(modelUri: monaco.Uri): Promise<ConsoleParserResult | undefined> { | ||
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()); | ||
} | ||
|
||
public setup() { | ||
this.worker = monaco.editor.createWebWorker({ label: CONSOLE_LANG_ID, moduleId: '' }); | ||
} | ||
|
||
public stop() { | ||
if (this.worker) this.worker.dispose(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
/* | ||
* 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 { createParser } from './parser'; | ||
import { ConsoleParserResult } from './types'; | ||
|
||
const parser = createParser(); | ||
describe('console parser', () => { | ||
it('returns errors if input is not correct', () => { | ||
const input = 'Incorrect input'; | ||
const parserResult = parser(input) as ConsoleParserResult; | ||
// the parser logs 2 errors: for the unexpected method and a general syntax error | ||
expect(parserResult.errors.length).toBe(2); | ||
// the parser logs a beginning of the request that it's trying to parse | ||
expect(parserResult.requests.length).toBe(1); | ||
}); | ||
|
||
it('returns parsedRequests if the input is correct', () => { | ||
const input = 'GET _search'; | ||
const { requests, errors } = parser(input) as ConsoleParserResult; | ||
expect(requests.length).toBe(1); | ||
expect(errors.length).toBe(0); | ||
const { method, url, startOffset, endOffset } = requests[0]; | ||
expect(method).toBe('GET'); | ||
expect(url).toBe('_search'); | ||
// the start offset of the request is the beginning of the string | ||
expect(startOffset).toBe(0); | ||
// the end offset of the request is the end of the string | ||
expect(endOffset).toBe(11); | ||
}); | ||
|
||
it('parses several requests', () => { | ||
const input = 'GET _search\nPOST _test_index'; | ||
const { requests } = parser(input) as ConsoleParserResult; | ||
expect(requests.length).toBe(2); | ||
}); | ||
|
||
it('parses a request with a request body', () => { | ||
const input = | ||
'GET _search\n' + '{\n' + ' "query": {\n' + ' "match_all": {}\n' + ' }\n' + '}'; | ||
const { requests } = parser(input) as ConsoleParserResult; | ||
expect(requests.length).toBe(1); | ||
const { method, url, data } = requests[0]; | ||
expect(method).toBe('GET'); | ||
expect(url).toBe('_search'); | ||
expect(data).toEqual([ | ||
{ | ||
query: { | ||
match_all: {}, | ||
}, | ||
}, | ||
]); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
/* | ||
* 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 interface ErrorAnnotation { | ||
offset: number; | ||
text: string; | ||
} | ||
|
||
export interface ParsedRequest { | ||
startOffset: number; | ||
endOffset: number; | ||
method: string; | ||
url: string; | ||
data?: Array<Record<string, unknown>>; | ||
} | ||
export interface ConsoleParserResult { | ||
errors: ErrorAnnotation[]; | ||
requests: ParsedRequest[]; | ||
} | ||
|
||
export interface ConsoleWorkerDefinition { | ||
getParserResult: (modelUri: string) => ConsoleParserResult | undefined; | ||
} | ||
export type ConsoleParser = (source: string) => ConsoleParserResult | undefined; |
Oops, something went wrong.