Skip to content

Commit 38d4dee

Browse files
committed
[Console] Fix method suggestion order (elastic#270787)
Closes elastic#259251 ## Summary - Pins Console HTTP method completion ordering with explicit `sortText` values so Monaco does not fall back to alphabetical label sorting. - Keeps the existing method set unchanged while ordering `GET` first and `DELETE` last. ## Root Cause - Monaco uses `sortText` for completion ordering and falls back to the item label when `sortText` is missing, which can put `DELETE` before safer/default verbs. ## Fix - Assign stable `sortText` values to method completion items based on the intended canonical order. - Add a focused unit test that sorts method suggestions the same way and verifies `GET` is first and `DELETE` is last. ## Before <img width="723" height="466" alt="image" src="https://github.com/user-attachments/assets/faf244b2-4207-483b-acbc-32b148441b18" /> ## After <img width="725" height="437" alt="image" src="https://github.com/user-attachments/assets/782c0c60-6052-4c28-80bc-f45403fa1383" /> ## Test Plan - `node scripts/jest --config=src/platform/plugins/shared/console/jest.config.js src/platform/plugins/shared/console/public/application/containers/editor/monaco_editor_actions_provider.test.ts` — passed. - `node scripts/check_changes.ts` — passed. ## Release Note - Fixes Console autocomplete so `GET` is shown before `DELETE` when suggesting HTTP methods on an empty request line. Assisted with Cursor using GPT-5.5 Made with [Cursor](https://cursor.com) Co-authored-by: Cursor <cursoragent@cursor.com> (cherry picked from commit 8849fcf) # Conflicts: # src/platform/plugins/shared/console/public/application/containers/editor/monaco_editor_actions_provider.test.ts
1 parent dce6ae9 commit 38d4dee

2 files changed

Lines changed: 27 additions & 3 deletions

File tree

src/platform/plugins/shared/console/public/application/containers/editor/monaco_editor_actions_provider.test.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,24 @@ describe('Editor actions provider', () => {
287287
);
288288
});
289289

290+
it('orders method suggestions with GET first and DELETE last using sortText', async () => {
291+
// Monaco sorts completion items by sortText, falling back to label. Without
292+
// an explicit sortText, alphabetical sorting puts DELETE first (#259251).
293+
mockGetParsedRequests.mockResolvedValue([]);
294+
const completionItems = await editorActionsProvider.provideCompletionItems(
295+
mockModel,
296+
mockPosition,
297+
mockContext
298+
);
299+
const sortedByMonaco = [...(completionItems?.suggestions ?? [])].sort((a, b) =>
300+
String(a.sortText ?? a.label).localeCompare(String(b.sortText ?? b.label))
301+
);
302+
const orderedLabels = sortedByMonaco.map((s) => s.label);
303+
expect(orderedLabels[0]).toBe('GET');
304+
expect(orderedLabels[orderedLabels.length - 1]).toBe('DELETE');
305+
expect(orderedLabels).toEqual(['GET', 'POST', 'PUT', 'PATCH', 'HEAD', 'DELETE']);
306+
});
307+
290308
it('returns completion items for url path if method already typed in', async () => {
291309
// mock a parsed request that only has a method
292310
mockGetParsedRequests.mockResolvedValue([

src/platform/plugins/shared/console/public/application/containers/editor/utils/autocomplete_utils.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,21 +60,27 @@ const filterTermsWithoutName = (terms: ResultTerm[]): ResultTerm[] =>
6060
terms.filter((term) => term.name !== undefined && term.name !== '');
6161

6262
/*
63-
* This function returns an array of completion items for the request method
63+
* This function returns an array of completion items for the request method.
64+
*
65+
* The order is deliberate: Monaco sorts completion items by `sortText` and
66+
* falls back to alphabetical label sorting, which would otherwise put DELETE
67+
* first (#259251). GET is the safest verb to accept by default and DELETE
68+
* the most destructive, so we pin GET first and DELETE last.
6469
*/
65-
const autocompleteMethods = ['GET', 'PUT', 'POST', 'DELETE', 'HEAD', 'PATCH'];
70+
const autocompleteMethods = ['GET', 'POST', 'PUT', 'PATCH', 'HEAD', 'DELETE'];
6671
export const getMethodCompletionItems = (
6772
model: monaco.editor.ITextModel,
6873
position: monaco.Position
6974
): monaco.languages.CompletionItem[] => {
7075
// get the word before suggestions to replace when selecting a suggestion from the list
7176
const wordUntilPosition = model.getWordUntilPosition(position);
72-
return autocompleteMethods.map((method) => ({
77+
return autocompleteMethods.map((method, index) => ({
7378
label: method,
7479
insertText: method,
7580
detail: i18nTexts.method,
7681
// only used to configure the icon
7782
kind: monaco.languages.CompletionItemKind.Constant,
83+
sortText: String(index),
7884
range: {
7985
// replace the whole word with the suggestion
8086
startColumn: wordUntilPosition.startColumn,

0 commit comments

Comments
 (0)